33use assists:: utils:: { insert_use, mod_path_to_ast, ImportScope , MergeBehaviour } ;
44use hir:: Query ;
55use itertools:: Itertools ;
6- use syntax:: AstNode ;
6+ use syntax:: { algo , AstNode } ;
77use text_edit:: TextEdit ;
88
99use crate :: { context:: CompletionContext , item:: CompletionKind , CompletionItem , CompletionItemKind } ;
@@ -17,9 +17,6 @@ pub(crate) fn complete_magic(acc: &mut Completions, ctx: &CompletionContext) ->
1717 let current_module = ctx. scope . module ( ) ?;
1818 let anchor = ctx. name_ref_syntax . as_ref ( ) ?;
1919 let import_scope = ImportScope :: find_insert_use_container ( anchor. syntax ( ) , & ctx. sema ) ?;
20- // TODO kb now this is the whole file, which is not disjoint with any other change in the same file, fix it
21- // otherwise it's impossible to correctly add the use statement and also change the completed text into something more meaningful
22- let import_syntax = import_scope. as_syntax_node ( ) ;
2320
2421 // TODO kb consider heuristics, such as "don't show `hash_map` import if `HashMap` is the import for completion"
2522 // TODO kb module functions are not completed, consider `std::io::stdin` one
@@ -35,23 +32,24 @@ pub(crate) fn complete_magic(acc: &mut Completions, ctx: &CompletionContext) ->
3532 either:: Either :: Right ( macro_def) => current_module. find_use_path ( ctx. db , macro_def) ,
3633 } )
3734 . filter_map ( |mod_path| {
35+ let mut builder = TextEdit :: builder ( ) ;
36+
3837 let correct_qualifier = mod_path. segments . last ( ) ?. to_string ( ) ;
38+ builder. replace ( anchor. syntax ( ) . text_range ( ) , correct_qualifier) ;
39+
40+ // TODO kb: assists already have the merge behaviour setting, need to unite both
3941 let rewriter =
4042 insert_use ( & import_scope, mod_path_to_ast ( & mod_path) , Some ( MergeBehaviour :: Full ) ) ;
41- let rewritten_node = rewriter. rewrite ( import_syntax) ;
42- let insert_use_edit =
43- TextEdit :: replace ( import_syntax. text_range ( ) , rewritten_node. to_string ( ) ) ;
44- let mut completion_edit =
45- TextEdit :: replace ( anchor. syntax ( ) . text_range ( ) , correct_qualifier) ;
46- completion_edit. union ( insert_use_edit) . expect ( "TODO kb" ) ;
43+ let old_ast = rewriter. rewrite_root ( ) ?;
44+ algo:: diff ( & old_ast, & rewriter. rewrite ( & old_ast) ) . into_text_edit ( & mut builder) ;
4745
4846 let completion_item: CompletionItem = CompletionItem :: new (
4947 CompletionKind :: Magic ,
5048 ctx. source_range ( ) ,
5149 mod_path. to_string ( ) ,
5250 )
5351 . kind ( CompletionItemKind :: Struct )
54- . text_edit ( completion_edit )
52+ . text_edit ( builder . finish ( ) )
5553 . into ( ) ;
5654 Some ( completion_item)
5755 } ) ;
@@ -74,6 +72,48 @@ mod tests {
7472 expect. assert_eq ( & actual)
7573 }
7674
75+ #[ test]
76+ fn function_magic_completion ( ) {
77+ check (
78+ r#"
79+ //- /lib.rs crate:dep
80+ pub mod io {
81+ pub fn stdin() {}
82+ };
83+
84+ //- /main.rs crate:main deps:dep
85+ fn main() {
86+ stdi<|>
87+ }
88+ "# ,
89+ expect ! [ [ r#"
90+ st dep::io::stdin
91+ "# ] ] ,
92+ ) ;
93+
94+ check_edit (
95+ "dep::io::stdin" ,
96+ r#"
97+ //- /lib.rs crate:dep
98+ pub mod io {
99+ pub fn stdin() {}
100+ };
101+
102+ //- /main.rs crate:main deps:dep
103+ fn main() {
104+ stdi<|>
105+ }
106+ "# ,
107+ r#"
108+ use dep::io::stdin;
109+
110+ fn main() {
111+ stdin
112+ }
113+ "# ,
114+ ) ;
115+ }
116+
77117 #[ test]
78118 fn case_insensitive_magic_completion_works ( ) {
79119 check (
0 commit comments