diff options
author | Aleksey Kladov <[email protected]> | 2019-11-27 18:32:33 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-11-27 18:35:06 +0000 |
commit | 757e593b253b4df7e6fc8bf15a4d4f34c9d484c5 (patch) | |
tree | d972d3a7e6457efdb5e0c558a8350db1818d07ae /crates/ra_ide_api/src/completion/completion_item.rs | |
parent | d9a36a736bfb91578a36505e7237212959bb55fe (diff) |
rename ra_ide_api -> ra_ide
Diffstat (limited to 'crates/ra_ide_api/src/completion/completion_item.rs')
-rw-r--r-- | crates/ra_ide_api/src/completion/completion_item.rs | 322 |
1 files changed, 0 insertions, 322 deletions
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs deleted file mode 100644 index 93f336370..000000000 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ /dev/null | |||
@@ -1,322 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::fmt; | ||
4 | |||
5 | use hir::Documentation; | ||
6 | use ra_syntax::TextRange; | ||
7 | use ra_text_edit::TextEdit; | ||
8 | |||
9 | /// `CompletionItem` describes a single completion variant in the editor pop-up. | ||
10 | /// It is basically a POD with various properties. To construct a | ||
11 | /// `CompletionItem`, use `new` method and the `Builder` struct. | ||
12 | pub struct CompletionItem { | ||
13 | /// Used only internally in tests, to check only specific kind of | ||
14 | /// completion (postfix, keyword, reference, etc). | ||
15 | #[allow(unused)] | ||
16 | completion_kind: CompletionKind, | ||
17 | /// Label in the completion pop up which identifies completion. | ||
18 | label: String, | ||
19 | /// Range of identifier that is being completed. | ||
20 | /// | ||
21 | /// It should be used primarily for UI, but we also use this to convert | ||
22 | /// genetic TextEdit into LSP's completion edit (see conv.rs). | ||
23 | /// | ||
24 | /// `source_range` must contain the completion offset. `insert_text` should | ||
25 | /// start with what `source_range` points to, or VSCode will filter out the | ||
26 | /// completion silently. | ||
27 | source_range: TextRange, | ||
28 | /// What happens when user selects this item. | ||
29 | /// | ||
30 | /// Typically, replaces `source_range` with new identifier. | ||
31 | text_edit: TextEdit, | ||
32 | insert_text_format: InsertTextFormat, | ||
33 | |||
34 | /// What item (struct, function, etc) are we completing. | ||
35 | kind: Option<CompletionItemKind>, | ||
36 | |||
37 | /// Lookup is used to check if completion item indeed can complete current | ||
38 | /// ident. | ||
39 | /// | ||
40 | /// That is, in `foo.bar<|>` lookup of `abracadabra` will be accepted (it | ||
41 | /// contains `bar` sub sequence), and `quux` will rejected. | ||
42 | lookup: Option<String>, | ||
43 | |||
44 | /// Additional info to show in the UI pop up. | ||
45 | detail: Option<String>, | ||
46 | documentation: Option<Documentation>, | ||
47 | |||
48 | /// Whether this item is marked as deprecated | ||
49 | deprecated: bool, | ||
50 | } | ||
51 | |||
52 | // We use custom debug for CompletionItem to make `insta`'s diffs more readable. | ||
53 | impl fmt::Debug for CompletionItem { | ||
54 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
55 | let mut s = f.debug_struct("CompletionItem"); | ||
56 | s.field("label", &self.label()).field("source_range", &self.source_range()); | ||
57 | if self.text_edit().as_atoms().len() == 1 { | ||
58 | let atom = &self.text_edit().as_atoms()[0]; | ||
59 | s.field("delete", &atom.delete); | ||
60 | s.field("insert", &atom.insert); | ||
61 | } else { | ||
62 | s.field("text_edit", &self.text_edit); | ||
63 | } | ||
64 | if let Some(kind) = self.kind().as_ref() { | ||
65 | s.field("kind", kind); | ||
66 | } | ||
67 | if self.lookup() != self.label() { | ||
68 | s.field("lookup", &self.lookup()); | ||
69 | } | ||
70 | if let Some(detail) = self.detail() { | ||
71 | s.field("detail", &detail); | ||
72 | } | ||
73 | if let Some(documentation) = self.documentation() { | ||
74 | s.field("documentation", &documentation); | ||
75 | } | ||
76 | if self.deprecated { | ||
77 | s.field("deprecated", &true); | ||
78 | } | ||
79 | s.finish() | ||
80 | } | ||
81 | } | ||
82 | |||
83 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
84 | pub enum CompletionItemKind { | ||
85 | Snippet, | ||
86 | Keyword, | ||
87 | Module, | ||
88 | Function, | ||
89 | BuiltinType, | ||
90 | Struct, | ||
91 | Enum, | ||
92 | EnumVariant, | ||
93 | Binding, | ||
94 | Field, | ||
95 | Static, | ||
96 | Const, | ||
97 | Trait, | ||
98 | TypeAlias, | ||
99 | Method, | ||
100 | TypeParam, | ||
101 | Macro, | ||
102 | } | ||
103 | |||
104 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | ||
105 | pub(crate) enum CompletionKind { | ||
106 | /// Parser-based keyword completion. | ||
107 | Keyword, | ||
108 | /// Your usual "complete all valid identifiers". | ||
109 | Reference, | ||
110 | /// "Secret sauce" completions. | ||
111 | Magic, | ||
112 | Snippet, | ||
113 | Postfix, | ||
114 | BuiltinType, | ||
115 | } | ||
116 | |||
117 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | ||
118 | pub enum InsertTextFormat { | ||
119 | PlainText, | ||
120 | Snippet, | ||
121 | } | ||
122 | |||
123 | impl CompletionItem { | ||
124 | pub(crate) fn new( | ||
125 | completion_kind: CompletionKind, | ||
126 | source_range: TextRange, | ||
127 | label: impl Into<String>, | ||
128 | ) -> Builder { | ||
129 | let label = label.into(); | ||
130 | Builder { | ||
131 | source_range, | ||
132 | completion_kind, | ||
133 | label, | ||
134 | insert_text: None, | ||
135 | insert_text_format: InsertTextFormat::PlainText, | ||
136 | detail: None, | ||
137 | documentation: None, | ||
138 | lookup: None, | ||
139 | kind: None, | ||
140 | text_edit: None, | ||
141 | deprecated: None, | ||
142 | } | ||
143 | } | ||
144 | /// What user sees in pop-up in the UI. | ||
145 | pub fn label(&self) -> &str { | ||
146 | &self.label | ||
147 | } | ||
148 | pub fn source_range(&self) -> TextRange { | ||
149 | self.source_range | ||
150 | } | ||
151 | |||
152 | pub fn insert_text_format(&self) -> InsertTextFormat { | ||
153 | self.insert_text_format | ||
154 | } | ||
155 | |||
156 | pub fn text_edit(&self) -> &TextEdit { | ||
157 | &self.text_edit | ||
158 | } | ||
159 | |||
160 | /// Short one-line additional information, like a type | ||
161 | pub fn detail(&self) -> Option<&str> { | ||
162 | self.detail.as_ref().map(|it| it.as_str()) | ||
163 | } | ||
164 | /// A doc-comment | ||
165 | pub fn documentation(&self) -> Option<Documentation> { | ||
166 | self.documentation.clone() | ||
167 | } | ||
168 | /// What string is used for filtering. | ||
169 | pub fn lookup(&self) -> &str { | ||
170 | self.lookup.as_ref().map(|it| it.as_str()).unwrap_or_else(|| self.label()) | ||
171 | } | ||
172 | |||
173 | pub fn kind(&self) -> Option<CompletionItemKind> { | ||
174 | self.kind | ||
175 | } | ||
176 | |||
177 | pub fn deprecated(&self) -> bool { | ||
178 | self.deprecated | ||
179 | } | ||
180 | } | ||
181 | |||
182 | /// A helper to make `CompletionItem`s. | ||
183 | #[must_use] | ||
184 | pub(crate) struct Builder { | ||
185 | source_range: TextRange, | ||
186 | completion_kind: CompletionKind, | ||
187 | label: String, | ||
188 | insert_text: Option<String>, | ||
189 | insert_text_format: InsertTextFormat, | ||
190 | detail: Option<String>, | ||
191 | documentation: Option<Documentation>, | ||
192 | lookup: Option<String>, | ||
193 | kind: Option<CompletionItemKind>, | ||
194 | text_edit: Option<TextEdit>, | ||
195 | deprecated: Option<bool>, | ||
196 | } | ||
197 | |||
198 | impl Builder { | ||
199 | pub(crate) fn add_to(self, acc: &mut Completions) { | ||
200 | acc.add(self.build()) | ||
201 | } | ||
202 | |||
203 | pub(crate) fn build(self) -> CompletionItem { | ||
204 | let label = self.label; | ||
205 | let text_edit = match self.text_edit { | ||
206 | Some(it) => it, | ||
207 | None => TextEdit::replace( | ||
208 | self.source_range, | ||
209 | self.insert_text.unwrap_or_else(|| label.clone()), | ||
210 | ), | ||
211 | }; | ||
212 | |||
213 | CompletionItem { | ||
214 | source_range: self.source_range, | ||
215 | label, | ||
216 | insert_text_format: self.insert_text_format, | ||
217 | text_edit, | ||
218 | detail: self.detail, | ||
219 | documentation: self.documentation, | ||
220 | lookup: self.lookup, | ||
221 | kind: self.kind, | ||
222 | completion_kind: self.completion_kind, | ||
223 | deprecated: self.deprecated.unwrap_or(false), | ||
224 | } | ||
225 | } | ||
226 | pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder { | ||
227 | self.lookup = Some(lookup.into()); | ||
228 | self | ||
229 | } | ||
230 | pub(crate) fn label(mut self, label: impl Into<String>) -> Builder { | ||
231 | self.label = label.into(); | ||
232 | self | ||
233 | } | ||
234 | pub(crate) fn insert_text(mut self, insert_text: impl Into<String>) -> Builder { | ||
235 | self.insert_text = Some(insert_text.into()); | ||
236 | self | ||
237 | } | ||
238 | pub(crate) fn insert_snippet(mut self, snippet: impl Into<String>) -> Builder { | ||
239 | self.insert_text_format = InsertTextFormat::Snippet; | ||
240 | self.insert_text(snippet) | ||
241 | } | ||
242 | pub(crate) fn kind(mut self, kind: CompletionItemKind) -> Builder { | ||
243 | self.kind = Some(kind); | ||
244 | self | ||
245 | } | ||
246 | pub(crate) fn text_edit(mut self, edit: TextEdit) -> Builder { | ||
247 | self.text_edit = Some(edit); | ||
248 | self | ||
249 | } | ||
250 | pub(crate) fn snippet_edit(mut self, edit: TextEdit) -> Builder { | ||
251 | self.insert_text_format = InsertTextFormat::Snippet; | ||
252 | self.text_edit(edit) | ||
253 | } | ||
254 | #[allow(unused)] | ||
255 | pub(crate) fn detail(self, detail: impl Into<String>) -> Builder { | ||
256 | self.set_detail(Some(detail)) | ||
257 | } | ||
258 | pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder { | ||
259 | self.detail = detail.map(Into::into); | ||
260 | self | ||
261 | } | ||
262 | #[allow(unused)] | ||
263 | pub(crate) fn documentation(self, docs: Documentation) -> Builder { | ||
264 | self.set_documentation(Some(docs)) | ||
265 | } | ||
266 | pub(crate) fn set_documentation(mut self, docs: Option<Documentation>) -> Builder { | ||
267 | self.documentation = docs.map(Into::into); | ||
268 | self | ||
269 | } | ||
270 | pub(crate) fn set_deprecated(mut self, deprecated: bool) -> Builder { | ||
271 | self.deprecated = Some(deprecated); | ||
272 | self | ||
273 | } | ||
274 | } | ||
275 | |||
276 | impl<'a> Into<CompletionItem> for Builder { | ||
277 | fn into(self) -> CompletionItem { | ||
278 | self.build() | ||
279 | } | ||
280 | } | ||
281 | |||
282 | /// Represents an in-progress set of completions being built. | ||
283 | #[derive(Debug, Default)] | ||
284 | pub(crate) struct Completions { | ||
285 | buf: Vec<CompletionItem>, | ||
286 | } | ||
287 | |||
288 | impl Completions { | ||
289 | pub(crate) fn add(&mut self, item: impl Into<CompletionItem>) { | ||
290 | self.buf.push(item.into()) | ||
291 | } | ||
292 | pub(crate) fn add_all<I>(&mut self, items: I) | ||
293 | where | ||
294 | I: IntoIterator, | ||
295 | I::Item: Into<CompletionItem>, | ||
296 | { | ||
297 | items.into_iter().for_each(|item| self.add(item.into())) | ||
298 | } | ||
299 | } | ||
300 | |||
301 | impl Into<Vec<CompletionItem>> for Completions { | ||
302 | fn into(self) -> Vec<CompletionItem> { | ||
303 | self.buf | ||
304 | } | ||
305 | } | ||
306 | |||
307 | #[cfg(test)] | ||
308 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { | ||
309 | use crate::completion::completions; | ||
310 | use crate::mock_analysis::{analysis_and_position, single_file_with_position}; | ||
311 | let (analysis, position) = if code.contains("//-") { | ||
312 | analysis_and_position(code) | ||
313 | } else { | ||
314 | single_file_with_position(code) | ||
315 | }; | ||
316 | let completions = completions(&analysis.db, position).unwrap(); | ||
317 | let completion_items: Vec<CompletionItem> = completions.into(); | ||
318 | let mut kind_completions: Vec<CompletionItem> = | ||
319 | completion_items.into_iter().filter(|c| c.completion_kind == kind).collect(); | ||
320 | kind_completions.sort_by_key(|c| c.label.clone()); | ||
321 | kind_completions | ||
322 | } | ||