diff options
-rw-r--r-- | crates/ra_ide/src/call_info.rs | 30 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_dot.rs | 231 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_context.rs | 7 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_item.rs | 27 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 314 | ||||
-rw-r--r-- | crates/ra_ide/src/lib.rs | 15 | ||||
-rw-r--r-- | crates/ra_ide/src/marks.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting.rs | 8 | ||||
-rw-r--r-- | crates/rust-analyzer/src/conv.rs | 21 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 7 |
10 files changed, 329 insertions, 333 deletions
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs index f95b6baf3..5da254a6e 100644 --- a/crates/ra_ide/src/call_info.rs +++ b/crates/ra_ide/src/call_info.rs | |||
@@ -19,10 +19,24 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal | |||
19 | call_info_for_token(&sema, token) | 19 | call_info_for_token(&sema, token) |
20 | } | 20 | } |
21 | 21 | ||
22 | pub(crate) fn call_info_for_token( | 22 | #[derive(Debug)] |
23 | sema: &Semantics<RootDatabase>, | 23 | pub(crate) struct ActiveParameter { |
24 | token: SyntaxToken, | 24 | /// FIXME: should be `Type` and `Name |
25 | ) -> Option<CallInfo> { | 25 | pub(crate) ty: String, |
26 | pub(crate) name: String, | ||
27 | } | ||
28 | |||
29 | impl ActiveParameter { | ||
30 | pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { | ||
31 | call_info(db, position)?.into_active_parameter() | ||
32 | } | ||
33 | |||
34 | pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { | ||
35 | call_info_for_token(sema, token)?.into_active_parameter() | ||
36 | } | ||
37 | } | ||
38 | |||
39 | fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<CallInfo> { | ||
26 | // Find the calling expression and it's NameRef | 40 | // Find the calling expression and it's NameRef |
27 | let calling_node = FnCallNode::with_node(&token.parent())?; | 41 | let calling_node = FnCallNode::with_node(&token.parent())?; |
28 | 42 | ||
@@ -160,6 +174,14 @@ impl FnCallNode { | |||
160 | } | 174 | } |
161 | 175 | ||
162 | impl CallInfo { | 176 | impl CallInfo { |
177 | fn into_active_parameter(self) -> Option<ActiveParameter> { | ||
178 | let idx = self.active_parameter?; | ||
179 | let ty = self.signature.parameter_types.get(idx)?.clone(); | ||
180 | let name = self.signature.parameter_names.get(idx)?.clone(); | ||
181 | let res = ActiveParameter { ty, name }; | ||
182 | Some(res) | ||
183 | } | ||
184 | |||
163 | fn with_fn(db: &RootDatabase, function: hir::Function) -> Self { | 185 | fn with_fn(db: &RootDatabase, function: hir::Function) -> Self { |
164 | let signature = FunctionSignature::from_hir(db, function); | 186 | let signature = FunctionSignature::from_hir(db, function); |
165 | 187 | ||
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 44288f92e..b93153b48 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs | |||
@@ -106,237 +106,6 @@ mod tests { | |||
106 | } | 106 | } |
107 | 107 | ||
108 | #[test] | 108 | #[test] |
109 | fn test_struct_field_completion_in_func_call() { | ||
110 | assert_debug_snapshot!( | ||
111 | do_ref_completion( | ||
112 | r" | ||
113 | struct A { another_field: i64, the_field: u32, my_string: String } | ||
114 | fn test(my_param: u32) -> u32 { my_param } | ||
115 | fn foo(a: A) { | ||
116 | test(a.<|>) | ||
117 | } | ||
118 | ", | ||
119 | ), | ||
120 | @r###" | ||
121 | [ | ||
122 | CompletionItem { | ||
123 | label: "another_field", | ||
124 | source_range: [201; 201), | ||
125 | delete: [201; 201), | ||
126 | insert: "another_field", | ||
127 | kind: Field, | ||
128 | detail: "i64", | ||
129 | }, | ||
130 | CompletionItem { | ||
131 | label: "my_string", | ||
132 | source_range: [201; 201), | ||
133 | delete: [201; 201), | ||
134 | insert: "my_string", | ||
135 | kind: Field, | ||
136 | detail: "{unknown}", | ||
137 | }, | ||
138 | CompletionItem { | ||
139 | label: "the_field", | ||
140 | source_range: [201; 201), | ||
141 | delete: [201; 201), | ||
142 | insert: "the_field", | ||
143 | kind: Field, | ||
144 | detail: "u32", | ||
145 | score: TypeMatch, | ||
146 | }, | ||
147 | ] | ||
148 | "### | ||
149 | ); | ||
150 | } | ||
151 | |||
152 | #[test] | ||
153 | fn test_struct_field_completion_in_func_call_with_type_and_name() { | ||
154 | assert_debug_snapshot!( | ||
155 | do_ref_completion( | ||
156 | r" | ||
157 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | ||
158 | fn test(the_field: u32) -> u32 { the_field } | ||
159 | fn foo(a: A) { | ||
160 | test(a.<|>) | ||
161 | } | ||
162 | ", | ||
163 | ), | ||
164 | @r###" | ||
165 | [ | ||
166 | CompletionItem { | ||
167 | label: "another_field", | ||
168 | source_range: [208; 208), | ||
169 | delete: [208; 208), | ||
170 | insert: "another_field", | ||
171 | kind: Field, | ||
172 | detail: "i64", | ||
173 | }, | ||
174 | CompletionItem { | ||
175 | label: "another_good_type", | ||
176 | source_range: [208; 208), | ||
177 | delete: [208; 208), | ||
178 | insert: "another_good_type", | ||
179 | kind: Field, | ||
180 | detail: "u32", | ||
181 | score: TypeMatch, | ||
182 | }, | ||
183 | CompletionItem { | ||
184 | label: "the_field", | ||
185 | source_range: [208; 208), | ||
186 | delete: [208; 208), | ||
187 | insert: "the_field", | ||
188 | kind: Field, | ||
189 | detail: "u32", | ||
190 | score: TypeAndNameMatch, | ||
191 | }, | ||
192 | ] | ||
193 | "### | ||
194 | ); | ||
195 | } | ||
196 | |||
197 | #[test] | ||
198 | fn test_struct_field_completion_in_record_lit() { | ||
199 | assert_debug_snapshot!( | ||
200 | do_ref_completion( | ||
201 | r" | ||
202 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | ||
203 | struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } | ||
204 | fn foo(a: A) { | ||
205 | let b = B { | ||
206 | the_field: a.<|> | ||
207 | }; | ||
208 | } | ||
209 | ", | ||
210 | ), | ||
211 | @r###" | ||
212 | [ | ||
213 | CompletionItem { | ||
214 | label: "another_field", | ||
215 | source_range: [270; 270), | ||
216 | delete: [270; 270), | ||
217 | insert: "another_field", | ||
218 | kind: Field, | ||
219 | detail: "i64", | ||
220 | }, | ||
221 | CompletionItem { | ||
222 | label: "another_good_type", | ||
223 | source_range: [270; 270), | ||
224 | delete: [270; 270), | ||
225 | insert: "another_good_type", | ||
226 | kind: Field, | ||
227 | detail: "u32", | ||
228 | score: TypeMatch, | ||
229 | }, | ||
230 | CompletionItem { | ||
231 | label: "the_field", | ||
232 | source_range: [270; 270), | ||
233 | delete: [270; 270), | ||
234 | insert: "the_field", | ||
235 | kind: Field, | ||
236 | detail: "u32", | ||
237 | score: TypeAndNameMatch, | ||
238 | }, | ||
239 | ] | ||
240 | "### | ||
241 | ); | ||
242 | } | ||
243 | |||
244 | #[test] | ||
245 | fn test_struct_field_completion_in_record_lit_and_fn_call() { | ||
246 | assert_debug_snapshot!( | ||
247 | do_ref_completion( | ||
248 | r" | ||
249 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | ||
250 | struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } | ||
251 | fn test(the_field: i64) -> i64 { the_field } | ||
252 | fn foo(a: A) { | ||
253 | let b = B { | ||
254 | the_field: test(a.<|>) | ||
255 | }; | ||
256 | } | ||
257 | ", | ||
258 | ), | ||
259 | @r###" | ||
260 | [ | ||
261 | CompletionItem { | ||
262 | label: "another_field", | ||
263 | source_range: [336; 336), | ||
264 | delete: [336; 336), | ||
265 | insert: "another_field", | ||
266 | kind: Field, | ||
267 | detail: "i64", | ||
268 | score: TypeMatch, | ||
269 | }, | ||
270 | CompletionItem { | ||
271 | label: "another_good_type", | ||
272 | source_range: [336; 336), | ||
273 | delete: [336; 336), | ||
274 | insert: "another_good_type", | ||
275 | kind: Field, | ||
276 | detail: "u32", | ||
277 | }, | ||
278 | CompletionItem { | ||
279 | label: "the_field", | ||
280 | source_range: [336; 336), | ||
281 | delete: [336; 336), | ||
282 | insert: "the_field", | ||
283 | kind: Field, | ||
284 | detail: "u32", | ||
285 | }, | ||
286 | ] | ||
287 | "### | ||
288 | ); | ||
289 | } | ||
290 | |||
291 | #[test] | ||
292 | fn test_struct_field_completion_in_fn_call_and_record_lit() { | ||
293 | assert_debug_snapshot!( | ||
294 | do_ref_completion( | ||
295 | r" | ||
296 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | ||
297 | struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } | ||
298 | fn test(the_field: i64) -> i64 { the_field } | ||
299 | fn foo(a: A) { | ||
300 | test(B { | ||
301 | the_field: a.<|> | ||
302 | }); | ||
303 | } | ||
304 | ", | ||
305 | ), | ||
306 | @r###" | ||
307 | [ | ||
308 | CompletionItem { | ||
309 | label: "another_field", | ||
310 | source_range: [328; 328), | ||
311 | delete: [328; 328), | ||
312 | insert: "another_field", | ||
313 | kind: Field, | ||
314 | detail: "i64", | ||
315 | }, | ||
316 | CompletionItem { | ||
317 | label: "another_good_type", | ||
318 | source_range: [328; 328), | ||
319 | delete: [328; 328), | ||
320 | insert: "another_good_type", | ||
321 | kind: Field, | ||
322 | detail: "u32", | ||
323 | score: TypeMatch, | ||
324 | }, | ||
325 | CompletionItem { | ||
326 | label: "the_field", | ||
327 | source_range: [328; 328), | ||
328 | delete: [328; 328), | ||
329 | insert: "the_field", | ||
330 | kind: Field, | ||
331 | detail: "u32", | ||
332 | score: TypeAndNameMatch, | ||
333 | }, | ||
334 | ] | ||
335 | "### | ||
336 | ); | ||
337 | } | ||
338 | |||
339 | #[test] | ||
340 | fn test_struct_field_completion_self() { | 109 | fn test_struct_field_completion_self() { |
341 | assert_debug_snapshot!( | 110 | assert_debug_snapshot!( |
342 | do_ref_completion( | 111 | do_ref_completion( |
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index dd7c8a873..a76d1ce45 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | }; | 11 | }; |
12 | use ra_text_edit::AtomTextEdit; | 12 | use ra_text_edit::AtomTextEdit; |
13 | 13 | ||
14 | use crate::{completion::CompletionConfig, FilePosition}; | 14 | use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition}; |
15 | 15 | ||
16 | /// `CompletionContext` is created early during completion to figure out, where | 16 | /// `CompletionContext` is created early during completion to figure out, where |
17 | /// exactly is the cursor, syntax-wise. | 17 | /// exactly is the cursor, syntax-wise. |
@@ -21,7 +21,6 @@ pub(crate) struct CompletionContext<'a> { | |||
21 | pub(super) db: &'a RootDatabase, | 21 | pub(super) db: &'a RootDatabase, |
22 | pub(super) config: &'a CompletionConfig, | 22 | pub(super) config: &'a CompletionConfig, |
23 | pub(super) offset: TextUnit, | 23 | pub(super) offset: TextUnit, |
24 | pub(super) file_position: FilePosition, | ||
25 | /// The token before the cursor, in the original file. | 24 | /// The token before the cursor, in the original file. |
26 | pub(super) original_token: SyntaxToken, | 25 | pub(super) original_token: SyntaxToken, |
27 | /// The token before the cursor, in the macro-expanded file. | 26 | /// The token before the cursor, in the macro-expanded file. |
@@ -34,6 +33,8 @@ pub(crate) struct CompletionContext<'a> { | |||
34 | pub(super) record_pat_syntax: Option<ast::RecordPat>, | 33 | pub(super) record_pat_syntax: Option<ast::RecordPat>, |
35 | pub(super) record_field_syntax: Option<ast::RecordField>, | 34 | pub(super) record_field_syntax: Option<ast::RecordField>, |
36 | pub(super) impl_def: Option<ast::ImplDef>, | 35 | pub(super) impl_def: Option<ast::ImplDef>, |
36 | /// FIXME: `ActiveParameter` is string-based, which is very wrong | ||
37 | pub(super) active_parameter: Option<ActiveParameter>, | ||
37 | pub(super) is_param: bool, | 38 | pub(super) is_param: bool, |
38 | /// If a name-binding or reference to a const in a pattern. | 39 | /// If a name-binding or reference to a const in a pattern. |
39 | /// Irrefutable patterns (like let) are excluded. | 40 | /// Irrefutable patterns (like let) are excluded. |
@@ -90,7 +91,6 @@ impl<'a> CompletionContext<'a> { | |||
90 | original_token, | 91 | original_token, |
91 | token, | 92 | token, |
92 | offset: position.offset, | 93 | offset: position.offset, |
93 | file_position: position, | ||
94 | krate, | 94 | krate, |
95 | name_ref_syntax: None, | 95 | name_ref_syntax: None, |
96 | function_syntax: None, | 96 | function_syntax: None, |
@@ -99,6 +99,7 @@ impl<'a> CompletionContext<'a> { | |||
99 | record_pat_syntax: None, | 99 | record_pat_syntax: None, |
100 | record_field_syntax: None, | 100 | record_field_syntax: None, |
101 | impl_def: None, | 101 | impl_def: None, |
102 | active_parameter: ActiveParameter::at(db, position), | ||
102 | is_param: false, | 103 | is_param: false, |
103 | is_pat_binding_or_const: false, | 104 | is_pat_binding_or_const: false, |
104 | is_trivial_path: false, | 105 | is_trivial_path: false, |
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index e17586aa5..edbf4a5b7 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs | |||
@@ -52,7 +52,7 @@ pub struct CompletionItem { | |||
52 | /// after completion. | 52 | /// after completion. |
53 | trigger_call_info: bool, | 53 | trigger_call_info: bool, |
54 | 54 | ||
55 | /// Score is usefull to pre select or display in better order completion items | 55 | /// Score is useful to pre select or display in better order completion items |
56 | score: Option<CompletionScore>, | 56 | score: Option<CompletionScore>, |
57 | } | 57 | } |
58 | 58 | ||
@@ -93,6 +93,14 @@ impl fmt::Debug for CompletionItem { | |||
93 | } | 93 | } |
94 | } | 94 | } |
95 | 95 | ||
96 | #[derive(Debug, Clone, Copy)] | ||
97 | pub enum CompletionScore { | ||
98 | /// If only type match | ||
99 | TypeMatch, | ||
100 | /// If type and name match | ||
101 | TypeAndNameMatch, | ||
102 | } | ||
103 | |||
96 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 104 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
97 | pub enum CompletionItemKind { | 105 | pub enum CompletionItemKind { |
98 | Snippet, | 106 | Snippet, |
@@ -182,7 +190,7 @@ impl CompletionItem { | |||
182 | } | 190 | } |
183 | /// What string is used for filtering. | 191 | /// What string is used for filtering. |
184 | pub fn lookup(&self) -> &str { | 192 | pub fn lookup(&self) -> &str { |
185 | self.lookup.as_deref().unwrap_or_else(|| self.label()) | 193 | self.lookup.as_deref().unwrap_or(&self.label) |
186 | } | 194 | } |
187 | 195 | ||
188 | pub fn kind(&self) -> Option<CompletionItemKind> { | 196 | pub fn kind(&self) -> Option<CompletionItemKind> { |
@@ -194,11 +202,7 @@ impl CompletionItem { | |||
194 | } | 202 | } |
195 | 203 | ||
196 | pub fn score(&self) -> Option<CompletionScore> { | 204 | pub fn score(&self) -> Option<CompletionScore> { |
197 | self.score.clone() | 205 | self.score |
198 | } | ||
199 | |||
200 | pub fn set_score(&mut self, score: CompletionScore) { | ||
201 | self.score = Some(score); | ||
202 | } | 206 | } |
203 | 207 | ||
204 | pub fn trigger_call_info(&self) -> bool { | 208 | pub fn trigger_call_info(&self) -> bool { |
@@ -302,7 +306,6 @@ impl Builder { | |||
302 | self.deprecated = Some(deprecated); | 306 | self.deprecated = Some(deprecated); |
303 | self | 307 | self |
304 | } | 308 | } |
305 | #[allow(unused)] | ||
306 | pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder { | 309 | pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder { |
307 | self.score = Some(score); | 310 | self.score = Some(score); |
308 | self | 311 | self |
@@ -319,14 +322,6 @@ impl<'a> Into<CompletionItem> for Builder { | |||
319 | } | 322 | } |
320 | } | 323 | } |
321 | 324 | ||
322 | #[derive(Debug, Clone)] | ||
323 | pub enum CompletionScore { | ||
324 | /// If only type match | ||
325 | TypeMatch, | ||
326 | /// If type and name match | ||
327 | TypeAndNameMatch, | ||
328 | } | ||
329 | |||
330 | /// Represents an in-progress set of completions being built. | 325 | /// Represents an in-progress set of completions being built. |
331 | #[derive(Debug, Default)] | 326 | #[derive(Debug, Default)] |
332 | pub(crate) struct Completions { | 327 | pub(crate) struct Completions { |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index f8dac1d54..78df9cbdb 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -6,7 +6,6 @@ use stdx::SepBy; | |||
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
7 | 7 | ||
8 | use crate::{ | 8 | use crate::{ |
9 | call_info::call_info, | ||
10 | completion::{ | 9 | completion::{ |
11 | completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, | 10 | completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, |
12 | CompletionKind, Completions, | 11 | CompletionKind, Completions, |
@@ -23,20 +22,20 @@ impl Completions { | |||
23 | ty: &Type, | 22 | ty: &Type, |
24 | ) { | 23 | ) { |
25 | let is_deprecated = is_deprecated(field, ctx.db); | 24 | let is_deprecated = is_deprecated(field, ctx.db); |
26 | let mut completion_item = CompletionItem::new( | 25 | let ty = ty.display(ctx.db).to_string(); |
27 | CompletionKind::Reference, | 26 | let name = field.name(ctx.db); |
28 | ctx.source_range(), | 27 | let mut completion_item = |
29 | field.name(ctx.db).to_string(), | 28 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) |
30 | ) | 29 | .kind(CompletionItemKind::Field) |
31 | .kind(CompletionItemKind::Field) | 30 | .detail(ty.clone()) |
32 | .detail(ty.display(ctx.db).to_string()) | 31 | .set_documentation(field.docs(ctx.db)) |
33 | .set_documentation(field.docs(ctx.db)) | 32 | .set_deprecated(is_deprecated); |
34 | .set_deprecated(is_deprecated) | 33 | |
35 | .build(); | 34 | if let Some(score) = compute_score(ctx, &ty, &name.to_string()) { |
36 | 35 | completion_item = completion_item.set_score(score); | |
37 | compute_score(&mut completion_item, ctx); | 36 | } |
38 | 37 | ||
39 | self.add(completion_item); | 38 | completion_item.add_to(self); |
40 | } | 39 | } |
41 | 40 | ||
42 | pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) { | 41 | pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) { |
@@ -305,40 +304,40 @@ impl Completions { | |||
305 | } | 304 | } |
306 | } | 305 | } |
307 | 306 | ||
308 | pub(crate) fn compute_score(completion_item: &mut CompletionItem, ctx: &CompletionContext) { | 307 | pub(crate) fn compute_score( |
308 | ctx: &CompletionContext, | ||
309 | // FIXME: this definitely should be a `Type` | ||
310 | ty: &str, | ||
311 | name: &str, | ||
312 | ) -> Option<CompletionScore> { | ||
309 | let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { | 313 | let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { |
310 | if let Some((struct_field, _)) = ctx.sema.resolve_record_field(record_field) { | 314 | tested_by!(test_struct_field_completion_in_record_lit); |
311 | ( | 315 | let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; |
312 | struct_field.name(ctx.db).to_string(), | 316 | ( |
313 | struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), | 317 | struct_field.name(ctx.db).to_string(), |
314 | ) | 318 | struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), |
315 | } else { | 319 | ) |
316 | return; | 320 | } else if let Some(active_parameter) = &ctx.active_parameter { |
317 | } | 321 | tested_by!(test_struct_field_completion_in_func_call); |
318 | } else if let Some(call_info) = call_info(ctx.db, ctx.file_position) { | 322 | (active_parameter.name.clone(), active_parameter.ty.clone()) |
319 | if call_info.active_parameter_type().is_some() | ||
320 | && call_info.active_parameter_name().is_some() | ||
321 | { | ||
322 | (call_info.active_parameter_name().unwrap(), call_info.active_parameter_type().unwrap()) | ||
323 | } else { | ||
324 | return; | ||
325 | } | ||
326 | } else { | 323 | } else { |
327 | return; | 324 | return None; |
328 | }; | 325 | }; |
329 | 326 | ||
330 | // Compute score | 327 | // Compute score |
331 | // For the same type | 328 | // For the same type |
332 | if let Some(a_parameter_type) = completion_item.detail() { | 329 | if &active_type != ty { |
333 | if &active_type == a_parameter_type { | 330 | return None; |
334 | // If same type + same name then go top position | 331 | } |
335 | if active_name == completion_item.label() { | 332 | |
336 | completion_item.set_score(CompletionScore::TypeAndNameMatch); | 333 | let mut res = CompletionScore::TypeMatch; |
337 | } else { | 334 | |
338 | completion_item.set_score(CompletionScore::TypeMatch); | 335 | // If same type + same name then go top position |
339 | } | 336 | if active_name == name { |
340 | } | 337 | res = CompletionScore::TypeAndNameMatch |
341 | } | 338 | } |
339 | |||
340 | Some(res) | ||
342 | } | 341 | } |
343 | 342 | ||
344 | enum Params { | 343 | enum Params { |
@@ -1072,4 +1071,237 @@ mod tests { | |||
1072 | "### | 1071 | "### |
1073 | ); | 1072 | ); |
1074 | } | 1073 | } |
1074 | |||
1075 | #[test] | ||
1076 | fn test_struct_field_completion_in_func_call() { | ||
1077 | covers!(test_struct_field_completion_in_func_call); | ||
1078 | assert_debug_snapshot!( | ||
1079 | do_reference_completion( | ||
1080 | r" | ||
1081 | struct A { another_field: i64, the_field: u32, my_string: String } | ||
1082 | fn test(my_param: u32) -> u32 { my_param } | ||
1083 | fn foo(a: A) { | ||
1084 | test(a.<|>) | ||
1085 | } | ||
1086 | ", | ||
1087 | ), | ||
1088 | @r###" | ||
1089 | [ | ||
1090 | CompletionItem { | ||
1091 | label: "another_field", | ||
1092 | source_range: [201; 201), | ||
1093 | delete: [201; 201), | ||
1094 | insert: "another_field", | ||
1095 | kind: Field, | ||
1096 | detail: "i64", | ||
1097 | }, | ||
1098 | CompletionItem { | ||
1099 | label: "my_string", | ||
1100 | source_range: [201; 201), | ||
1101 | delete: [201; 201), | ||
1102 | insert: "my_string", | ||
1103 | kind: Field, | ||
1104 | detail: "{unknown}", | ||
1105 | }, | ||
1106 | CompletionItem { | ||
1107 | label: "the_field", | ||
1108 | source_range: [201; 201), | ||
1109 | delete: [201; 201), | ||
1110 | insert: "the_field", | ||
1111 | kind: Field, | ||
1112 | detail: "u32", | ||
1113 | score: TypeMatch, | ||
1114 | }, | ||
1115 | ] | ||
1116 | "### | ||
1117 | ); | ||
1118 | } | ||
1119 | |||
1120 | #[test] | ||
1121 | fn test_struct_field_completion_in_func_call_with_type_and_name() { | ||
1122 | assert_debug_snapshot!( | ||
1123 | do_reference_completion( | ||
1124 | r" | ||
1125 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | ||
1126 | fn test(the_field: u32) -> u32 { the_field } | ||
1127 | fn foo(a: A) { | ||
1128 | test(a.<|>) | ||
1129 | } | ||
1130 | ", | ||
1131 | ), | ||
1132 | @r###" | ||
1133 | [ | ||
1134 | CompletionItem { | ||
1135 | label: "another_field", | ||
1136 | source_range: [208; 208), | ||
1137 | delete: [208; 208), | ||
1138 | insert: "another_field", | ||
1139 | kind: Field, | ||
1140 | detail: "i64", | ||
1141 | }, | ||
1142 | CompletionItem { | ||
1143 | label: "another_good_type", | ||
1144 | source_range: [208; 208), | ||
1145 | delete: [208; 208), | ||
1146 | insert: "another_good_type", | ||
1147 | kind: Field, | ||
1148 | detail: "u32", | ||
1149 | score: TypeMatch, | ||
1150 | }, | ||
1151 | CompletionItem { | ||
1152 | label: "the_field", | ||
1153 | source_range: [208; 208), | ||
1154 | delete: [208; 208), | ||
1155 | insert: "the_field", | ||
1156 | kind: Field, | ||
1157 | detail: "u32", | ||
1158 | score: TypeAndNameMatch, | ||
1159 | }, | ||
1160 | ] | ||
1161 | "### | ||
1162 | ); | ||
1163 | } | ||
1164 | |||
1165 | #[test] | ||
1166 | fn test_struct_field_completion_in_record_lit() { | ||
1167 | covers!(test_struct_field_completion_in_func_call); | ||
1168 | assert_debug_snapshot!( | ||
1169 | do_reference_completion( | ||
1170 | r" | ||
1171 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | ||
1172 | struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } | ||
1173 | fn foo(a: A) { | ||
1174 | let b = B { | ||
1175 | the_field: a.<|> | ||
1176 | }; | ||
1177 | } | ||
1178 | ", | ||
1179 | ), | ||
1180 | @r###" | ||
1181 | [ | ||
1182 | CompletionItem { | ||
1183 | label: "another_field", | ||
1184 | source_range: [270; 270), | ||
1185 | delete: [270; 270), | ||
1186 | insert: "another_field", | ||
1187 | kind: Field, | ||
1188 | detail: "i64", | ||
1189 | }, | ||
1190 | CompletionItem { | ||
1191 | label: "another_good_type", | ||
1192 | source_range: [270; 270), | ||
1193 | delete: [270; 270), | ||
1194 | insert: "another_good_type", | ||
1195 | kind: Field, | ||
1196 | detail: "u32", | ||
1197 | score: TypeMatch, | ||
1198 | }, | ||
1199 | CompletionItem { | ||
1200 | label: "the_field", | ||
1201 | source_range: [270; 270), | ||
1202 | delete: [270; 270), | ||
1203 | insert: "the_field", | ||
1204 | kind: Field, | ||
1205 | detail: "u32", | ||
1206 | score: TypeAndNameMatch, | ||
1207 | }, | ||
1208 | ] | ||
1209 | "### | ||
1210 | ); | ||
1211 | } | ||
1212 | |||
1213 | #[test] | ||
1214 | fn test_struct_field_completion_in_record_lit_and_fn_call() { | ||
1215 | assert_debug_snapshot!( | ||
1216 | do_reference_completion( | ||
1217 | r" | ||
1218 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | ||
1219 | struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } | ||
1220 | fn test(the_field: i64) -> i64 { the_field } | ||
1221 | fn foo(a: A) { | ||
1222 | let b = B { | ||
1223 | the_field: test(a.<|>) | ||
1224 | }; | ||
1225 | } | ||
1226 | ", | ||
1227 | ), | ||
1228 | @r###" | ||
1229 | [ | ||
1230 | CompletionItem { | ||
1231 | label: "another_field", | ||
1232 | source_range: [336; 336), | ||
1233 | delete: [336; 336), | ||
1234 | insert: "another_field", | ||
1235 | kind: Field, | ||
1236 | detail: "i64", | ||
1237 | score: TypeMatch, | ||
1238 | }, | ||
1239 | CompletionItem { | ||
1240 | label: "another_good_type", | ||
1241 | source_range: [336; 336), | ||
1242 | delete: [336; 336), | ||
1243 | insert: "another_good_type", | ||
1244 | kind: Field, | ||
1245 | detail: "u32", | ||
1246 | }, | ||
1247 | CompletionItem { | ||
1248 | label: "the_field", | ||
1249 | source_range: [336; 336), | ||
1250 | delete: [336; 336), | ||
1251 | insert: "the_field", | ||
1252 | kind: Field, | ||
1253 | detail: "u32", | ||
1254 | }, | ||
1255 | ] | ||
1256 | "### | ||
1257 | ); | ||
1258 | } | ||
1259 | |||
1260 | #[test] | ||
1261 | fn test_struct_field_completion_in_fn_call_and_record_lit() { | ||
1262 | assert_debug_snapshot!( | ||
1263 | do_reference_completion( | ||
1264 | r" | ||
1265 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | ||
1266 | struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } | ||
1267 | fn test(the_field: i64) -> i64 { the_field } | ||
1268 | fn foo(a: A) { | ||
1269 | test(B { | ||
1270 | the_field: a.<|> | ||
1271 | }); | ||
1272 | } | ||
1273 | ", | ||
1274 | ), | ||
1275 | @r###" | ||
1276 | [ | ||
1277 | CompletionItem { | ||
1278 | label: "another_field", | ||
1279 | source_range: [328; 328), | ||
1280 | delete: [328; 328), | ||
1281 | insert: "another_field", | ||
1282 | kind: Field, | ||
1283 | detail: "i64", | ||
1284 | }, | ||
1285 | CompletionItem { | ||
1286 | label: "another_good_type", | ||
1287 | source_range: [328; 328), | ||
1288 | delete: [328; 328), | ||
1289 | insert: "another_good_type", | ||
1290 | kind: Field, | ||
1291 | detail: "u32", | ||
1292 | score: TypeMatch, | ||
1293 | }, | ||
1294 | CompletionItem { | ||
1295 | label: "the_field", | ||
1296 | source_range: [328; 328), | ||
1297 | delete: [328; 328), | ||
1298 | insert: "the_field", | ||
1299 | kind: Field, | ||
1300 | detail: "u32", | ||
1301 | score: TypeAndNameMatch, | ||
1302 | }, | ||
1303 | ] | ||
1304 | "### | ||
1305 | ); | ||
1306 | } | ||
1075 | } | 1307 | } |
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index ddaa30a16..f692fbaa2 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -129,21 +129,6 @@ pub struct CallInfo { | |||
129 | pub active_parameter: Option<usize>, | 129 | pub active_parameter: Option<usize>, |
130 | } | 130 | } |
131 | 131 | ||
132 | impl CallInfo { | ||
133 | pub fn active_parameter_type(&self) -> Option<String> { | ||
134 | if let Some(id) = self.active_parameter { | ||
135 | return self.signature.parameter_types.get(id).map(|param_ty| param_ty.clone()); | ||
136 | } | ||
137 | None | ||
138 | } | ||
139 | pub fn active_parameter_name(&self) -> Option<String> { | ||
140 | if let Some(id) = self.active_parameter { | ||
141 | return self.signature.parameter_names.get(id).map(|param_ty| param_ty.clone()); | ||
142 | } | ||
143 | None | ||
144 | } | ||
145 | } | ||
146 | |||
147 | /// `AnalysisHost` stores the current state of the world. | 132 | /// `AnalysisHost` stores the current state of the world. |
148 | #[derive(Debug)] | 133 | #[derive(Debug)] |
149 | pub struct AnalysisHost { | 134 | pub struct AnalysisHost { |
diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs index eee44e886..bea30fe2a 100644 --- a/crates/ra_ide/src/marks.rs +++ b/crates/ra_ide/src/marks.rs | |||
@@ -9,4 +9,6 @@ test_utils::marks!( | |||
9 | search_filters_by_range | 9 | search_filters_by_range |
10 | dont_insert_macro_call_parens_unncessary | 10 | dont_insert_macro_call_parens_unncessary |
11 | self_fulfilling_completion | 11 | self_fulfilling_completion |
12 | test_struct_field_completion_in_func_call | ||
13 | test_struct_field_completion_in_record_lit | ||
12 | ); | 14 | ); |
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 93d502875..d9912155b 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -19,7 +19,7 @@ use ra_syntax::{ | |||
19 | }; | 19 | }; |
20 | use rustc_hash::FxHashMap; | 20 | use rustc_hash::FxHashMap; |
21 | 21 | ||
22 | use crate::{call_info::call_info_for_token, Analysis, FileId}; | 22 | use crate::{call_info::ActiveParameter, Analysis, FileId}; |
23 | 23 | ||
24 | pub(crate) use html::highlight_as_html; | 24 | pub(crate) use html::highlight_as_html; |
25 | pub use tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag}; | 25 | pub use tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag}; |
@@ -364,10 +364,8 @@ fn highlight_injection( | |||
364 | literal: ast::RawString, | 364 | literal: ast::RawString, |
365 | expanded: SyntaxToken, | 365 | expanded: SyntaxToken, |
366 | ) -> Option<()> { | 366 | ) -> Option<()> { |
367 | let call_info = call_info_for_token(&sema, expanded)?; | 367 | let active_parameter = ActiveParameter::at_token(&sema, expanded)?; |
368 | let idx = call_info.active_parameter?; | 368 | if !active_parameter.name.starts_with("ra_fixture") { |
369 | let name = call_info.signature.parameter_names.get(idx)?; | ||
370 | if !name.starts_with("ra_fixture") { | ||
371 | return None; | 369 | return None; |
372 | } | 370 | } |
373 | let value = literal.value()?; | 371 | let value = literal.value()?; |
diff --git a/crates/rust-analyzer/src/conv.rs b/crates/rust-analyzer/src/conv.rs index 7e30956cc..098ee369c 100644 --- a/crates/rust-analyzer/src/conv.rs +++ b/crates/rust-analyzer/src/conv.rs | |||
@@ -9,10 +9,10 @@ use lsp_types::{ | |||
9 | TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, WorkspaceEdit, | 9 | TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, WorkspaceEdit, |
10 | }; | 10 | }; |
11 | use ra_ide::{ | 11 | use ra_ide::{ |
12 | translate_offset_with_edit, CompletionItem, CompletionItemKind, CompletionScore, FileId, | 12 | translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition, |
13 | FilePosition, FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, | 13 | FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, HighlightTag, |
14 | HighlightTag, InlayHint, InlayKind, InsertTextFormat, LineCol, LineIndex, NavigationTarget, | 14 | InlayHint, InlayKind, InsertTextFormat, LineCol, LineIndex, NavigationTarget, RangeInfo, |
15 | RangeInfo, ReferenceAccess, Severity, SourceChange, SourceFileEdit, | 15 | ReferenceAccess, Severity, SourceChange, SourceFileEdit, |
16 | }; | 16 | }; |
17 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; | 17 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; |
18 | use ra_text_edit::{AtomTextEdit, TextEdit}; | 18 | use ra_text_edit::{AtomTextEdit, TextEdit}; |
@@ -114,10 +114,10 @@ impl Conv for Severity { | |||
114 | } | 114 | } |
115 | } | 115 | } |
116 | 116 | ||
117 | impl ConvWith<(&LineIndex, LineEndings, &mut usize)> for CompletionItem { | 117 | impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem { |
118 | type Output = ::lsp_types::CompletionItem; | 118 | type Output = ::lsp_types::CompletionItem; |
119 | 119 | ||
120 | fn conv_with(self, ctx: (&LineIndex, LineEndings, &mut usize)) -> ::lsp_types::CompletionItem { | 120 | fn conv_with(self, ctx: (&LineIndex, LineEndings)) -> ::lsp_types::CompletionItem { |
121 | let mut additional_text_edits = Vec::new(); | 121 | let mut additional_text_edits = Vec::new(); |
122 | let mut text_edit = None; | 122 | let mut text_edit = None; |
123 | // LSP does not allow arbitrary edits in completion, so we have to do a | 123 | // LSP does not allow arbitrary edits in completion, so we have to do a |
@@ -165,13 +165,8 @@ impl ConvWith<(&LineIndex, LineEndings, &mut usize)> for CompletionItem { | |||
165 | ..Default::default() | 165 | ..Default::default() |
166 | }; | 166 | }; |
167 | 167 | ||
168 | if let Some(score) = self.score() { | 168 | if self.score().is_some() { |
169 | match score { | 169 | res.preselect = Some(true) |
170 | CompletionScore::TypeAndNameMatch => res.preselect = Some(true), | ||
171 | CompletionScore::TypeMatch => {} | ||
172 | } | ||
173 | res.sort_text = Some(format!("{:02}", *ctx.2)); | ||
174 | *ctx.2 += 1; | ||
175 | } | 170 | } |
176 | 171 | ||
177 | if self.deprecated() { | 172 | if self.deprecated() { |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index ee669f383..41d9fe344 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -423,11 +423,8 @@ pub fn handle_completion( | |||
423 | }; | 423 | }; |
424 | let line_index = world.analysis().file_line_index(position.file_id)?; | 424 | let line_index = world.analysis().file_line_index(position.file_id)?; |
425 | let line_endings = world.file_line_endings(position.file_id); | 425 | let line_endings = world.file_line_endings(position.file_id); |
426 | let mut count_sort_text_item = 0usize; | 426 | let items: Vec<CompletionItem> = |
427 | let items: Vec<CompletionItem> = items | 427 | items.into_iter().map(|item| item.conv_with((&line_index, line_endings))).collect(); |
428 | .into_iter() | ||
429 | .map(|item| item.conv_with((&line_index, line_endings, &mut count_sort_text_item))) | ||
430 | .collect(); | ||
431 | 428 | ||
432 | Ok(Some(items.into())) | 429 | Ok(Some(items.into())) |
433 | } | 430 | } |