aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_ide/src/call_info.rs30
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs231
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs7
-rw-r--r--crates/ra_ide/src/completion/completion_item.rs27
-rw-r--r--crates/ra_ide/src/completion/presentation.rs314
-rw-r--r--crates/ra_ide/src/lib.rs15
-rw-r--r--crates/ra_ide/src/marks.rs2
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs8
-rw-r--r--crates/rust-analyzer/src/conv.rs21
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs7
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
22pub(crate) fn call_info_for_token( 22#[derive(Debug)]
23 sema: &Semantics<RootDatabase>, 23pub(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
29impl 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
39fn 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
162impl CallInfo { 176impl 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};
12use ra_text_edit::AtomTextEdit; 12use ra_text_edit::AtomTextEdit;
13 13
14use crate::{completion::CompletionConfig, FilePosition}; 14use 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)]
97pub 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)]
97pub enum CompletionItemKind { 105pub 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)]
323pub 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)]
332pub(crate) struct Completions { 327pub(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;
6use test_utils::tested_by; 6use test_utils::tested_by;
7 7
8use crate::{ 8use 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
308pub(crate) fn compute_score(completion_item: &mut CompletionItem, ctx: &CompletionContext) { 307pub(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
344enum Params { 343enum 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
132impl 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)]
149pub struct AnalysisHost { 134pub 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};
20use rustc_hash::FxHashMap; 20use rustc_hash::FxHashMap;
21 21
22use crate::{call_info::call_info_for_token, Analysis, FileId}; 22use crate::{call_info::ActiveParameter, Analysis, FileId};
23 23
24pub(crate) use html::highlight_as_html; 24pub(crate) use html::highlight_as_html;
25pub use tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag}; 25pub 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};
11use ra_ide::{ 11use 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};
17use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 17use ra_syntax::{SyntaxKind, TextRange, TextUnit};
18use ra_text_edit::{AtomTextEdit, TextEdit}; 18use ra_text_edit::{AtomTextEdit, TextEdit};
@@ -114,10 +114,10 @@ impl Conv for Severity {
114 } 114 }
115} 115}
116 116
117impl ConvWith<(&LineIndex, LineEndings, &mut usize)> for CompletionItem { 117impl 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}