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,19 @@ 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 parent_node = use_item. syntax ( ) . parent ( ) ?;
40+ let ( editor, _) =
41+ SyntaxEditor :: new ( parent_node. ancestors ( ) . last ( ) . unwrap_or ( parent_node. clone ( ) ) ) ;
42+ merge_uses ( use_item, vec ! [ neighbor] , & ctx. config . insert_use , & editor) ?;
43+ ( target, editor)
4144 } else {
4245 // Merge selected
4346 let selection_range = ctx. selection_trimmed ( ) ;
@@ -50,104 +53,81 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> O
5053 } ) ;
5154
5255 let first_selected = selected_nodes. next ( ) ?;
53- let edits = match_ast ! {
56+ let ( editor, _) =
57+ SyntaxEditor :: new ( parent_node. ancestors ( ) . last ( ) . unwrap_or ( parent_node. clone ( ) ) ) ;
58+ match_ast ! {
5459 match first_selected {
5560 ast:: Use ( use_item) => {
5661 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)
62+ merge_uses(
63+ use_item,
64+ selected_nodes. filter_map( ast:: Use :: cast) . collect( ) ,
65+ & ctx. config. insert_use,
66+ & editor,
67+ ) ?;
5868 } ,
5969 ast:: UseTree ( use_tree) => {
6070 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)
71+ merge_use_trees(
72+ use_tree,
73+ selected_nodes. filter_map( ast:: UseTree :: cast) . collect( ) ,
74+ & editor,
75+ ) ?;
6276 } ,
6377 _ => return None ,
6478 }
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 ( ) ?,
79+ }
80+ ( selection_range, editor)
7281 } ;
7382
7483 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- }
9284 builder. add_file_edits ( ctx. vfs_file_id ( ) , editor) ;
9385 } )
9486}
9587
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- }
88+ fn merge_uses (
89+ first : ast:: Use ,
90+ rest : Vec < ast:: Use > ,
91+ cfg : & InsertUseConfig ,
92+ editor : & SyntaxEditor ,
93+ ) -> Option < ( ) > {
94+ if rest. is_empty ( ) {
95+ return None ;
11496 }
115- fn try_merge ( & self , other : & Self , cfg : & InsertUseConfig ) -> Option < Self > ;
116- fn into_either ( self ) -> Either < ast:: Use , ast:: UseTree > ;
117- }
11897
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)
98+ let mb = match cfg . granularity {
99+ ImportGranularity :: One => MergeBehavior :: One ,
100+ _ => MergeBehavior :: Crate ,
101+ } ;
102+ let mut merged = first . clone ( ) ;
103+ for item in & rest {
104+ merged = try_merge_imports ( editor , & merged , item , mb) ? ;
126105 }
127- fn into_either ( self ) -> Either < ast :: Use , ast :: UseTree > {
128- Either :: Left ( self )
106+ for item in rest {
107+ item . remove ( editor ) ;
129108 }
109+ editor. replace ( first. syntax ( ) , merged. syntax ( ) ) ;
110+ Some ( ( ) )
130111}
131112
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 )
113+ fn merge_use_trees (
114+ first : ast:: UseTree ,
115+ rest : Vec < ast:: UseTree > ,
116+ editor : & SyntaxEditor ,
117+ ) -> Option < ( ) > {
118+ if rest. is_empty ( ) {
119+ return None ;
138120 }
139- }
140-
141- #[ derive( Debug ) ]
142- enum Edit {
143- Remove ( Either < ast:: Use , ast:: UseTree > ) ,
144- Replace ( SyntaxNode , SyntaxNode ) ,
145- }
146121
147- impl Edit {
148- fn replace ( old : impl AstNode , new : impl AstNode ) -> Self {
149- Edit :: Replace ( old. syntax ( ) . clone ( ) , new. syntax ( ) . clone ( ) )
122+ let mut merged = first. clone ( ) ;
123+ for item in & rest {
124+ merged = try_merge_trees ( editor, & merged, item, MergeBehavior :: Crate ) ?;
125+ }
126+ for item in rest {
127+ item. remove ( editor) ;
150128 }
129+ editor. replace ( first. syntax ( ) , merged. syntax ( ) ) ;
130+ Some ( ( ) )
151131}
152132
153133#[ cfg( test) ]
0 commit comments