ide_completion/completions/
item_list.rs1use crate::{
4 CompletionContext, Completions,
5 context::{ItemListKind, PathCompletionCtx, PathExprCtx, Qualified},
6};
7
8pub(crate) mod trait_impl;
9
10pub(crate) fn complete_item_list_in_expr(
11 acc: &mut Completions,
12 ctx: &CompletionContext<'_, '_>,
13 path_ctx: &PathCompletionCtx<'_>,
14 expr_ctx: &PathExprCtx<'_>,
15) {
16 if !expr_ctx.in_block_expr {
17 return;
18 }
19 if !path_ctx.is_trivial_path() {
20 return;
21 }
22 add_keywords(acc, ctx, None);
23}
24
25pub(crate) fn complete_item_list(
26 acc: &mut Completions,
27 ctx: &CompletionContext<'_, '_>,
28 path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
29 kind: &ItemListKind,
30) {
31 let _p = tracing::info_span!("complete_item_list").entered();
32
33 if path_ctx.is_trivial_path() && !matches!(kind, ItemListKind::TraitImpl(_)) {
35 add_keywords(acc, ctx, Some(kind));
36 }
37
38 match qualified {
39 Qualified::With {
40 resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))),
41 super_chain_len,
42 ..
43 } => {
44 for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
45 match def {
46 hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => {
47 acc.add_macro(ctx, path_ctx, m, name)
48 }
49 hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
50 acc.add_module(ctx, path_ctx, m, name, vec![])
51 }
52 _ => (),
53 }
54 }
55
56 acc.add_super_keyword(ctx, *super_chain_len);
57 }
58 Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
59 Qualified::No if ctx.qualifier_ctx.none() => {
60 ctx.process_all_names(&mut |name, def, doc_aliases| match def {
61 hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => {
62 acc.add_macro(ctx, path_ctx, m, name)
63 }
64 hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
65 acc.add_module(ctx, path_ctx, m, name, doc_aliases)
66 }
67 _ => (),
68 });
69 acc.add_nameref_keywords_with_colon(ctx);
70 }
71 Qualified::TypeAnchor { .. } | Qualified::No | Qualified::With { .. } => {}
72 }
73}
74
75fn add_keywords(
76 acc: &mut Completions,
77 ctx: &CompletionContext<'_, '_>,
78 kind: Option<&ItemListKind>,
79) {
80 let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
81
82 let in_item_list = matches!(kind, Some(ItemListKind::SourceFile | ItemListKind::Module) | None);
83 let in_assoc_non_trait_impl = matches!(kind, Some(ItemListKind::Impl | ItemListKind::Trait));
84
85 let in_extern_block = matches!(kind, Some(ItemListKind::ExternBlock { .. }));
86 let in_unsafe_extern_block =
87 matches!(kind, Some(ItemListKind::ExternBlock { is_unsafe: true }));
88
89 let in_trait = matches!(kind, Some(ItemListKind::Trait));
90 let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl));
91 let in_block = kind.is_none();
92
93 let no_vis_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
94 let no_abi_qualifiers = ctx.qualifier_ctx.abi_node.is_none();
95 let has_extern_kw =
96 ctx.qualifier_ctx.abi_node.as_ref().is_some_and(|it| it.string_token().is_none());
97 let has_unsafe_kw = ctx.qualifier_ctx.unsafe_tok.is_some();
98 let has_async_kw = ctx.qualifier_ctx.async_tok.is_some();
99 let has_safe_kw = ctx.qualifier_ctx.safe_tok.is_some();
100
101 if (has_unsafe_kw || has_safe_kw) && in_extern_block {
103 add_keyword("fn", "fn $1($2);");
104 add_keyword("static", "static $1: $2;");
105 return;
106 }
107
108 if has_unsafe_kw || has_async_kw {
109 if !has_unsafe_kw {
110 add_keyword("unsafe", "unsafe $0");
111 }
112 if !has_async_kw {
113 add_keyword("async", "async $0");
114 }
115
116 if in_item_list || in_assoc_non_trait_impl {
117 add_keyword("fn", "fn $1($2) {\n $0\n}");
118 }
119
120 if has_unsafe_kw && in_item_list {
121 add_keyword("trait", "trait $1 {\n $0\n}");
122 if no_vis_qualifiers {
123 add_keyword("impl", "impl $1 {\n $0\n}");
124 add_keyword("impl for", "impl $1 for $2 {\n $0\n}");
125 }
126 }
127
128 if !has_async_kw && no_vis_qualifiers && no_abi_qualifiers && in_item_list {
129 add_keyword("extern", "extern $0");
130 }
131
132 return;
133 }
134
135 if !in_trait && !in_block && no_vis_qualifiers {
139 add_keyword("pub(crate)", "pub(crate) $0");
140 add_keyword("pub(super)", "pub(super) $0");
141 add_keyword("pub", "pub $0");
142 }
143
144 if in_item_list {
146 add_keyword("enum", "enum $1 {\n $0\n}");
147 add_keyword("mod", "mod $0");
148 add_keyword("static", "static $0");
149 add_keyword("struct", "struct $0");
150 add_keyword("trait", "trait $1 {\n $0\n}");
151 add_keyword("union", "union $1 {\n $0\n}");
152 add_keyword("use", "use $0;");
153 if no_vis_qualifiers {
154 add_keyword("impl", "impl $1 {\n $0\n}");
155 add_keyword("impl for", "impl $1 for $2 {\n $0\n}");
156 }
157 }
158
159 if in_extern_block {
160 add_keyword("unsafe", "unsafe $0");
161 if in_unsafe_extern_block {
162 add_keyword("safe", "safe $0");
163 }
164
165 add_keyword("fn", "fn $1($2);");
166 add_keyword("static", "static $1: $2;");
167 } else {
168 if !in_inherent_impl {
169 if !in_trait && no_abi_qualifiers {
170 add_keyword("extern", "extern $0");
171 }
172 add_keyword("type", "type $0");
173 }
174 if has_extern_kw {
175 add_keyword("crate", "crate $0;");
176 }
177
178 add_keyword("fn", "fn $1($2) {\n $0\n}");
179 add_keyword("unsafe", "unsafe $0");
180 add_keyword("const", "const $0");
181 add_keyword("async", "async $0");
182 }
183}