From 9e7c952bbddc2e6763c49f0511a295362e9893d6 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sun, 18 Oct 2020 13:09:00 +0300 Subject: Extract call_info and completion into separate crates --- crates/ide/src/completion/complete_postfix.rs | 454 -------------------------- 1 file changed, 454 deletions(-) delete mode 100644 crates/ide/src/completion/complete_postfix.rs (limited to 'crates/ide/src/completion/complete_postfix.rs') diff --git a/crates/ide/src/completion/complete_postfix.rs b/crates/ide/src/completion/complete_postfix.rs deleted file mode 100644 index db5319618..000000000 --- a/crates/ide/src/completion/complete_postfix.rs +++ /dev/null @@ -1,454 +0,0 @@ -//! FIXME: write short doc here - -mod format_like; - -use assists::utils::TryEnum; -use syntax::{ - ast::{self, AstNode, AstToken}, - TextRange, TextSize, -}; -use text_edit::TextEdit; - -use self::format_like::add_format_like_completions; -use crate::{ - completion::{ - completion_config::SnippetCap, - completion_context::CompletionContext, - completion_item::{Builder, CompletionKind, Completions}, - }, - CompletionItem, CompletionItemKind, -}; - -pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { - if !ctx.config.enable_postfix_completions { - return; - } - - let dot_receiver = match &ctx.dot_receiver { - Some(it) => it, - None => return, - }; - - let receiver_text = - get_receiver_text(dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); - - let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { - Some(it) => it, - None => return, - }; - - let cap = match ctx.config.snippet_cap { - Some(it) => it, - None => return, - }; - let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty); - if let Some(try_enum) = &try_enum { - match try_enum { - TryEnum::Result => { - postfix_snippet( - ctx, - cap, - &dot_receiver, - "ifl", - "if let Ok {}", - &format!("if let Ok($1) = {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - - postfix_snippet( - ctx, - cap, - &dot_receiver, - "while", - "while let Ok {}", - &format!("while let Ok($1) = {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - } - TryEnum::Option => { - postfix_snippet( - ctx, - cap, - &dot_receiver, - "ifl", - "if let Some {}", - &format!("if let Some($1) = {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - - postfix_snippet( - ctx, - cap, - &dot_receiver, - "while", - "while let Some {}", - &format!("while let Some($1) = {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - } - } - } else if receiver_ty.is_bool() || receiver_ty.is_unknown() { - postfix_snippet( - ctx, - cap, - &dot_receiver, - "if", - "if expr {}", - &format!("if {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - postfix_snippet( - ctx, - cap, - &dot_receiver, - "while", - "while expr {}", - &format!("while {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text)) - .add_to(acc); - } - - postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)) - .add_to(acc); - postfix_snippet( - ctx, - cap, - &dot_receiver, - "refm", - "&mut expr", - &format!("&mut {}", receiver_text), - ) - .add_to(acc); - - // The rest of the postfix completions create an expression that moves an argument, - // so it's better to consider references now to avoid breaking the compilation - let dot_receiver = include_references(dot_receiver); - let receiver_text = - get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); - - match try_enum { - Some(try_enum) => match try_enum { - TryEnum::Result => { - postfix_snippet( - ctx, - cap, - &dot_receiver, - "match", - "match expr {}", - &format!("match {} {{\n Ok(${{1:_}}) => {{$2}},\n Err(${{3:_}}) => {{$0}},\n}}", receiver_text), - ) - .add_to(acc); - } - TryEnum::Option => { - postfix_snippet( - ctx, - cap, - &dot_receiver, - "match", - "match expr {}", - &format!( - "match {} {{\n Some(${{1:_}}) => {{$2}},\n None => {{$0}},\n}}", - receiver_text - ), - ) - .add_to(acc); - } - }, - None => { - postfix_snippet( - ctx, - cap, - &dot_receiver, - "match", - "match expr {}", - &format!("match {} {{\n ${{1:_}} => {{$0}},\n}}", receiver_text), - ) - .add_to(acc); - } - } - - postfix_snippet( - ctx, - cap, - &dot_receiver, - "box", - "Box::new(expr)", - &format!("Box::new({})", receiver_text), - ) - .add_to(acc); - - postfix_snippet(ctx, cap, &dot_receiver, "ok", "Ok(expr)", &format!("Ok({})", receiver_text)) - .add_to(acc); - - postfix_snippet( - ctx, - cap, - &dot_receiver, - "dbg", - "dbg!(expr)", - &format!("dbg!({})", receiver_text), - ) - .add_to(acc); - - postfix_snippet( - ctx, - cap, - &dot_receiver, - "dbgr", - "dbg!(&expr)", - &format!("dbg!(&{})", receiver_text), - ) - .add_to(acc); - - postfix_snippet( - ctx, - cap, - &dot_receiver, - "call", - "function(expr)", - &format!("${{1}}({})", receiver_text), - ) - .add_to(acc); - - if let ast::Expr::Literal(literal) = dot_receiver.clone() { - if let Some(literal_text) = ast::String::cast(literal.token()) { - add_format_like_completions(acc, ctx, &dot_receiver, cap, &literal_text); - } - } -} - -fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { - if receiver_is_ambiguous_float_literal { - let text = receiver.syntax().text(); - let without_dot = ..text.len() - TextSize::of('.'); - text.slice(without_dot).to_string() - } else { - receiver.to_string() - } -} - -fn include_references(initial_element: &ast::Expr) -> ast::Expr { - let mut resulting_element = initial_element.clone(); - while let Some(parent_ref_element) = - resulting_element.syntax().parent().and_then(ast::RefExpr::cast) - { - resulting_element = ast::Expr::from(parent_ref_element); - } - resulting_element -} - -fn postfix_snippet( - ctx: &CompletionContext, - cap: SnippetCap, - receiver: &ast::Expr, - label: &str, - detail: &str, - snippet: &str, -) -> Builder { - let edit = { - let receiver_syntax = receiver.syntax(); - let receiver_range = ctx.sema.original_range(receiver_syntax).range; - let delete_range = TextRange::new(receiver_range.start(), ctx.source_range().end()); - TextEdit::replace(delete_range, snippet.to_string()) - }; - CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label) - .detail(detail) - .kind(CompletionItemKind::Snippet) - .snippet_edit(cap, edit) -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::completion::{ - test_utils::{check_edit, completion_list}, - CompletionKind, - }; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Postfix); - expect.assert_eq(&actual) - } - - #[test] - fn postfix_completion_works_for_trivial_path_expression() { - check( - r#" -fn main() { - let bar = true; - bar.<|> -} -"#, - expect![[r#" - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn if if expr {} - sn match match expr {} - sn not !expr - sn ok Ok(expr) - sn ref &expr - sn refm &mut expr - sn while while expr {} - "#]], - ); - } - - #[test] - fn postfix_type_filtering() { - check( - r#" -fn main() { - let bar: u8 = 12; - bar.<|> -} -"#, - expect![[r#" - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn match match expr {} - sn ok Ok(expr) - sn ref &expr - sn refm &mut expr - "#]], - ) - } - - #[test] - fn option_iflet() { - check_edit( - "ifl", - r#" -enum Option { Some(T), None } - -fn main() { - let bar = Option::Some(true); - bar.<|> -} -"#, - r#" -enum Option { Some(T), None } - -fn main() { - let bar = Option::Some(true); - if let Some($1) = bar { - $0 -} -} -"#, - ); - } - - #[test] - fn result_match() { - check_edit( - "match", - r#" -enum Result { Ok(T), Err(E) } - -fn main() { - let bar = Result::Ok(true); - bar.<|> -} -"#, - r#" -enum Result { Ok(T), Err(E) } - -fn main() { - let bar = Result::Ok(true); - match bar { - Ok(${1:_}) => {$2}, - Err(${3:_}) => {$0}, -} -} -"#, - ); - } - - #[test] - fn postfix_completion_works_for_ambiguous_float_literal() { - check_edit("refm", r#"fn main() { 42.<|> }"#, r#"fn main() { &mut 42 }"#) - } - - #[test] - fn works_in_simple_macro() { - check_edit( - "dbg", - r#" -macro_rules! m { ($e:expr) => { $e } } -fn main() { - let bar: u8 = 12; - m!(bar.d<|>) -} -"#, - r#" -macro_rules! m { ($e:expr) => { $e } } -fn main() { - let bar: u8 = 12; - m!(dbg!(bar)) -} -"#, - ); - } - - #[test] - fn postfix_completion_for_references() { - check_edit("dbg", r#"fn main() { &&42.<|> }"#, r#"fn main() { dbg!(&&42) }"#); - check_edit("refm", r#"fn main() { &&42.<|> }"#, r#"fn main() { &&&mut 42 }"#); - } - - #[test] - fn postfix_completion_for_format_like_strings() { - check_edit( - "fmt", - r#"fn main() { "{some_var:?}".<|> }"#, - r#"fn main() { format!("{:?}", some_var) }"#, - ); - check_edit( - "panic", - r#"fn main() { "Panic with {a}".<|> }"#, - r#"fn main() { panic!("Panic with {}", a) }"#, - ); - check_edit( - "println", - r#"fn main() { "{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".<|> }"#, - r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }) }"#, - ); - check_edit( - "loge", - r#"fn main() { "{2+2}".<|> }"#, - r#"fn main() { log::error!("{}", 2+2) }"#, - ); - check_edit( - "logt", - r#"fn main() { "{2+2}".<|> }"#, - r#"fn main() { log::trace!("{}", 2+2) }"#, - ); - check_edit( - "logd", - r#"fn main() { "{2+2}".<|> }"#, - r#"fn main() { log::debug!("{}", 2+2) }"#, - ); - check_edit( - "logi", - r#"fn main() { "{2+2}".<|> }"#, - r#"fn main() { log::info!("{}", 2+2) }"#, - ); - check_edit( - "logw", - r#"fn main() { "{2+2}".<|> }"#, - r#"fn main() { log::warn!("{}", 2+2) }"#, - ); - check_edit( - "loge", - r#"fn main() { "{2+2}".<|> }"#, - r#"fn main() { log::error!("{}", 2+2) }"#, - ); - } -} -- cgit v1.2.3