From 757e593b253b4df7e6fc8bf15a4d4f34c9d484c5 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 27 Nov 2019 21:32:33 +0300 Subject: rename ra_ide_api -> ra_ide --- crates/ra_ide/src/completion/complete_postfix.rs | 282 +++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 crates/ra_ide/src/completion/complete_postfix.rs (limited to 'crates/ra_ide/src/completion/complete_postfix.rs') diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs new file mode 100644 index 000000000..646a30c76 --- /dev/null +++ b/crates/ra_ide/src/completion/complete_postfix.rs @@ -0,0 +1,282 @@ +//! FIXME: write short doc here + +use ra_syntax::{ast::AstNode, TextRange, TextUnit}; +use ra_text_edit::TextEdit; + +use crate::{ + completion::{ + completion_context::CompletionContext, + completion_item::{Builder, CompletionKind, Completions}, + }, + CompletionItem, +}; + +pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { + if ctx.db.feature_flags.get("completion.enable-postfix") == false { + return; + } + + let dot_receiver = match &ctx.dot_receiver { + Some(it) => it, + None => return, + }; + + let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal { + let text = dot_receiver.syntax().text(); + let without_dot = ..text.len() - TextUnit::of_char('.'); + text.slice(without_dot).to_string() + } else { + dot_receiver.syntax().text().to_string() + }; + + let receiver_ty = match ctx.analyzer.type_of(ctx.db, &dot_receiver) { + Some(it) => it, + None => return, + }; + + if receiver_ty.is_bool() || receiver_ty.is_unknown() { + postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) + .add_to(acc); + postfix_snippet( + ctx, + "while", + "while expr {}", + &format!("while {} {{\n$0\n}}", receiver_text), + ) + .add_to(acc); + } + + postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc); + + postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc); + postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc); + + postfix_snippet( + ctx, + "match", + "match expr {}", + &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), + ) + .add_to(acc); + + postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc); + + postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text)) + .add_to(acc); +} + +fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { + let edit = { + let receiver_range = + ctx.dot_receiver.as_ref().expect("no receiver available").syntax().text_range(); + let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end()); + TextEdit::replace(delete_range, snippet.to_string()) + }; + CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label) + .detail(detail) + .snippet_edit(edit) +} + +#[cfg(test)] +mod tests { + use insta::assert_debug_snapshot; + + use crate::completion::{do_completion, CompletionItem, CompletionKind}; + + fn do_postfix_completion(code: &str) -> Vec { + do_completion(code, CompletionKind::Postfix) + } + + #[test] + fn postfix_completion_works_for_trivial_path_expression() { + assert_debug_snapshot!( + do_postfix_completion( + r#" + fn main() { + let bar = true; + bar.<|> + } + "#, + ), + @r###" + [ + CompletionItem { + label: "box", + source_range: [89; 89), + delete: [85; 89), + insert: "Box::new(bar)", + detail: "Box::new(expr)", + }, + CompletionItem { + label: "dbg", + source_range: [89; 89), + delete: [85; 89), + insert: "dbg!(bar)", + detail: "dbg!(expr)", + }, + CompletionItem { + label: "if", + source_range: [89; 89), + delete: [85; 89), + insert: "if bar {$0}", + detail: "if expr {}", + }, + CompletionItem { + label: "match", + source_range: [89; 89), + delete: [85; 89), + insert: "match bar {\n ${1:_} => {$0\\},\n}", + detail: "match expr {}", + }, + CompletionItem { + label: "not", + source_range: [89; 89), + delete: [85; 89), + insert: "!bar", + detail: "!expr", + }, + CompletionItem { + label: "ref", + source_range: [89; 89), + delete: [85; 89), + insert: "&bar", + detail: "&expr", + }, + CompletionItem { + label: "refm", + source_range: [89; 89), + delete: [85; 89), + insert: "&mut bar", + detail: "&mut expr", + }, + CompletionItem { + label: "while", + source_range: [89; 89), + delete: [85; 89), + insert: "while bar {\n$0\n}", + detail: "while expr {}", + }, + ] + "### + ); + } + + #[test] + fn some_postfix_completions_ignored() { + assert_debug_snapshot!( + do_postfix_completion( + r#" + fn main() { + let bar: u8 = 12; + bar.<|> + } + "#, + ), + @r###" + [ + CompletionItem { + label: "box", + source_range: [91; 91), + delete: [87; 91), + insert: "Box::new(bar)", + detail: "Box::new(expr)", + }, + CompletionItem { + label: "dbg", + source_range: [91; 91), + delete: [87; 91), + insert: "dbg!(bar)", + detail: "dbg!(expr)", + }, + CompletionItem { + label: "match", + source_range: [91; 91), + delete: [87; 91), + insert: "match bar {\n ${1:_} => {$0\\},\n}", + detail: "match expr {}", + }, + CompletionItem { + label: "not", + source_range: [91; 91), + delete: [87; 91), + insert: "!bar", + detail: "!expr", + }, + CompletionItem { + label: "ref", + source_range: [91; 91), + delete: [87; 91), + insert: "&bar", + detail: "&expr", + }, + CompletionItem { + label: "refm", + source_range: [91; 91), + delete: [87; 91), + insert: "&mut bar", + detail: "&mut expr", + }, + ] + "### + ); + } + + #[test] + fn postfix_completion_works_for_ambiguous_float_literal() { + assert_debug_snapshot!( + do_postfix_completion( + r#" + fn main() { + 42.<|> + } + "#, + ), + @r###" + [ + CompletionItem { + label: "box", + source_range: [52; 52), + delete: [49; 52), + insert: "Box::new(42)", + detail: "Box::new(expr)", + }, + CompletionItem { + label: "dbg", + source_range: [52; 52), + delete: [49; 52), + insert: "dbg!(42)", + detail: "dbg!(expr)", + }, + CompletionItem { + label: "match", + source_range: [52; 52), + delete: [49; 52), + insert: "match 42 {\n ${1:_} => {$0\\},\n}", + detail: "match expr {}", + }, + CompletionItem { + label: "not", + source_range: [52; 52), + delete: [49; 52), + insert: "!42", + detail: "!expr", + }, + CompletionItem { + label: "ref", + source_range: [52; 52), + delete: [49; 52), + insert: "&42", + detail: "&expr", + }, + CompletionItem { + label: "refm", + source_range: [52; 52), + delete: [49; 52), + insert: "&mut 42", + detail: "&mut expr", + }, + ] + "### + ); + } +} -- cgit v1.2.3