1
1
use syntax:: {
2
2
AstNode , SyntaxKind ,
3
- ast:: { self , HasVisibility , edit_in_place:: Removable , make} ,
4
- ted:: { self , Position } ,
3
+ ast:: {
4
+ self , HasAttrs , HasVisibility , edit:: IndentLevel , edit_in_place:: AttrsOwnerEdit , make,
5
+ syntax_factory:: SyntaxFactory ,
6
+ } ,
7
+ syntax_editor:: { Element , Position , Removable } ,
5
8
} ;
6
9
7
10
use crate :: {
8
11
AssistId ,
9
12
assist_context:: { AssistContext , Assists } ,
10
13
} ;
11
14
12
- // Assist: unmerge_use
15
+ // Assist: unmerge_imports
13
16
//
14
- // Extracts single use item from use list.
17
+ // Extracts a use item from a use list into a standalone use list.
15
18
//
16
19
// ```
17
20
// use std::fmt::{Debug, Display$0};
@@ -21,39 +24,50 @@ use crate::{
21
24
// use std::fmt::{Debug};
22
25
// use std::fmt::Display;
23
26
// ```
24
- pub ( crate ) fn unmerge_use ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
25
- let tree: ast :: UseTree = ctx. find_node_at_offset :: < ast:: UseTree > ( ) ?. clone_for_update ( ) ;
27
+ pub ( crate ) fn unmerge_imports ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
28
+ let tree = ctx. find_node_at_offset :: < ast:: UseTree > ( ) ?;
26
29
27
30
let tree_list = tree. syntax ( ) . parent ( ) . and_then ( ast:: UseTreeList :: cast) ?;
28
31
if tree_list. use_trees ( ) . count ( ) < 2 {
29
- cov_mark:: hit!( skip_single_use_item ) ;
32
+ cov_mark:: hit!( skip_single_import ) ;
30
33
return None ;
31
34
}
32
35
33
- let use_: ast :: Use = tree_list. syntax ( ) . ancestors ( ) . find_map ( ast:: Use :: cast) ?;
36
+ let use_ = tree_list. syntax ( ) . ancestors ( ) . find_map ( ast:: Use :: cast) ?;
34
37
let path = resolve_full_path ( & tree) ?;
35
38
36
- let old_parent_range = use_. syntax ( ) . parent ( ) ?. text_range ( ) ;
37
- let new_parent = use_. syntax ( ) . parent ( ) ?;
38
-
39
39
// If possible, explain what is going to be done.
40
40
let label = match tree. path ( ) . and_then ( |path| path. first_segment ( ) ) {
41
41
Some ( name) => format ! ( "Unmerge use of `{name}`" ) ,
42
42
None => "Unmerge use" . into ( ) ,
43
43
} ;
44
44
45
45
let target = tree. syntax ( ) . text_range ( ) ;
46
- acc. add ( AssistId :: refactor_rewrite ( "unmerge_use" ) , label, target, |builder| {
47
- let new_use = make:: use_ (
46
+ acc. add ( AssistId :: refactor_rewrite ( "unmerge_imports" ) , label, target, |builder| {
47
+ let make = SyntaxFactory :: with_mappings ( ) ;
48
+ let new_use = make. use_ (
48
49
use_. visibility ( ) ,
49
- make:: use_tree ( path, tree. use_tree_list ( ) , tree. rename ( ) , tree. star_token ( ) . is_some ( ) ) ,
50
- )
51
- . clone_for_update ( ) ;
52
-
53
- tree . remove ( ) ;
54
- ted :: insert ( Position :: after ( use_ . syntax ( ) ) , new_use . syntax ( ) ) ;
50
+ make. use_tree ( path, tree. use_tree_list ( ) , tree. rename ( ) , tree. star_token ( ) . is_some ( ) ) ,
51
+ ) ;
52
+ // Add any attributes that are present on the use tree
53
+ use_ . attrs ( ) . for_each ( |attr| {
54
+ new_use . add_attr ( attr . clone_for_update ( ) ) ;
55
+ } ) ;
55
56
56
- builder. replace ( old_parent_range, new_parent. to_string ( ) ) ;
57
+ let mut editor = builder. make_editor ( use_. syntax ( ) ) ;
58
+ // Remove the use tree from the current use item
59
+ tree. remove ( & mut editor) ;
60
+ // Insert a newline and indentation, followed by the new use item
61
+ editor. insert_all (
62
+ Position :: after ( use_. syntax ( ) ) ,
63
+ vec ! [
64
+ make. whitespace( & format!( "\n {}" , IndentLevel :: from_node( use_. syntax( ) ) ) )
65
+ . syntax_element( ) ,
66
+ new_use. syntax( ) . syntax_element( ) ,
67
+ ] ,
68
+ ) ;
69
+ editor. add_mappings ( make. finish_with_mappings ( ) ) ;
70
+ builder. add_file_edits ( ctx. vfs_file_id ( ) , editor) ;
57
71
} )
58
72
}
59
73
@@ -80,22 +94,22 @@ mod tests {
80
94
use super :: * ;
81
95
82
96
#[ test]
83
- fn skip_single_use_item ( ) {
84
- cov_mark:: check!( skip_single_use_item ) ;
97
+ fn skip_single_import ( ) {
98
+ cov_mark:: check!( skip_single_import ) ;
85
99
check_assist_not_applicable (
86
- unmerge_use ,
100
+ unmerge_imports ,
87
101
r"
88
102
use std::fmt::Debug$0;
89
103
" ,
90
104
) ;
91
105
check_assist_not_applicable (
92
- unmerge_use ,
106
+ unmerge_imports ,
93
107
r"
94
108
use std::fmt::{Debug$0};
95
109
" ,
96
110
) ;
97
111
check_assist_not_applicable (
98
- unmerge_use ,
112
+ unmerge_imports ,
99
113
r"
100
114
use std::fmt::Debug as Dbg$0;
101
115
" ,
@@ -105,17 +119,17 @@ use std::fmt::Debug as Dbg$0;
105
119
#[ test]
106
120
fn skip_single_glob_import ( ) {
107
121
check_assist_not_applicable (
108
- unmerge_use ,
122
+ unmerge_imports ,
109
123
r"
110
124
use std::fmt::*$0;
111
125
" ,
112
126
) ;
113
127
}
114
128
115
129
#[ test]
116
- fn unmerge_use_item ( ) {
130
+ fn unmerge_import ( ) {
117
131
check_assist (
118
- unmerge_use ,
132
+ unmerge_imports ,
119
133
r"
120
134
use std::fmt::{Debug, Display$0};
121
135
" ,
@@ -126,7 +140,7 @@ use std::fmt::Display;
126
140
) ;
127
141
128
142
check_assist (
129
- unmerge_use ,
143
+ unmerge_imports ,
130
144
r"
131
145
use std::fmt::{Debug, format$0, Display};
132
146
" ,
@@ -140,7 +154,7 @@ use std::fmt::format;
140
154
#[ test]
141
155
fn unmerge_glob_import ( ) {
142
156
check_assist (
143
- unmerge_use ,
157
+ unmerge_imports ,
144
158
r"
145
159
use std::fmt::{*$0, Display};
146
160
" ,
@@ -152,9 +166,9 @@ use std::fmt::*;
152
166
}
153
167
154
168
#[ test]
155
- fn unmerge_renamed_use_item ( ) {
169
+ fn unmerge_renamed_import ( ) {
156
170
check_assist (
157
- unmerge_use ,
171
+ unmerge_imports ,
158
172
r"
159
173
use std::fmt::{Debug, Display as Disp$0};
160
174
" ,
@@ -166,9 +180,9 @@ use std::fmt::Display as Disp;
166
180
}
167
181
168
182
#[ test]
169
- fn unmerge_indented_use_item ( ) {
183
+ fn unmerge_indented_import ( ) {
170
184
check_assist (
171
- unmerge_use ,
185
+ unmerge_imports ,
172
186
r"
173
187
mod format {
174
188
use std::fmt::{Debug, Display$0 as Disp, format};
@@ -184,9 +198,9 @@ mod format {
184
198
}
185
199
186
200
#[ test]
187
- fn unmerge_nested_use_item ( ) {
201
+ fn unmerge_nested_import ( ) {
188
202
check_assist (
189
- unmerge_use ,
203
+ unmerge_imports ,
190
204
r"
191
205
use foo::bar::{baz::{qux$0, foobar}, barbaz};
192
206
" ,
@@ -196,7 +210,7 @@ use foo::bar::baz::qux;
196
210
" ,
197
211
) ;
198
212
check_assist (
199
- unmerge_use ,
213
+ unmerge_imports ,
200
214
r"
201
215
use foo::bar::{baz$0::{qux, foobar}, barbaz};
202
216
" ,
@@ -208,9 +222,9 @@ use foo::bar::baz::{qux, foobar};
208
222
}
209
223
210
224
#[ test]
211
- fn unmerge_use_item_with_visibility ( ) {
225
+ fn unmerge_import_with_visibility ( ) {
212
226
check_assist (
213
- unmerge_use ,
227
+ unmerge_imports ,
214
228
r"
215
229
pub use std::fmt::{Debug, Display$0};
216
230
" ,
@@ -222,12 +236,27 @@ pub use std::fmt::Display;
222
236
}
223
237
224
238
#[ test]
225
- fn unmerge_use_item_on_self ( ) {
239
+ fn unmerge_import_on_self ( ) {
226
240
check_assist (
227
- unmerge_use ,
241
+ unmerge_imports ,
228
242
r"use std::process::{Command, self$0};" ,
229
243
r"use std::process::{Command};
230
244
use std::process;" ,
231
245
) ;
232
246
}
247
+
248
+ #[ test]
249
+ fn unmerge_import_with_attributes ( ) {
250
+ check_assist (
251
+ unmerge_imports,
252
+ r"
253
+ #[allow(deprecated)]
254
+ use foo::{bar, baz$0};" ,
255
+ r"
256
+ #[allow(deprecated)]
257
+ use foo::{bar};
258
+ #[allow(deprecated)]
259
+ use foo::baz;" ,
260
+ ) ;
261
+ }
233
262
}
0 commit comments