aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorIgor Aleksanov <[email protected]>2020-09-12 15:32:19 +0100
committerIgor Aleksanov <[email protected]>2020-10-02 10:42:39 +0100
commite447b3a4a2bf089e5e3a190a532c17a4572ea013 (patch)
treecf5a0b06d5fffb5e95271cd6c818928ff2494b20 /crates
parentea320141c6f87383880878b91182355c9ad7dc7b (diff)
Improve checks for postfix suggestions
Diffstat (limited to 'crates')
-rw-r--r--crates/ide/src/completion/complete_postfix.rs4
-rw-r--r--crates/ide/src/completion/complete_postfix/format_like.rs26
-rw-r--r--crates/ide/src/completion/completion_context.rs9
3 files changed, 23 insertions, 16 deletions
diff --git a/crates/ide/src/completion/complete_postfix.rs b/crates/ide/src/completion/complete_postfix.rs
index 73a5f1439..599074254 100644
--- a/crates/ide/src/completion/complete_postfix.rs
+++ b/crates/ide/src/completion/complete_postfix.rs
@@ -211,9 +211,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
211 ) 211 )
212 .add_to(acc); 212 .add_to(acc);
213 213
214 if ctx.is_string_literal { 214 add_format_like_completions(acc, ctx, &dot_receiver, cap, &receiver_text);
215 add_format_like_completions(acc, ctx, &dot_receiver, cap, &receiver_text);
216 }
217} 215}
218 216
219fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { 217fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String {
diff --git a/crates/ide/src/completion/complete_postfix/format_like.rs b/crates/ide/src/completion/complete_postfix/format_like.rs
index 93211a35f..6be3c2c92 100644
--- a/crates/ide/src/completion/complete_postfix/format_like.rs
+++ b/crates/ide/src/completion/complete_postfix/format_like.rs
@@ -27,7 +27,11 @@ pub(super) fn add_format_like_completions(
27 cap: SnippetCap, 27 cap: SnippetCap,
28 receiver_text: &str, 28 receiver_text: &str,
29) { 29) {
30 assert!(receiver_text.len() >= 2); 30 if !is_string_literal(receiver_text) {
31 // It's not a string literal, do not parse input.
32 return;
33 }
34
31 let input = &receiver_text[1..receiver_text.len() - 1]; 35 let input = &receiver_text[1..receiver_text.len() - 1];
32 36
33 let mut parser = FormatStrParser::new(input); 37 let mut parser = FormatStrParser::new(input);
@@ -42,6 +46,20 @@ pub(super) fn add_format_like_completions(
42 } 46 }
43} 47}
44 48
49/// Checks whether provided item is a string literal.
50fn is_string_literal(item: &str) -> bool {
51 if item.len() < 2 {
52 return false;
53 }
54 if item.chars().nth(0) != Some('"') || item.chars().nth(item.len() - 1) != Some('"') {
55 return false;
56 }
57
58 true
59}
60
61/// Parser for a format-like string. It is more allowing in terms of string contents,
62/// as we expect variable placeholders to be filled with expressions.
45#[derive(Debug)] 63#[derive(Debug)]
46pub struct FormatStrParser { 64pub struct FormatStrParser {
47 input: String, 65 input: String,
@@ -127,7 +145,7 @@ impl FormatStrParser {
127 pub fn parse(&mut self) -> Result<(), ()> { 145 pub fn parse(&mut self) -> Result<(), ()> {
128 let mut current_expr = String::new(); 146 let mut current_expr = String::new();
129 147
130 let mut placeholders_count = 0; 148 let mut placeholder_id = 1;
131 149
132 // Count of open braces inside of an expression. 150 // Count of open braces inside of an expression.
133 // We assume that user knows what they're doing, thus we treat it like a correct pattern, e.g. 151 // We assume that user knows what they're doing, thus we treat it like a correct pattern, e.g.
@@ -163,8 +181,8 @@ impl FormatStrParser {
163 (State::MaybeExpr, '}') => { 181 (State::MaybeExpr, '}') => {
164 // This is an empty sequence '{}'. Replace it with placeholder. 182 // This is an empty sequence '{}'. Replace it with placeholder.
165 self.output.push(chr); 183 self.output.push(chr);
166 self.extracted_expressions.push(format!("${}", placeholders_count)); 184 self.extracted_expressions.push(format!("${}", placeholder_id));
167 placeholders_count += 1; 185 placeholder_id += 1;
168 self.state = State::NotExpr; 186 self.state = State::NotExpr;
169 } 187 }
170 (State::MaybeExpr, _) => { 188 (State::MaybeExpr, _) => {
diff --git a/crates/ide/src/completion/completion_context.rs b/crates/ide/src/completion/completion_context.rs
index 842d1987c..101be8eb5 100644
--- a/crates/ide/src/completion/completion_context.rs
+++ b/crates/ide/src/completion/completion_context.rs
@@ -74,8 +74,6 @@ pub(crate) struct CompletionContext<'a> {
74 pub(super) is_pattern_call: bool, 74 pub(super) is_pattern_call: bool,
75 /// If this is a macro call, i.e. the () are already there. 75 /// If this is a macro call, i.e. the () are already there.
76 pub(super) is_macro_call: bool, 76 pub(super) is_macro_call: bool,
77 /// If this is a string literal, like "lorem ipsum".
78 pub(super) is_string_literal: bool,
79 pub(super) is_path_type: bool, 77 pub(super) is_path_type: bool,
80 pub(super) has_type_args: bool, 78 pub(super) has_type_args: bool,
81 pub(super) attribute_under_caret: Option<ast::Attr>, 79 pub(super) attribute_under_caret: Option<ast::Attr>,
@@ -158,7 +156,6 @@ impl<'a> CompletionContext<'a> {
158 is_call: false, 156 is_call: false,
159 is_pattern_call: false, 157 is_pattern_call: false,
160 is_macro_call: false, 158 is_macro_call: false,
161 is_string_literal: false,
162 is_path_type: false, 159 is_path_type: false,
163 has_type_args: false, 160 has_type_args: false,
164 dot_receiver_is_ambiguous_float_literal: false, 161 dot_receiver_is_ambiguous_float_literal: false,
@@ -473,12 +470,6 @@ impl<'a> CompletionContext<'a> {
473 } else { 470 } else {
474 false 471 false
475 }; 472 };
476
477 self.is_string_literal = if let Some(ast::Expr::Literal(l)) = &self.dot_receiver {
478 matches!(l.kind(), ast::LiteralKind::String { .. })
479 } else {
480 false
481 };
482 } 473 }
483 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { 474 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
484 // As above 475 // As above