diff options
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r-- | crates/ra_ide/src/completion/complete_keyword.rs | 12 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_postfix.rs | 39 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_snippet.rs | 26 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_trait_impl.rs | 18 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_config.rs | 29 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_item.rs | 9 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 47 |
7 files changed, 136 insertions, 44 deletions
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs index 38f9c34e7..adefb290e 100644 --- a/crates/ra_ide/src/completion/complete_keyword.rs +++ b/crates/ra_ide/src/completion/complete_keyword.rs | |||
@@ -42,10 +42,14 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC | |||
42 | } | 42 | } |
43 | 43 | ||
44 | fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem { | 44 | fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem { |
45 | CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw) | 45 | let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw) |
46 | .kind(CompletionItemKind::Keyword) | 46 | .kind(CompletionItemKind::Keyword); |
47 | .insert_snippet(snippet) | 47 | |
48 | .build() | 48 | match ctx.config.snippet_cap { |
49 | Some(cap) => res.insert_snippet(cap, snippet), | ||
50 | _ => res.insert_text(if snippet.contains('$') { kw } else { snippet }), | ||
51 | } | ||
52 | .build() | ||
49 | } | 53 | } |
50 | 54 | ||
51 | pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { | 55 | pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { |
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index 29c2881c6..8d397b0fe 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs | |||
@@ -6,6 +6,7 @@ use ra_syntax::{ | |||
6 | }; | 6 | }; |
7 | use ra_text_edit::TextEdit; | 7 | use ra_text_edit::TextEdit; |
8 | 8 | ||
9 | use super::completion_config::SnippetCap; | ||
9 | use crate::{ | 10 | use crate::{ |
10 | completion::{ | 11 | completion::{ |
11 | completion_context::CompletionContext, | 12 | completion_context::CompletionContext, |
@@ -32,9 +33,15 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
32 | None => return, | 33 | None => return, |
33 | }; | 34 | }; |
34 | 35 | ||
36 | let cap = match ctx.config.snippet_cap { | ||
37 | Some(it) => it, | ||
38 | None => return, | ||
39 | }; | ||
40 | |||
35 | if receiver_ty.is_bool() || receiver_ty.is_unknown() { | 41 | if receiver_ty.is_bool() || receiver_ty.is_unknown() { |
36 | postfix_snippet( | 42 | postfix_snippet( |
37 | ctx, | 43 | ctx, |
44 | cap, | ||
38 | &dot_receiver, | 45 | &dot_receiver, |
39 | "if", | 46 | "if", |
40 | "if expr {}", | 47 | "if expr {}", |
@@ -43,6 +50,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
43 | .add_to(acc); | 50 | .add_to(acc); |
44 | postfix_snippet( | 51 | postfix_snippet( |
45 | ctx, | 52 | ctx, |
53 | cap, | ||
46 | &dot_receiver, | 54 | &dot_receiver, |
47 | "while", | 55 | "while", |
48 | "while expr {}", | 56 | "while expr {}", |
@@ -52,11 +60,20 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
52 | } | 60 | } |
53 | 61 | ||
54 | // !&&&42 is a compiler error, ergo process it before considering the references | 62 | // !&&&42 is a compiler error, ergo process it before considering the references |
55 | postfix_snippet(ctx, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc); | 63 | postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text)) |
64 | .add_to(acc); | ||
56 | 65 | ||
57 | postfix_snippet(ctx, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc); | 66 | postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)) |
58 | postfix_snippet(ctx, &dot_receiver, "refm", "&mut expr", &format!("&mut {}", receiver_text)) | ||
59 | .add_to(acc); | 67 | .add_to(acc); |
68 | postfix_snippet( | ||
69 | ctx, | ||
70 | cap, | ||
71 | &dot_receiver, | ||
72 | "refm", | ||
73 | "&mut expr", | ||
74 | &format!("&mut {}", receiver_text), | ||
75 | ) | ||
76 | .add_to(acc); | ||
60 | 77 | ||
61 | // The rest of the postfix completions create an expression that moves an argument, | 78 | // The rest of the postfix completions create an expression that moves an argument, |
62 | // so it's better to consider references now to avoid breaking the compilation | 79 | // so it's better to consider references now to avoid breaking the compilation |
@@ -66,6 +83,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
66 | 83 | ||
67 | postfix_snippet( | 84 | postfix_snippet( |
68 | ctx, | 85 | ctx, |
86 | cap, | ||
69 | &dot_receiver, | 87 | &dot_receiver, |
70 | "match", | 88 | "match", |
71 | "match expr {}", | 89 | "match expr {}", |
@@ -75,6 +93,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
75 | 93 | ||
76 | postfix_snippet( | 94 | postfix_snippet( |
77 | ctx, | 95 | ctx, |
96 | cap, | ||
78 | &dot_receiver, | 97 | &dot_receiver, |
79 | "box", | 98 | "box", |
80 | "Box::new(expr)", | 99 | "Box::new(expr)", |
@@ -82,8 +101,15 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
82 | ) | 101 | ) |
83 | .add_to(acc); | 102 | .add_to(acc); |
84 | 103 | ||
85 | postfix_snippet(ctx, &dot_receiver, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)) | 104 | postfix_snippet( |
86 | .add_to(acc); | 105 | ctx, |
106 | cap, | ||
107 | &dot_receiver, | ||
108 | "dbg", | ||
109 | "dbg!(expr)", | ||
110 | &format!("dbg!({})", receiver_text), | ||
111 | ) | ||
112 | .add_to(acc); | ||
87 | } | 113 | } |
88 | 114 | ||
89 | fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { | 115 | fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { |
@@ -108,6 +134,7 @@ fn include_references(initial_element: &ast::Expr) -> ast::Expr { | |||
108 | 134 | ||
109 | fn postfix_snippet( | 135 | fn postfix_snippet( |
110 | ctx: &CompletionContext, | 136 | ctx: &CompletionContext, |
137 | cap: SnippetCap, | ||
111 | receiver: &ast::Expr, | 138 | receiver: &ast::Expr, |
112 | label: &str, | 139 | label: &str, |
113 | detail: &str, | 140 | detail: &str, |
@@ -121,7 +148,7 @@ fn postfix_snippet( | |||
121 | }; | 148 | }; |
122 | CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label) | 149 | CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label) |
123 | .detail(detail) | 150 | .detail(detail) |
124 | .snippet_edit(edit) | 151 | .snippet_edit(cap, edit) |
125 | } | 152 | } |
126 | 153 | ||
127 | #[cfg(test)] | 154 | #[cfg(test)] |
diff --git a/crates/ra_ide/src/completion/complete_snippet.rs b/crates/ra_ide/src/completion/complete_snippet.rs index f731e9b9a..4bccfbfed 100644 --- a/crates/ra_ide/src/completion/complete_snippet.rs +++ b/crates/ra_ide/src/completion/complete_snippet.rs | |||
@@ -1,13 +1,13 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use crate::completion::{ | 3 | use crate::completion::{ |
4 | completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, | 4 | completion_config::SnippetCap, completion_item::Builder, CompletionContext, CompletionItem, |
5 | CompletionKind, Completions, | 5 | CompletionItemKind, CompletionKind, Completions, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | fn snippet(ctx: &CompletionContext, label: &str, snippet: &str) -> Builder { | 8 | fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder { |
9 | CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), label) | 9 | CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), label) |
10 | .insert_snippet(snippet) | 10 | .insert_snippet(cap, snippet) |
11 | .kind(CompletionItemKind::Snippet) | 11 | .kind(CompletionItemKind::Snippet) |
12 | } | 12 | } |
13 | 13 | ||
@@ -15,17 +15,27 @@ pub(super) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionConte | |||
15 | if !(ctx.is_trivial_path && ctx.function_syntax.is_some()) { | 15 | if !(ctx.is_trivial_path && ctx.function_syntax.is_some()) { |
16 | return; | 16 | return; |
17 | } | 17 | } |
18 | let cap = match ctx.config.snippet_cap { | ||
19 | Some(it) => it, | ||
20 | None => return, | ||
21 | }; | ||
18 | 22 | ||
19 | snippet(ctx, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc); | 23 | snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc); |
20 | snippet(ctx, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc); | 24 | snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc); |
21 | } | 25 | } |
22 | 26 | ||
23 | pub(super) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { | 27 | pub(super) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { |
24 | if !ctx.is_new_item { | 28 | if !ctx.is_new_item { |
25 | return; | 29 | return; |
26 | } | 30 | } |
31 | let cap = match ctx.config.snippet_cap { | ||
32 | Some(it) => it, | ||
33 | None => return, | ||
34 | }; | ||
35 | |||
27 | snippet( | 36 | snippet( |
28 | ctx, | 37 | ctx, |
38 | cap, | ||
29 | "Test function", | 39 | "Test function", |
30 | "\ | 40 | "\ |
31 | #[test] | 41 | #[test] |
@@ -36,8 +46,8 @@ fn ${1:feature}() { | |||
36 | .lookup_by("tfn") | 46 | .lookup_by("tfn") |
37 | .add_to(acc); | 47 | .add_to(acc); |
38 | 48 | ||
39 | snippet(ctx, "macro_rules", "macro_rules! $1 {\n\t($2) => {\n\t\t$0\n\t};\n}").add_to(acc); | 49 | snippet(ctx, cap, "macro_rules", "macro_rules! $1 {\n\t($2) => {\n\t\t$0\n\t};\n}").add_to(acc); |
40 | snippet(ctx, "pub(crate)", "pub(crate) $0").add_to(acc); | 50 | snippet(ctx, cap, "pub(crate)", "pub(crate) $0").add_to(acc); |
41 | } | 51 | } |
42 | 52 | ||
43 | #[cfg(test)] | 53 | #[cfg(test)] |
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 2ec0e7ce9..c39943252 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs | |||
@@ -122,7 +122,7 @@ fn add_function_impl( | |||
122 | ctx: &CompletionContext, | 122 | ctx: &CompletionContext, |
123 | func: &hir::Function, | 123 | func: &hir::Function, |
124 | ) { | 124 | ) { |
125 | let display = FunctionSignature::from_hir(ctx.db, *func); | 125 | let signature = FunctionSignature::from_hir(ctx.db, *func); |
126 | 126 | ||
127 | let fn_name = func.name(ctx.db).to_string(); | 127 | let fn_name = func.name(ctx.db).to_string(); |
128 | 128 | ||
@@ -141,12 +141,20 @@ fn add_function_impl( | |||
141 | } else { | 141 | } else { |
142 | CompletionItemKind::Function | 142 | CompletionItemKind::Function |
143 | }; | 143 | }; |
144 | |||
145 | let snippet = format!("{} {{\n $0\n}}", display); | ||
146 | |||
147 | let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end()); | 144 | let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end()); |
148 | 145 | ||
149 | builder.snippet_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc); | 146 | match ctx.config.snippet_cap { |
147 | Some(cap) => { | ||
148 | let snippet = format!("{} {{\n $0\n}}", signature); | ||
149 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) | ||
150 | } | ||
151 | None => { | ||
152 | let header = format!("{} {{", signature); | ||
153 | builder.text_edit(TextEdit::replace(range, header)) | ||
154 | } | ||
155 | } | ||
156 | .kind(completion_kind) | ||
157 | .add_to(acc); | ||
150 | } | 158 | } |
151 | 159 | ||
152 | fn add_type_alias_impl( | 160 | fn add_type_alias_impl( |
diff --git a/crates/ra_ide/src/completion/completion_config.rs b/crates/ra_ide/src/completion/completion_config.rs new file mode 100644 index 000000000..6cf7ed6e4 --- /dev/null +++ b/crates/ra_ide/src/completion/completion_config.rs | |||
@@ -0,0 +1,29 @@ | |||
1 | //! Settings for tweaking completion. | ||
2 | //! | ||
3 | //! The fun thing here is `SnippetCap` -- this type can only be created in this | ||
4 | //! module, and we use to statically check that we only produce snippet | ||
5 | //! completions if we are allowed to. | ||
6 | |||
7 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
8 | pub struct CompletionConfig { | ||
9 | pub enable_postfix_completions: bool, | ||
10 | pub add_call_parenthesis: bool, | ||
11 | pub add_call_argument_snippets: bool, | ||
12 | pub snippet_cap: Option<SnippetCap>, | ||
13 | } | ||
14 | |||
15 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
16 | pub struct SnippetCap { | ||
17 | _private: (), | ||
18 | } | ||
19 | |||
20 | impl Default for CompletionConfig { | ||
21 | fn default() -> Self { | ||
22 | CompletionConfig { | ||
23 | enable_postfix_completions: true, | ||
24 | add_call_parenthesis: true, | ||
25 | add_call_argument_snippets: true, | ||
26 | snippet_cap: Some(SnippetCap { _private: () }), | ||
27 | } | ||
28 | } | ||
29 | } | ||
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index edbf4a5b7..fb06cc125 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | use std::fmt; | 3 | use std::fmt; |
4 | 4 | ||
5 | use super::completion_config::SnippetCap; | ||
5 | use hir::Documentation; | 6 | use hir::Documentation; |
6 | use ra_syntax::TextRange; | 7 | use ra_syntax::TextRange; |
7 | use ra_text_edit::TextEdit; | 8 | use ra_text_edit::TextEdit; |
@@ -270,7 +271,11 @@ impl Builder { | |||
270 | self.insert_text = Some(insert_text.into()); | 271 | self.insert_text = Some(insert_text.into()); |
271 | self | 272 | self |
272 | } | 273 | } |
273 | pub(crate) fn insert_snippet(mut self, snippet: impl Into<String>) -> Builder { | 274 | pub(crate) fn insert_snippet( |
275 | mut self, | ||
276 | _cap: SnippetCap, | ||
277 | snippet: impl Into<String>, | ||
278 | ) -> Builder { | ||
274 | self.insert_text_format = InsertTextFormat::Snippet; | 279 | self.insert_text_format = InsertTextFormat::Snippet; |
275 | self.insert_text(snippet) | 280 | self.insert_text(snippet) |
276 | } | 281 | } |
@@ -282,7 +287,7 @@ impl Builder { | |||
282 | self.text_edit = Some(edit); | 287 | self.text_edit = Some(edit); |
283 | self | 288 | self |
284 | } | 289 | } |
285 | pub(crate) fn snippet_edit(mut self, edit: TextEdit) -> Builder { | 290 | pub(crate) fn snippet_edit(mut self, _cap: SnippetCap, edit: TextEdit) -> Builder { |
286 | self.insert_text_format = InsertTextFormat::Snippet; | 291 | self.insert_text_format = InsertTextFormat::Snippet; |
287 | self.text_edit(edit) | 292 | self.text_edit(edit) |
288 | } | 293 | } |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 78df9cbdb..5e2b8b920 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -114,17 +114,19 @@ impl Completions { | |||
114 | 114 | ||
115 | // Add `<>` for generic types | 115 | // Add `<>` for generic types |
116 | if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis { | 116 | if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis { |
117 | let has_non_default_type_params = match resolution { | 117 | if let Some(cap) = ctx.config.snippet_cap { |
118 | ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), | 118 | let has_non_default_type_params = match resolution { |
119 | ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), | 119 | ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), |
120 | _ => false, | 120 | ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), |
121 | }; | 121 | _ => false, |
122 | if has_non_default_type_params { | 122 | }; |
123 | tested_by!(inserts_angle_brackets_for_generics); | 123 | if has_non_default_type_params { |
124 | completion_item = completion_item | 124 | tested_by!(inserts_angle_brackets_for_generics); |
125 | .lookup_by(local_name.clone()) | 125 | completion_item = completion_item |
126 | .label(format!("{}<…>", local_name)) | 126 | .lookup_by(local_name.clone()) |
127 | .insert_snippet(format!("{}<$0>", local_name)); | 127 | .label(format!("{}<…>", local_name)) |
128 | .insert_snippet(cap, format!("{}<$0>", local_name)); | ||
129 | } | ||
128 | } | 130 | } |
129 | } | 131 | } |
130 | 132 | ||
@@ -184,13 +186,16 @@ impl Completions { | |||
184 | .set_deprecated(is_deprecated(macro_, ctx.db)) | 186 | .set_deprecated(is_deprecated(macro_, ctx.db)) |
185 | .detail(detail); | 187 | .detail(detail); |
186 | 188 | ||
187 | builder = if ctx.use_item_syntax.is_some() || ctx.is_macro_call { | 189 | builder = match ctx.config.snippet_cap { |
188 | tested_by!(dont_insert_macro_call_parens_unncessary); | 190 | Some(cap) if ctx.use_item_syntax.is_none() && !ctx.is_macro_call => { |
189 | builder.insert_text(name) | 191 | let macro_braces_to_insert = |
190 | } else { | 192 | self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str())); |
191 | let macro_braces_to_insert = | 193 | builder.insert_snippet(cap, macro_declaration + macro_braces_to_insert) |
192 | self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str())); | 194 | } |
193 | builder.insert_snippet(macro_declaration + macro_braces_to_insert) | 195 | _ => { |
196 | tested_by!(dont_insert_macro_call_parens_unncessary); | ||
197 | builder.insert_text(name) | ||
198 | } | ||
194 | }; | 199 | }; |
195 | 200 | ||
196 | self.add(builder); | 201 | self.add(builder); |
@@ -366,6 +371,10 @@ impl Builder { | |||
366 | if ctx.use_item_syntax.is_some() || ctx.is_call { | 371 | if ctx.use_item_syntax.is_some() || ctx.is_call { |
367 | return self; | 372 | return self; |
368 | } | 373 | } |
374 | let cap = match ctx.config.snippet_cap { | ||
375 | Some(it) => it, | ||
376 | None => return self, | ||
377 | }; | ||
369 | // If not an import, add parenthesis automatically. | 378 | // If not an import, add parenthesis automatically. |
370 | tested_by!(inserts_parens_for_function_calls); | 379 | tested_by!(inserts_parens_for_function_calls); |
371 | 380 | ||
@@ -387,7 +396,7 @@ impl Builder { | |||
387 | 396 | ||
388 | (snippet, format!("{}(…)", name)) | 397 | (snippet, format!("{}(…)", name)) |
389 | }; | 398 | }; |
390 | self.lookup_by(name).label(label).insert_snippet(snippet) | 399 | self.lookup_by(name).label(label).insert_snippet(cap, snippet) |
391 | } | 400 | } |
392 | } | 401 | } |
393 | 402 | ||