Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 519ac81

Browse files
committed
internal: Move most remaining keyword completions to item list completions
1 parent 4f5c7aa commit 519ac81

File tree

6 files changed

+135
-143
lines changed

6 files changed

+135
-143
lines changed

crates/ide-completion/src/completions/item_list.rs

Lines changed: 101 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,98 @@
22
33
use crate::{
44
completions::module_or_fn_macro,
5-
context::{PathCompletionCtx, PathKind, PathQualifierCtx},
6-
CompletionContext, Completions,
5+
context::{ItemListKind, PathCompletionCtx, PathKind, PathQualifierCtx},
6+
CompletionContext, CompletionItem, CompletionItemKind, Completions,
77
};
88

99
pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext) {
1010
let _p = profile::span("complete_item_list");
1111

12-
let (&is_absolute_path, path_qualifier, _kind) = match ctx.path_context() {
12+
let (&is_absolute_path, path_qualifier, kind) = match ctx.path_context() {
1313
Some(PathCompletionCtx {
1414
kind: PathKind::Item { kind },
1515
is_absolute_path,
1616
qualifier,
1717
..
18-
}) => (is_absolute_path, qualifier, kind),
18+
}) => (is_absolute_path, qualifier, Some(kind)),
19+
Some(PathCompletionCtx {
20+
kind: PathKind::Expr { in_block_expr: true, .. },
21+
is_absolute_path,
22+
qualifier,
23+
..
24+
}) => (is_absolute_path, qualifier, None),
1925
_ => return,
2026
};
27+
let mut add_keyword = |kw, snippet| add_keyword(acc, ctx, kw, snippet);
28+
29+
let in_item_list = matches!(kind, Some(ItemListKind::SourceFile | ItemListKind::Module) | None);
30+
let in_assoc_non_trait_impl = matches!(kind, Some(ItemListKind::Impl | ItemListKind::Trait));
31+
let in_extern_block = matches!(kind, Some(ItemListKind::ExternBlock));
32+
let in_trait = matches!(kind, Some(ItemListKind::Trait));
33+
let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl));
34+
let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl));
35+
let no_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
36+
let in_block = matches!(kind, None);
37+
38+
'block: loop {
39+
if path_qualifier.is_some() {
40+
break 'block;
41+
}
42+
if !in_trait_impl {
43+
if ctx.qualifier_ctx.unsafe_tok.is_some() {
44+
if in_item_list || in_assoc_non_trait_impl {
45+
add_keyword("fn", "fn $1($2) {\n $0\n}");
46+
}
47+
if in_item_list {
48+
add_keyword("trait", "trait $1 {\n $0\n}");
49+
if no_qualifiers {
50+
add_keyword("impl", "impl $1 {\n $0\n}");
51+
}
52+
}
53+
break 'block;
54+
}
55+
56+
if in_item_list {
57+
add_keyword("enum", "enum $1 {\n $0\n}");
58+
add_keyword("mod", "mod $0");
59+
add_keyword("static", "static $0");
60+
add_keyword("struct", "struct $0");
61+
add_keyword("trait", "trait $1 {\n $0\n}");
62+
add_keyword("union", "union $1 {\n $0\n}");
63+
add_keyword("use", "use $0");
64+
if no_qualifiers {
65+
add_keyword("impl", "impl $1 {\n $0\n}");
66+
}
67+
}
68+
69+
if !in_trait && !in_block && no_qualifiers {
70+
add_keyword("pub(crate)", "pub(crate)");
71+
add_keyword("pub(super)", "pub(super)");
72+
add_keyword("pub", "pub");
73+
}
74+
75+
if in_extern_block {
76+
add_keyword("fn", "fn $1($2);");
77+
} else {
78+
if !in_inherent_impl {
79+
if !in_trait {
80+
add_keyword("extern", "extern $0");
81+
}
82+
add_keyword("type", "type $0");
83+
}
84+
85+
add_keyword("fn", "fn $1($2) {\n $0\n}");
86+
add_keyword("unsafe", "unsafe");
87+
add_keyword("const", "const $0");
88+
}
89+
}
90+
break 'block;
91+
}
92+
93+
if kind.is_none() {
94+
// this is already handled by expression
95+
return;
96+
}
2197

2298
match path_qualifier {
2399
Some(PathQualifierCtx { resolution, is_super_chain, .. }) => {
@@ -33,9 +109,7 @@ pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext)
33109
acc.add_keyword(ctx, "super::");
34110
}
35111
}
36-
None if is_absolute_path => {
37-
acc.add_crate_roots(ctx);
38-
}
112+
None if is_absolute_path => acc.add_crate_roots(ctx),
39113
None if ctx.qualifier_ctx.none() => {
40114
ctx.process_all_names(&mut |name, def| {
41115
if let Some(def) = module_or_fn_macro(ctx.db, def) {
@@ -47,3 +121,23 @@ pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext)
47121
None => {}
48122
}
49123
}
124+
125+
pub(super) fn add_keyword(acc: &mut Completions, ctx: &CompletionContext, kw: &str, snippet: &str) {
126+
let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
127+
128+
match ctx.config.snippet_cap {
129+
Some(cap) => {
130+
if snippet.ends_with('}') && ctx.incomplete_let {
131+
// complete block expression snippets with a trailing semicolon, if inside an incomplete let
132+
cov_mark::hit!(let_semi);
133+
item.insert_snippet(cap, format!("{};", snippet));
134+
} else {
135+
item.insert_snippet(cap, snippet);
136+
}
137+
}
138+
None => {
139+
item.insert_text(if snippet.contains('$') { kw } else { snippet });
140+
}
141+
};
142+
item.add_to(acc);
143+
}

crates/ide-completion/src/completions/keyword.rs

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
//! - `self`, `super` and `crate`, as these are considered part of path completions.
33
//! - `await`, as this is a postfix completion we handle this in the postfix completions.
44
5-
use syntax::T;
6-
75
use crate::{
86
context::{NameRefContext, PathKind},
97
CompletionContext, CompletionItem, CompletionItemKind, Completions,
@@ -24,10 +22,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
2422

2523
let mut add_keyword = |kw, snippet| add_keyword(acc, ctx, kw, snippet);
2624

27-
let expects_assoc_item = ctx.expects_assoc_item();
28-
let has_block_expr_parent = ctx.has_block_expr_parent();
29-
let expects_item = ctx.expects_item();
30-
3125
if let Some(PathKind::Vis { .. }) = ctx.path_kind() {
3226
return;
3327
}
@@ -38,50 +32,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
3832
}
3933
return;
4034
}
41-
if ctx.previous_token_is(T![unsafe]) {
42-
if expects_item || expects_assoc_item || has_block_expr_parent {
43-
add_keyword("fn", "fn $1($2) {\n $0\n}")
44-
}
45-
46-
if expects_item || has_block_expr_parent {
47-
add_keyword("trait", "trait $1 {\n $0\n}");
48-
add_keyword("impl", "impl $1 {\n $0\n}");
49-
}
50-
51-
return;
52-
}
53-
54-
if ctx.qualifier_ctx.vis_node.is_none()
55-
&& (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field())
56-
{
57-
add_keyword("pub(crate)", "pub(crate)");
58-
add_keyword("pub(super)", "pub(super)");
59-
add_keyword("pub", "pub");
60-
}
61-
62-
if expects_item || expects_assoc_item || has_block_expr_parent {
63-
add_keyword("unsafe", "unsafe");
64-
add_keyword("fn", "fn $1($2) {\n $0\n}");
65-
add_keyword("const", "const $0");
66-
add_keyword("type", "type $0");
67-
}
68-
69-
if expects_item || has_block_expr_parent {
70-
if ctx.qualifier_ctx.vis_node.is_none() {
71-
add_keyword("impl", "impl $1 {\n $0\n}");
72-
add_keyword("extern", "extern $0");
73-
}
74-
add_keyword("use", "use $0");
75-
add_keyword("trait", "trait $1 {\n $0\n}");
76-
add_keyword("static", "static $0");
77-
add_keyword("mod", "mod $0");
78-
}
79-
80-
if expects_item || has_block_expr_parent {
81-
add_keyword("enum", "enum $1 {\n $0\n}");
82-
add_keyword("struct", "struct $0");
83-
add_keyword("union", "union $1 {\n $0\n}");
84-
}
8535
}
8636

8737
pub(super) fn add_keyword(acc: &mut Completions, ctx: &CompletionContext, kw: &str, snippet: &str) {

crates/ide-completion/src/context.rs

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ pub(super) enum ItemListKind {
7171
SourceFile,
7272
Module,
7373
Impl,
74+
TraitImpl,
7475
Trait,
7576
ExternBlock,
7677
}
@@ -335,10 +336,6 @@ impl<'a> CompletionContext<'a> {
335336
matches!(self.completion_location, Some(ImmediateLocation::Trait | ImmediateLocation::Impl))
336337
}
337338

338-
pub(crate) fn expects_non_trait_assoc_item(&self) -> bool {
339-
matches!(self.completion_location, Some(ImmediateLocation::Impl))
340-
}
341-
342339
pub(crate) fn expects_item(&self) -> bool {
343340
matches!(self.completion_location, Some(ImmediateLocation::ItemList))
344341
}
@@ -348,19 +345,10 @@ impl<'a> CompletionContext<'a> {
348345
matches!(self.completion_location, Some(ImmediateLocation::GenericArgList(_)))
349346
}
350347

351-
pub(crate) fn has_block_expr_parent(&self) -> bool {
352-
matches!(self.completion_location, Some(ImmediateLocation::StmtList))
353-
}
354-
355348
pub(crate) fn expects_ident_ref_expr(&self) -> bool {
356349
matches!(self.completion_location, Some(ImmediateLocation::RefExpr))
357350
}
358351

359-
pub(crate) fn expect_field(&self) -> bool {
360-
matches!(self.completion_location, Some(ImmediateLocation::TupleField))
361-
|| matches!(self.name_ctx(), Some(NameContext { kind: NameKind::RecordField, .. }))
362-
}
363-
364352
/// Whether the cursor is right after a trait or impl header.
365353
/// trait Foo ident$0
366354
// FIXME: This probably shouldn't exist
@@ -1276,10 +1264,19 @@ impl<'a> CompletionContext<'a> {
12761264
Some(SyntaxKind::MACRO_PAT) => Some(PathKind::Pat),
12771265
Some(SyntaxKind::MACRO_TYPE) => Some(PathKind::Type),
12781266
Some(SyntaxKind::ITEM_LIST) => Some(PathKind::Item { kind: ItemListKind::Module }),
1279-
Some(SyntaxKind::ASSOC_ITEM_LIST) => Some(PathKind::Item { kind: match parent.and_then(|it| it.parent()).map(|it| it.kind()) {
1280-
Some(SyntaxKind::TRAIT) => ItemListKind::Trait,
1281-
Some(SyntaxKind::IMPL) => ItemListKind::Impl,
1282-
_ => return Some(None),
1267+
Some(SyntaxKind::ASSOC_ITEM_LIST) => Some(PathKind::Item { kind: match parent.and_then(|it| it.parent()) {
1268+
Some(it) => match_ast! {
1269+
match it {
1270+
ast::Trait(_) => ItemListKind::Trait,
1271+
ast::Impl(it) => if it.trait_().is_some() {
1272+
ItemListKind::TraitImpl
1273+
} else {
1274+
ItemListKind::Impl
1275+
},
1276+
_ => return Some(None)
1277+
}
1278+
},
1279+
None => return Some(None),
12831280
} }),
12841281
Some(SyntaxKind::EXTERN_ITEM_LIST) => Some(PathKind::Item { kind: ItemListKind::ExternBlock }),
12851282
Some(SyntaxKind::SOURCE_FILE) => Some(PathKind::Item { kind: ItemListKind::SourceFile }),
@@ -1313,12 +1310,18 @@ impl<'a> CompletionContext<'a> {
13131310
ast::UseTree(_) => Some(PathKind::Use),
13141311
ast::ItemList(_) => Some(PathKind::Item { kind: ItemListKind::Module }),
13151312
ast::AssocItemList(it) => Some(PathKind::Item { kind: {
1316-
match it.syntax().parent()?.kind() {
1317-
SyntaxKind::TRAIT => ItemListKind::Trait,
1318-
SyntaxKind::IMPL => ItemListKind::Impl,
1319-
_ => return None,
1313+
match_ast! {
1314+
match (it.syntax().parent()?) {
1315+
ast::Trait(_) => ItemListKind::Trait,
1316+
ast::Impl(it) => if it.trait_().is_some() {
1317+
ItemListKind::TraitImpl
1318+
} else {
1319+
ItemListKind::Impl
1320+
},
1321+
_ => return None
13201322
}
1321-
}}),
1323+
}
1324+
}}),
13221325
ast::ExternItemList(_) => Some(PathKind::Item { kind: ItemListKind::ExternBlock }),
13231326
ast::SourceFile(_) => Some(PathKind::Item { kind: ItemListKind::SourceFile }),
13241327
_ => return None,

crates/ide-completion/src/tests/item.rs

Lines changed: 6 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -88,69 +88,26 @@ fn after_target_name_in_impl() {
8888

8989
#[test]
9090
fn after_struct_name() {
91-
// FIXME: This should emit `kw where` only
92-
check(
93-
r"struct Struct $0",
94-
expect![[r#"
95-
kw const
96-
kw enum
97-
kw extern
98-
kw fn
99-
kw impl
100-
kw mod
101-
kw pub
102-
kw pub(crate)
103-
kw pub(super)
104-
kw static
105-
kw struct
106-
kw trait
107-
kw type
108-
kw union
109-
kw unsafe
110-
kw use
111-
"#]],
112-
);
91+
// FIXME: This should emit `kw where`
92+
check(r"struct Struct $0", expect![[r#""#]]);
11393
}
11494

11595
#[test]
11696
fn after_fn_name() {
117-
// FIXME: This should emit `kw where` only
118-
check(
119-
r"fn func() $0",
120-
expect![[r#"
121-
kw const
122-
kw enum
123-
kw extern
124-
kw fn
125-
kw impl
126-
kw mod
127-
kw pub
128-
kw pub(crate)
129-
kw pub(super)
130-
kw static
131-
kw struct
132-
kw trait
133-
kw type
134-
kw union
135-
kw unsafe
136-
kw use
137-
"#]],
138-
);
97+
// FIXME: This should emit `kw where`
98+
check(r"fn func() $0", expect![[r#""#]]);
13999
}
140100

141101
#[test]
142102
fn before_record_field() {
103+
// FIXME: This should emit visibility qualifiers
143104
check(
144105
r#"
145106
struct Foo {
146107
$0
147108
pub f: i32,
148109
}
149110
"#,
150-
expect![[r#"
151-
kw pub
152-
kw pub(crate)
153-
kw pub(super)
154-
"#]],
111+
expect![[r#""#]],
155112
)
156113
}

0 commit comments

Comments
 (0)