1- use either:: Either ;
21use ide_db:: imports:: {
32 insert_use:: { ImportGranularity , InsertUseConfig } ,
43 merge_imports:: { MergeBehavior , try_merge_imports, try_merge_trees} ,
54} ;
65use syntax:: {
7- AstNode , SyntaxElement , SyntaxNode , algo:: neighbor, ast, match_ast, syntax_editor:: Removable ,
6+ AstNode , SyntaxElement ,
7+ algo:: neighbor,
8+ ast, match_ast,
9+ syntax_editor:: { Removable , SyntaxEditor } ,
810} ;
911
1012use crate :: {
@@ -13,8 +15,6 @@ use crate::{
1315 utils:: next_prev,
1416} ;
1517
16- use Edit :: * ;
17-
1818// Assist: merge_imports
1919//
2020// Merges neighbor imports with a common prefix.
@@ -28,16 +28,17 @@ use Edit::*;
2828// use std::{fmt::Formatter, io};
2929// ```
3030pub ( crate ) fn merge_imports ( acc : & mut Assists , ctx : & AssistContext < ' _ , ' _ > ) -> Option < ( ) > {
31- let ( target, edits ) = if ctx. has_empty_selection ( ) {
31+ let ( target, editor ) = if ctx. has_empty_selection ( ) {
3232 // Merge a neighbor
3333 cov_mark:: hit!( merge_with_use_item_neighbors) ;
3434 let tree = ctx. find_node_at_offset :: < ast:: UseTree > ( ) ?. top_use_tree ( ) ;
3535 let target = tree. syntax ( ) . text_range ( ) ;
3636
3737 let use_item = tree. syntax ( ) . parent ( ) . and_then ( ast:: Use :: cast) ?;
38- let mut neighbor = next_prev ( ) . find_map ( |dir| neighbor ( & use_item, dir) ) . into_iter ( ) ;
39- let edits = use_item. try_merge_from ( & mut neighbor, & ctx. config . insert_use ) ;
40- ( target, edits?)
38+ let neighbor = next_prev ( ) . find_map ( |dir| neighbor ( & use_item, dir) ) ?;
39+ let ( editor, _) = SyntaxEditor :: new ( use_item. syntax ( ) . parent ( ) ?. ancestors ( ) . last ( ) ?) ;
40+ merge_uses ( use_item, vec ! [ neighbor] , & ctx. config . insert_use , & editor) ?;
41+ ( target, editor)
4142 } else {
4243 // Merge selected
4344 let selection_range = ctx. selection_trimmed ( ) ;
@@ -50,104 +51,80 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> O
5051 } ) ;
5152
5253 let first_selected = selected_nodes. next ( ) ?;
53- let edits = match_ast ! {
54+ let ( editor, _) = SyntaxEditor :: new ( parent_node. ancestors ( ) . last ( ) . unwrap ( ) ) ;
55+ match_ast ! {
5456 match first_selected {
5557 ast:: Use ( use_item) => {
5658 cov_mark:: hit!( merge_with_selected_use_item_neighbors) ;
57- use_item. try_merge_from( & mut selected_nodes. filter_map( ast:: Use :: cast) , & ctx. config. insert_use)
59+ merge_uses(
60+ use_item,
61+ selected_nodes. filter_map( ast:: Use :: cast) . collect( ) ,
62+ & ctx. config. insert_use,
63+ & editor,
64+ ) ?;
5865 } ,
5966 ast:: UseTree ( use_tree) => {
6067 cov_mark:: hit!( merge_with_selected_use_tree_neighbors) ;
61- use_tree. try_merge_from( & mut selected_nodes. filter_map( ast:: UseTree :: cast) , & ctx. config. insert_use)
68+ merge_use_trees(
69+ use_tree,
70+ selected_nodes. filter_map( ast:: UseTree :: cast) . collect( ) ,
71+ & editor,
72+ ) ?;
6273 } ,
6374 _ => return None ,
6475 }
65- } ;
66- ( selection_range, edits?)
67- } ;
68-
69- let parent_node = match ctx. covering_element ( ) {
70- SyntaxElement :: Node ( n) => n,
71- SyntaxElement :: Token ( t) => t. parent ( ) ?,
76+ }
77+ ( selection_range, editor)
7278 } ;
7379
7480 acc. add ( AssistId :: refactor_rewrite ( "merge_imports" ) , "Merge imports" , target, |builder| {
75- let editor = builder. make_editor ( & parent_node) ;
76-
77- for edit in edits {
78- match edit {
79- Remove ( it) => {
80- let node = it. as_ref ( ) ;
81- if let Some ( left) = node. left ( ) {
82- left. remove ( & editor) ;
83- } else if let Some ( right) = node. right ( ) {
84- right. remove ( & editor) ;
85- }
86- }
87- Replace ( old, new) => {
88- editor. replace ( old, & new) ;
89- }
90- }
91- }
9281 builder. add_file_edits ( ctx. vfs_file_id ( ) , editor) ;
9382 } )
9483}
9584
96- trait Merge : AstNode + Clone {
97- fn try_merge_from (
98- self ,
99- items : & mut dyn Iterator < Item = Self > ,
100- cfg : & InsertUseConfig ,
101- ) -> Option < Vec < Edit > > {
102- let mut edits = Vec :: new ( ) ;
103- let mut merged = self . clone ( ) ;
104- for item in items {
105- merged = merged. try_merge ( & item, cfg) ?;
106- edits. push ( Edit :: Remove ( item. into_either ( ) ) ) ;
107- }
108- if !edits. is_empty ( ) {
109- edits. push ( Edit :: replace ( self , merged) ) ;
110- Some ( edits)
111- } else {
112- None
113- }
85+ fn merge_uses (
86+ first : ast:: Use ,
87+ rest : Vec < ast:: Use > ,
88+ cfg : & InsertUseConfig ,
89+ editor : & SyntaxEditor ,
90+ ) -> Option < ( ) > {
91+ if rest. is_empty ( ) {
92+ return None ;
11493 }
115- fn try_merge ( & self , other : & Self , cfg : & InsertUseConfig ) -> Option < Self > ;
116- fn into_either ( self ) -> Either < ast:: Use , ast:: UseTree > ;
117- }
11894
119- impl Merge for ast :: Use {
120- fn try_merge ( & self , other : & Self , cfg : & InsertUseConfig ) -> Option < Self > {
121- let mb = match cfg . granularity {
122- ImportGranularity :: One => MergeBehavior :: One ,
123- _ => MergeBehavior :: Crate ,
124- } ;
125- try_merge_imports ( self , other , mb)
95+ let mb = match cfg . granularity {
96+ ImportGranularity :: One => MergeBehavior :: One ,
97+ _ => MergeBehavior :: Crate ,
98+ } ;
99+ let mut merged = first . clone ( ) ;
100+ for item in & rest {
101+ merged = try_merge_imports ( editor , & merged , item , mb) ? ;
126102 }
127- fn into_either ( self ) -> Either < ast :: Use , ast :: UseTree > {
128- Either :: Left ( self )
103+ for item in rest {
104+ item . remove ( editor ) ;
129105 }
106+ editor. replace ( first. syntax ( ) , merged. syntax ( ) ) ;
107+ Some ( ( ) )
130108}
131109
132- impl Merge for ast:: UseTree {
133- fn try_merge ( & self , other : & Self , _: & InsertUseConfig ) -> Option < Self > {
134- try_merge_trees ( self , other, MergeBehavior :: Crate )
135- }
136- fn into_either ( self ) -> Either < ast:: Use , ast:: UseTree > {
137- Either :: Right ( self )
110+ fn merge_use_trees (
111+ first : ast:: UseTree ,
112+ rest : Vec < ast:: UseTree > ,
113+ editor : & SyntaxEditor ,
114+ ) -> Option < ( ) > {
115+ if rest. is_empty ( ) {
116+ return None ;
138117 }
139- }
140-
141- #[ derive( Debug ) ]
142- enum Edit {
143- Remove ( Either < ast:: Use , ast:: UseTree > ) ,
144- Replace ( SyntaxNode , SyntaxNode ) ,
145- }
146118
147- impl Edit {
148- fn replace ( old : impl AstNode , new : impl AstNode ) -> Self {
149- Edit :: Replace ( old. syntax ( ) . clone ( ) , new. syntax ( ) . clone ( ) )
119+ let mut merged = first. clone ( ) ;
120+ for item in & rest {
121+ merged = try_merge_trees ( editor, & merged, item, MergeBehavior :: Crate ) ?;
122+ }
123+ for item in rest {
124+ item. remove ( editor) ;
150125 }
126+ editor. replace ( first. syntax ( ) , merged. syntax ( ) ) ;
127+ Some ( ( ) )
151128}
152129
153130#[ cfg( test) ]
0 commit comments