1 //! FIXME: write short doc here
3 use hir::{Ty, TypeCtor};
4 use ra_syntax::{ast::AstNode, TextRange, TextUnit};
5 use ra_text_edit::TextEdit;
9 completion_context::CompletionContext,
10 completion_item::{Builder, CompletionKind, Completions},
15 pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
16 if ctx.db.feature_flags.get("completions.enable-postfix") == false {
20 let dot_receiver = match &ctx.dot_receiver {
25 let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal {
26 let text = dot_receiver.syntax().text();
27 let without_dot = ..text.len() - TextUnit::of_char('.');
28 text.slice(without_dot).to_string()
30 dot_receiver.syntax().text().to_string()
33 let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver);
35 if is_bool_or_unknown(receiver_ty) {
36 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
42 &format!("while {} {{\n$0\n}}", receiver_text),
47 postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc);
49 postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc);
50 postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc);
56 &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text),
60 postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc);
62 postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text))
66 fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
69 ctx.dot_receiver.as_ref().expect("no receiver available").syntax().text_range();
70 let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end());
71 TextEdit::replace(delete_range, snippet.to_string())
73 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
78 fn is_bool_or_unknown(ty: Option<Ty>) -> bool {
80 Some(Ty::Apply(app)) if app.ctor == TypeCtor::Bool => true,
81 Some(Ty::Unknown) | None => true,
88 use insta::assert_debug_snapshot;
90 use crate::completion::{do_completion, CompletionItem, CompletionKind};
92 fn do_postfix_completion(code: &str) -> Vec<CompletionItem> {
93 do_completion(code, CompletionKind::Postfix)
97 fn postfix_completion_works_for_trivial_path_expression() {
98 assert_debug_snapshot!(
99 do_postfix_completion(
110 source_range: [89; 89),
112 insert: "Box::new(bar)",
113 detail: "Box::new(expr)",
117 source_range: [89; 89),
120 detail: "dbg!(expr)",
124 source_range: [89; 89),
126 insert: "if bar {$0}",
127 detail: "if expr {}",
131 source_range: [89; 89),
133 insert: "match bar {\n ${1:_} => {$0\\},\n}",
134 detail: "match expr {}",
138 source_range: [89; 89),
145 source_range: [89; 89),
152 source_range: [89; 89),
159 source_range: [89; 89),
161 insert: "while bar {\n$0\n}",
162 detail: "while expr {}",
169 fn some_postfix_completions_ignored() {
170 assert_debug_snapshot!(
171 do_postfix_completion(
182 source_range: [91; 91),
184 insert: "Box::new(bar)",
185 detail: "Box::new(expr)",
189 source_range: [91; 91),
192 detail: "dbg!(expr)",
196 source_range: [91; 91),
198 insert: "match bar {\n ${1:_} => {$0\\},\n}",
199 detail: "match expr {}",
203 source_range: [91; 91),
210 source_range: [91; 91),
217 source_range: [91; 91),
227 fn postfix_completion_works_for_ambiguous_float_literal() {
228 assert_debug_snapshot!(
229 do_postfix_completion(
239 source_range: [52; 52),
241 insert: "Box::new(42)",
242 detail: "Box::new(expr)",
246 source_range: [52; 52),
249 detail: "dbg!(expr)",
253 source_range: [52; 52),
255 insert: "match 42 {\n ${1:_} => {$0\\},\n}",
256 detail: "match expr {}",
260 source_range: [52; 52),
267 source_range: [52; 52),
274 source_range: [52; 52),