diff options
Diffstat (limited to 'crates/ide_completion/src/completions.rs')
-rw-r--r-- | crates/ide_completion/src/completions.rs | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs new file mode 100644 index 000000000..3b582ed07 --- /dev/null +++ b/crates/ide_completion/src/completions.rs | |||
@@ -0,0 +1,224 @@ | |||
1 | //! This module defines an accumulator for completions which are going to be presented to user. | ||
2 | |||
3 | pub(crate) mod attribute; | ||
4 | pub(crate) mod dot; | ||
5 | pub(crate) mod record; | ||
6 | pub(crate) mod pattern; | ||
7 | pub(crate) mod fn_param; | ||
8 | pub(crate) mod keyword; | ||
9 | pub(crate) mod snippet; | ||
10 | pub(crate) mod qualified_path; | ||
11 | pub(crate) mod unqualified_path; | ||
12 | pub(crate) mod postfix; | ||
13 | pub(crate) mod macro_in_item_position; | ||
14 | pub(crate) mod trait_impl; | ||
15 | pub(crate) mod mod_; | ||
16 | pub(crate) mod flyimport; | ||
17 | |||
18 | use std::iter; | ||
19 | |||
20 | use hir::{known, ModPath, ScopeDef, Type}; | ||
21 | |||
22 | use crate::{ | ||
23 | item::Builder, | ||
24 | render::{ | ||
25 | const_::render_const, | ||
26 | enum_variant::render_variant, | ||
27 | function::render_fn, | ||
28 | macro_::render_macro, | ||
29 | pattern::{render_struct_pat, render_variant_pat}, | ||
30 | render_field, render_resolution, render_tuple_field, | ||
31 | type_alias::render_type_alias, | ||
32 | RenderContext, | ||
33 | }, | ||
34 | CompletionContext, CompletionItem, | ||
35 | }; | ||
36 | |||
37 | /// Represents an in-progress set of completions being built. | ||
38 | #[derive(Debug, Default)] | ||
39 | pub struct Completions { | ||
40 | buf: Vec<CompletionItem>, | ||
41 | } | ||
42 | |||
43 | impl Into<Vec<CompletionItem>> for Completions { | ||
44 | fn into(self) -> Vec<CompletionItem> { | ||
45 | self.buf | ||
46 | } | ||
47 | } | ||
48 | |||
49 | impl Builder { | ||
50 | /// Convenience method, which allows to add a freshly created completion into accumulator | ||
51 | /// without binding it to the variable. | ||
52 | pub(crate) fn add_to(self, acc: &mut Completions) { | ||
53 | acc.add(self.build()) | ||
54 | } | ||
55 | } | ||
56 | |||
57 | impl Completions { | ||
58 | pub(crate) fn add(&mut self, item: CompletionItem) { | ||
59 | self.buf.push(item.into()) | ||
60 | } | ||
61 | |||
62 | pub(crate) fn add_all<I>(&mut self, items: I) | ||
63 | where | ||
64 | I: IntoIterator, | ||
65 | I::Item: Into<CompletionItem>, | ||
66 | { | ||
67 | items.into_iter().for_each(|item| self.add(item.into())) | ||
68 | } | ||
69 | |||
70 | pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) { | ||
71 | let item = render_field(RenderContext::new(ctx), field, ty); | ||
72 | self.add(item); | ||
73 | } | ||
74 | |||
75 | pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) { | ||
76 | let item = render_tuple_field(RenderContext::new(ctx), field, ty); | ||
77 | self.add(item); | ||
78 | } | ||
79 | |||
80 | pub(crate) fn add_resolution( | ||
81 | &mut self, | ||
82 | ctx: &CompletionContext, | ||
83 | local_name: String, | ||
84 | resolution: &ScopeDef, | ||
85 | ) { | ||
86 | if let Some(item) = render_resolution(RenderContext::new(ctx), local_name, resolution) { | ||
87 | self.add(item); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | pub(crate) fn add_macro( | ||
92 | &mut self, | ||
93 | ctx: &CompletionContext, | ||
94 | name: Option<String>, | ||
95 | macro_: hir::MacroDef, | ||
96 | ) { | ||
97 | let name = match name { | ||
98 | Some(it) => it, | ||
99 | None => return, | ||
100 | }; | ||
101 | if let Some(item) = render_macro(RenderContext::new(ctx), None, name, macro_) { | ||
102 | self.add(item); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | pub(crate) fn add_function( | ||
107 | &mut self, | ||
108 | ctx: &CompletionContext, | ||
109 | func: hir::Function, | ||
110 | local_name: Option<String>, | ||
111 | ) { | ||
112 | if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) { | ||
113 | self.add(item) | ||
114 | } | ||
115 | } | ||
116 | |||
117 | pub(crate) fn add_variant_pat( | ||
118 | &mut self, | ||
119 | ctx: &CompletionContext, | ||
120 | variant: hir::Variant, | ||
121 | local_name: Option<hir::Name>, | ||
122 | ) { | ||
123 | if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, local_name, None) { | ||
124 | self.add(item); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | pub(crate) fn add_qualified_variant_pat( | ||
129 | &mut self, | ||
130 | ctx: &CompletionContext, | ||
131 | variant: hir::Variant, | ||
132 | path: ModPath, | ||
133 | ) { | ||
134 | if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)) { | ||
135 | self.add(item); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | pub(crate) fn add_struct_pat( | ||
140 | &mut self, | ||
141 | ctx: &CompletionContext, | ||
142 | strukt: hir::Struct, | ||
143 | local_name: Option<hir::Name>, | ||
144 | ) { | ||
145 | if let Some(item) = render_struct_pat(RenderContext::new(ctx), strukt, local_name) { | ||
146 | self.add(item); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { | ||
151 | if let Some(item) = render_const(RenderContext::new(ctx), constant) { | ||
152 | self.add(item); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { | ||
157 | if let Some(item) = render_type_alias(RenderContext::new(ctx), type_alias) { | ||
158 | self.add(item) | ||
159 | } | ||
160 | } | ||
161 | |||
162 | pub(crate) fn add_qualified_enum_variant( | ||
163 | &mut self, | ||
164 | ctx: &CompletionContext, | ||
165 | variant: hir::Variant, | ||
166 | path: ModPath, | ||
167 | ) { | ||
168 | let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path)); | ||
169 | self.add(item); | ||
170 | } | ||
171 | |||
172 | pub(crate) fn add_enum_variant( | ||
173 | &mut self, | ||
174 | ctx: &CompletionContext, | ||
175 | variant: hir::Variant, | ||
176 | local_name: Option<String>, | ||
177 | ) { | ||
178 | let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); | ||
179 | self.add(item); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | fn complete_enum_variants( | ||
184 | acc: &mut Completions, | ||
185 | ctx: &CompletionContext, | ||
186 | ty: &hir::Type, | ||
187 | cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath), | ||
188 | ) { | ||
189 | if let Some(hir::Adt::Enum(enum_data)) = | ||
190 | iter::successors(Some(ty.clone()), |ty| ty.remove_ref()).last().and_then(|ty| ty.as_adt()) | ||
191 | { | ||
192 | let variants = enum_data.variants(ctx.db); | ||
193 | |||
194 | let module = if let Some(module) = ctx.scope.module() { | ||
195 | // Compute path from the completion site if available. | ||
196 | module | ||
197 | } else { | ||
198 | // Otherwise fall back to the enum's definition site. | ||
199 | enum_data.module(ctx.db) | ||
200 | }; | ||
201 | |||
202 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { | ||
203 | if impl_.target_ty(ctx.db) == *ty { | ||
204 | for &variant in &variants { | ||
205 | let self_path = hir::ModPath::from_segments( | ||
206 | hir::PathKind::Plain, | ||
207 | iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))), | ||
208 | ); | ||
209 | cb(acc, ctx, variant, self_path); | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | |||
214 | for variant in variants { | ||
215 | if let Some(path) = module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) { | ||
216 | // Variants with trivial paths are already added by the existing completion logic, | ||
217 | // so we should avoid adding these twice | ||
218 | if path.segments().len() > 1 { | ||
219 | cb(acc, ctx, variant, path); | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | } | ||