@@ -43,6 +43,7 @@ use syntax::{
4343use text_edit:: TextEdit ;
4444
4545use crate :: {
46+ context:: { ItemListKind , NameContext , NameKind , NameRefContext , PathCompletionCtx , PathKind } ,
4647 CompletionContext , CompletionItem , CompletionItemKind , CompletionRelevance , Completions ,
4748} ;
4849
@@ -54,7 +55,6 @@ enum ImplCompletionKind {
5455 Const ,
5556}
5657
57- // FIXME: Make this a submodule of [`item_list`]
5858pub ( crate ) fn complete_trait_impl ( acc : & mut Completions , ctx : & CompletionContext ) {
5959 if let Some ( ( kind, replacement_range, impl_def) ) = completion_match ( ctx) {
6060 if let Some ( hir_impl) = ctx. sema . to_def ( & impl_def) {
@@ -77,74 +77,48 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
7777 }
7878}
7979
80- // FIXME: This should be lifted out so that we can do proper smart item keyword completions
8180fn completion_match ( ctx : & CompletionContext ) -> Option < ( ImplCompletionKind , TextRange , ast:: Impl ) > {
8281 let token = ctx. token . clone ( ) ;
8382
84- // For keyword without name like `impl .. { fn $0 }`, the current position is inside
85- // the whitespace token, which is outside `FN` syntax node.
86- // We need to follow the previous token in this case.
87- let mut token_before_ws = token. clone ( ) ;
88- if token. kind ( ) == SyntaxKind :: WHITESPACE {
89- token_before_ws = token. prev_token ( ) ?;
90- }
91-
92- let parent_kind = token_before_ws. parent ( ) . map_or ( SyntaxKind :: EOF , |it| it. kind ( ) ) ;
93- if token. parent ( ) . map ( |n| n. kind ( ) ) == Some ( SyntaxKind :: ASSOC_ITEM_LIST )
94- && matches ! (
95- token_before_ws. kind( ) ,
96- SyntaxKind :: SEMICOLON | SyntaxKind :: R_CURLY | SyntaxKind :: L_CURLY
97- )
98- {
99- let impl_def = ast:: Impl :: cast ( token. parent ( ) ?. parent ( ) ?) ?;
100- let kind = ImplCompletionKind :: All ;
101- let replacement_range = TextRange :: empty ( ctx. position . offset ) ;
102- Some ( ( kind, replacement_range, impl_def) )
103- } else {
104- let impl_item_offset = match token_before_ws. kind ( ) {
105- // `impl .. { const $0 }`
106- // ERROR 0
107- // CONST_KW <- *
108- T ! [ const ] => 0 ,
109- // `impl .. { fn/type $0 }`
110- // FN/TYPE_ALIAS 0
111- // FN_KW <- *
112- T ! [ fn ] | T ! [ type ] => 0 ,
113- // `impl .. { fn/type/const foo$0 }`
114- // FN/TYPE_ALIAS/CONST 1
115- // NAME 0
116- // IDENT <- *
117- SyntaxKind :: IDENT if parent_kind == SyntaxKind :: NAME => 1 ,
118- // `impl .. { foo$0 }`
119- // MACRO_CALL 3
120- // PATH 2
121- // PATH_SEGMENT 1
122- // NAME_REF 0
123- // IDENT <- *
124- SyntaxKind :: IDENT if parent_kind == SyntaxKind :: NAME_REF => 3 ,
83+ if let Some ( NameContext { name, kind, .. } ) = ctx. name_ctx ( ) {
84+ let kind = match kind {
85+ NameKind :: Const => ImplCompletionKind :: Const ,
86+ NameKind :: Function => ImplCompletionKind :: Fn ,
87+ NameKind :: TypeAlias => ImplCompletionKind :: TypeAlias ,
12588 _ => return None ,
12689 } ;
127-
128- let impl_item = token_before_ws. ancestors ( ) . nth ( impl_item_offset) ?;
129- // Must directly belong to an impl block.
130- // IMPL
131- // ASSOC_ITEM_LIST
132- // <item>
133- let impl_def = ast:: Impl :: cast ( impl_item. parent ( ) ?. parent ( ) ?) ?;
134- let kind = match impl_item. kind ( ) {
135- // `impl ... { const $0 fn/type/const }`
136- _ if token_before_ws. kind ( ) == T ! [ const ] => ImplCompletionKind :: Const ,
137- SyntaxKind :: CONST | SyntaxKind :: ERROR => ImplCompletionKind :: Const ,
138- SyntaxKind :: TYPE_ALIAS => ImplCompletionKind :: TypeAlias ,
139- SyntaxKind :: FN => ImplCompletionKind :: Fn ,
140- SyntaxKind :: MACRO_CALL => ImplCompletionKind :: All ,
141- _ => return None ,
142- } ;
143-
144- let replacement_range = replacement_range ( ctx, & impl_item) ;
145-
146- Some ( ( kind, replacement_range, impl_def) )
90+ let item = match name {
91+ Some ( name) => name. syntax ( ) . parent ( ) ,
92+ None => {
93+ if token. kind ( ) == SyntaxKind :: WHITESPACE { token. prev_token ( ) ? } else { token }
94+ . parent ( )
95+ }
96+ } ?;
97+ return Some ( (
98+ kind,
99+ replacement_range ( ctx, & item) ,
100+ // item -> ASSOC_ITEM_LIST -> IMPL
101+ ast:: Impl :: cast ( item. parent ( ) ?. parent ( ) ?) ?,
102+ ) ) ;
103+ } else if let Some ( NameRefContext {
104+ nameref,
105+ path_ctx :
106+ Some ( PathCompletionCtx { kind : PathKind :: Item { kind : ItemListKind :: TraitImpl } , .. } ) ,
107+ ..
108+ } ) = ctx. nameref_ctx ( )
109+ {
110+ if !ctx. is_non_trivial_path ( ) {
111+ return Some ( (
112+ ImplCompletionKind :: All ,
113+ match nameref {
114+ Some ( name) => name. syntax ( ) . text_range ( ) ,
115+ None => TextRange :: empty ( ctx. position . offset ) ,
116+ } ,
117+ ctx. impl_def . clone ( ) ?,
118+ ) ) ;
119+ }
147120 }
121+ None
148122}
149123
150124fn add_function_impl (
0 commit comments