aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Parilin <[email protected]>2019-10-14 16:39:40 +0100
committerSergey Parilin <[email protected]>2019-10-14 16:39:40 +0100
commitbec47e221fbd78a2e5f253e9418c4b86e243e35a (patch)
treef6669763a3a3fe2a6240f9bdb4f5837f9866d6ee
parent77f2dd96a122e59a8d8df8afb53a741df9b1af76 (diff)
#1435 postfix completion for integer literals
-rw-r--r--crates/ra_ide_api/src/completion/complete_postfix.rs67
-rw-r--r--crates/ra_ide_api/src/completion/completion_context.rs12
2 files changed, 77 insertions, 2 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs
index 445a02676..555cecb73 100644
--- a/crates/ra_ide_api/src/completion/complete_postfix.rs
+++ b/crates/ra_ide_api/src/completion/complete_postfix.rs
@@ -8,7 +8,7 @@ use crate::{
8 CompletionItem, 8 CompletionItem,
9}; 9};
10use hir::{Ty, TypeCtor}; 10use hir::{Ty, TypeCtor};
11use ra_syntax::{ast::AstNode, TextRange}; 11use ra_syntax::{ast::AstNode, TextRange, TextUnit};
12use ra_text_edit::TextEditBuilder; 12use ra_text_edit::TextEditBuilder;
13 13
14fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { 14fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
@@ -42,7 +42,13 @@ fn is_bool_or_unknown(ty: Option<Ty>) -> bool {
42 42
43pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { 43pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
44 if let Some(dot_receiver) = &ctx.dot_receiver { 44 if let Some(dot_receiver) = &ctx.dot_receiver {
45 let receiver_text = dot_receiver.syntax().text().to_string(); 45 let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal {
46 let text = dot_receiver.syntax().text();
47 let without_dot = ..text.len() - TextUnit::of_char('.');
48 text.slice(without_dot).to_string()
49 } else {
50 dot_receiver.syntax().text().to_string()
51 };
46 let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); 52 let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver);
47 if is_bool_or_unknown(receiver_ty) { 53 if is_bool_or_unknown(receiver_ty) {
48 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) 54 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
@@ -209,4 +215,61 @@ mod tests {
209]"### 215]"###
210 ); 216 );
211 } 217 }
218
219 #[test]
220 fn postfix_completion_works_for_ambiguous_float_literal() {
221 assert_debug_snapshot!(
222 do_postfix_completion(
223 r#"
224 fn main() {
225 42.<|>
226 }
227 "#,
228 ),
229 @r###"[
230 CompletionItem {
231 label: "box",
232 source_range: [52; 52),
233 delete: [49; 52),
234 insert: "Box::new(42)",
235 detail: "Box::new(expr)",
236 },
237 CompletionItem {
238 label: "dbg",
239 source_range: [52; 52),
240 delete: [49; 52),
241 insert: "dbg!(42)",
242 detail: "dbg!(expr)",
243 },
244 CompletionItem {
245 label: "match",
246 source_range: [52; 52),
247 delete: [49; 52),
248 insert: "match 42 {\n ${1:_} => {$0\\},\n}",
249 detail: "match expr {}",
250 },
251 CompletionItem {
252 label: "not",
253 source_range: [52; 52),
254 delete: [49; 52),
255 insert: "!42",
256 detail: "!expr",
257 },
258 CompletionItem {
259 label: "ref",
260 source_range: [52; 52),
261 delete: [49; 52),
262 insert: "&42",
263 detail: "&expr",
264 },
265 CompletionItem {
266 label: "refm",
267 source_range: [52; 52),
268 delete: [49; 52),
269 insert: "&mut 42",
270 detail: "&mut expr",
271 },
272]"###
273 );
274 }
212} 275}
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index 73f3f3960..64cbc0f98 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -38,6 +38,7 @@ pub(crate) struct CompletionContext<'a> {
38 pub(super) is_new_item: bool, 38 pub(super) is_new_item: bool,
39 /// The receiver if this is a field or method access, i.e. writing something.<|> 39 /// The receiver if this is a field or method access, i.e. writing something.<|>
40 pub(super) dot_receiver: Option<ast::Expr>, 40 pub(super) dot_receiver: Option<ast::Expr>,
41 pub(super) dot_receiver_is_ambiguous_float_literal: bool,
41 /// If this is a call (method or function) in particular, i.e. the () are already there. 42 /// If this is a call (method or function) in particular, i.e. the () are already there.
42 pub(super) is_call: bool, 43 pub(super) is_call: bool,
43 pub(super) is_path_type: bool, 44 pub(super) is_path_type: bool,
@@ -80,6 +81,7 @@ impl<'a> CompletionContext<'a> {
80 is_call: false, 81 is_call: false,
81 is_path_type: false, 82 is_path_type: false,
82 has_type_args: false, 83 has_type_args: false,
84 dot_receiver_is_ambiguous_float_literal: false,
83 }; 85 };
84 ctx.fill(&original_parse, position.offset); 86 ctx.fill(&original_parse, position.offset);
85 Some(ctx) 87 Some(ctx)
@@ -235,6 +237,16 @@ impl<'a> CompletionContext<'a> {
235 .expr() 237 .expr()
236 .map(|e| e.syntax().text_range()) 238 .map(|e| e.syntax().text_range())
237 .and_then(|r| find_node_with_range(original_file.syntax(), r)); 239 .and_then(|r| find_node_with_range(original_file.syntax(), r));
240 self.dot_receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) =
241 &self.dot_receiver
242 {
243 match l.kind() {
244 ast::LiteralKind::FloatNumber { suffix: _ } => l.token().text().ends_with('.'),
245 _ => false,
246 }
247 } else {
248 false
249 }
238 } 250 }
239 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { 251 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
240 // As above 252 // As above