1
+ use either:: Either ;
2
+ use itertools:: Itertools ;
1
3
use rustc_hash:: FxHashMap ;
2
4
3
- use syntax:: { algo , ast, match_ast , AstNode , SyntaxKind :: * , SyntaxNode } ;
5
+ use syntax:: { ast, ted , AstNode } ;
4
6
5
7
use crate :: { AssistContext , AssistId , AssistKind , Assists } ;
6
8
@@ -22,60 +24,70 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
22
24
pub ( crate ) fn reorder_fields ( acc : & mut Assists , ctx : & AssistContext ) -> Option < ( ) > {
23
25
let record = ctx
24
26
. find_node_at_offset :: < ast:: RecordExpr > ( )
25
- . map ( |it| it. syntax ( ) . clone ( ) )
26
- . or_else ( || ctx. find_node_at_offset :: < ast:: RecordPat > ( ) . map ( |it| it. syntax ( ) . clone ( ) ) ) ?;
27
-
28
- let path = record. children ( ) . find_map ( ast:: Path :: cast) ?;
27
+ . map ( Either :: Left )
28
+ . or_else ( || ctx. find_node_at_offset :: < ast:: RecordPat > ( ) . map ( Either :: Right ) ) ?;
29
29
30
+ let path = record. as_ref ( ) . either ( |it| it. path ( ) , |it| it. path ( ) ) ?;
30
31
let ranks = compute_fields_ranks ( & path, & ctx) ?;
32
+ let get_rank_of_field =
33
+ |of : Option < _ > | * ranks. get ( & of. unwrap_or_default ( ) ) . unwrap_or ( & usize:: MAX ) ;
31
34
32
- let fields: Vec < SyntaxNode > = {
33
- let field_kind = match record. kind ( ) {
34
- RECORD_EXPR => RECORD_EXPR_FIELD ,
35
- RECORD_PAT => RECORD_PAT_FIELD ,
36
- _ => {
37
- stdx:: never!( ) ;
38
- return None ;
39
- }
40
- } ;
41
- record. children ( ) . flat_map ( |n| n. children ( ) ) . filter ( |n| n. kind ( ) == field_kind) . collect ( )
35
+ let field_list = match & record {
36
+ Either :: Left ( it) => Either :: Left ( it. record_expr_field_list ( ) ?) ,
37
+ Either :: Right ( it) => Either :: Right ( it. record_pat_field_list ( ) ?) ,
42
38
} ;
43
-
44
- let sorted_fields = {
45
- let mut fields = fields. clone ( ) ;
46
- fields. sort_by_key ( |node| * ranks. get ( & get_field_name ( node) ) . unwrap_or ( & usize:: max_value ( ) ) ) ;
47
- fields
39
+ let fields = match field_list {
40
+ Either :: Left ( it) => Either :: Left ( (
41
+ it. fields ( )
42
+ . sorted_unstable_by_key ( |field| {
43
+ get_rank_of_field ( field. field_name ( ) . map ( |it| it. to_string ( ) ) )
44
+ } )
45
+ . collect :: < Vec < _ > > ( ) ,
46
+ it,
47
+ ) ) ,
48
+ Either :: Right ( it) => Either :: Right ( (
49
+ it. fields ( )
50
+ . sorted_unstable_by_key ( |field| {
51
+ get_rank_of_field ( field. field_name ( ) . map ( |it| it. to_string ( ) ) )
52
+ } )
53
+ . collect :: < Vec < _ > > ( ) ,
54
+ it,
55
+ ) ) ,
48
56
} ;
49
57
50
- if sorted_fields == fields {
58
+ let is_sorted = fields. as_ref ( ) . either (
59
+ |( sorted, field_list) | field_list. fields ( ) . zip ( sorted) . all ( |( a, b) | a == * b) ,
60
+ |( sorted, field_list) | field_list. fields ( ) . zip ( sorted) . all ( |( a, b) | a == * b) ,
61
+ ) ;
62
+ if is_sorted {
51
63
cov_mark:: hit!( reorder_sorted_fields) ;
52
64
return None ;
53
65
}
54
-
55
- let target = record. text_range ( ) ;
66
+ let target = record. as_ref ( ) . either ( AstNode :: syntax, AstNode :: syntax) . text_range ( ) ;
56
67
acc. add (
57
68
AssistId ( "reorder_fields" , AssistKind :: RefactorRewrite ) ,
58
69
"Reorder record fields" ,
59
70
target,
60
- |edit| {
61
- let mut rewriter = algo:: SyntaxRewriter :: default ( ) ;
62
- for ( old, new) in fields. iter ( ) . zip ( & sorted_fields) {
63
- rewriter. replace ( old, new) ;
71
+ |builder| match fields {
72
+ Either :: Left ( ( sorted, field_list) ) => {
73
+ replace ( builder. make_ast_mut ( field_list) . fields ( ) , sorted)
74
+ }
75
+ Either :: Right ( ( sorted, field_list) ) => {
76
+ replace ( builder. make_ast_mut ( field_list) . fields ( ) , sorted)
64
77
}
65
- edit. rewrite ( rewriter) ;
66
78
} ,
67
79
)
68
80
}
69
81
70
- fn get_field_name ( node : & SyntaxNode ) -> String {
71
- let res = match_ast ! {
72
- match node {
73
- ast :: RecordExprField ( field ) => field . field_name ( ) . map ( |it| it . to_string ( ) ) ,
74
- ast :: RecordPatField ( field ) => field . field_name ( ) . map ( |it| it . to_string ( ) ) ,
75
- _ => None ,
76
- }
77
- } ;
78
- res . unwrap_or_default ( )
82
+ fn replace < T : AstNode + PartialEq > (
83
+ fields : impl Iterator < Item = T > ,
84
+ sorted_fields : impl IntoIterator < Item = T > ,
85
+ ) {
86
+ fields . zip ( sorted_fields ) . filter ( | ( field , sorted ) | field != sorted ) . for_each (
87
+ | ( field , sorted_field ) | {
88
+ ted :: replace ( field . syntax ( ) , sorted_field . syntax ( ) . clone_for_update ( ) ) ;
89
+ } ,
90
+ ) ;
79
91
}
80
92
81
93
fn compute_fields_ranks ( path : & ast:: Path , ctx : & AssistContext ) -> Option < FxHashMap < String , usize > > {
@@ -86,7 +98,7 @@ fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashM
86
98
87
99
let res = strukt
88
100
. fields ( ctx. db ( ) )
89
- . iter ( )
101
+ . into_iter ( )
90
102
. enumerate ( )
91
103
. map ( |( idx, field) | ( field. name ( ctx. db ( ) ) . to_string ( ) , idx) )
92
104
. collect ( ) ;
@@ -137,7 +149,6 @@ const test: Foo = Foo { foo: 1, bar: 0 };
137
149
"# ,
138
150
)
139
151
}
140
-
141
152
#[ test]
142
153
fn reorder_struct_pattern ( ) {
143
154
check_assist (
0 commit comments