Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide-completion/src/completions/dot.rs2
-rw-r--r--crates/ide-completion/src/completions/postfix.rs106
-rw-r--r--crates/ide-completion/src/completions/postfix/format_like.rs9
3 files changed, 70 insertions, 47 deletions
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index a4f092cc49..4d4c9c9aa2 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -1035,7 +1035,7 @@ fn main() {
fn postfix_drop_completion() {
cov_mark::check!(postfix_drop_completion);
check_edit(
- "drop",
+ "x.drop",
r#"
//- minicore: drop
struct Vec<T>(T);
diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs
index c6e243b31a..04c1318d83 100644
--- a/crates/ide-completion/src/completions/postfix.rs
+++ b/crates/ide-completion/src/completions/postfix.rs
@@ -12,6 +12,7 @@ use ide_db::{
use stdx::never;
use syntax::{
ast::{self, make, AstNode, AstToken},
+ format_smolstr,
SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR},
TextRange, TextSize,
};
@@ -55,10 +56,11 @@ pub(crate) fn complete_postfix(
None => return,
};
- let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, dot_receiver) {
- Some(it) => it,
- None => return,
- };
+ let postfix_snippet =
+ match build_postfix_snippet_builder(ctx, cap, dot_receiver, &receiver_text) {
+ Some(it) => it,
+ None => return,
+ };
if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() {
if receiver_ty.impls_trait(ctx.db, drop_trait, &[]) {
@@ -173,10 +175,11 @@ pub(crate) fn complete_postfix(
let (dot_receiver, node_to_replace_with) = include_references(dot_receiver);
let receiver_text =
get_receiver_text(&node_to_replace_with, receiver_is_ambiguous_float_literal);
- let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, &dot_receiver) {
- Some(it) => it,
- None => return,
- };
+ let postfix_snippet =
+ match build_postfix_snippet_builder(ctx, cap, &dot_receiver, &receiver_text) {
+ Some(it) => it,
+ None => return,
+ };
if !ctx.config.snippets.is_empty() {
add_custom_postfix_completions(acc, ctx, &postfix_snippet, &receiver_text);
@@ -317,6 +320,7 @@ fn build_postfix_snippet_builder<'ctx>(
ctx: &'ctx CompletionContext<'_>,
cap: SnippetCap,
receiver: &'ctx ast::Expr,
+ receiver_text: &'ctx str,
) -> Option<impl Fn(&str, &str, &str) -> Builder + 'ctx> {
let receiver_range = ctx.sema.original_range_opt(receiver.syntax())?.range;
if ctx.source_range().end() < receiver_range.start() {
@@ -332,13 +336,16 @@ fn build_postfix_snippet_builder<'ctx>(
fn build<'ctx>(
ctx: &'ctx CompletionContext<'_>,
cap: SnippetCap,
+ receiver_text: &'ctx str,
delete_range: TextRange,
) -> impl Fn(&str, &str, &str) -> Builder + 'ctx {
move |label, detail, snippet| {
let edit = TextEdit::replace(delete_range, snippet.to_owned());
- let mut item =
- CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
+ let mut item = CompletionItem::new(CompletionItemKind::Snippet, delete_range, label);
item.detail(detail).snippet_edit(cap, edit);
+ // Editors may filter completion item with the text within delete_range, so we need to
+ // include the receiver text in the lookup for editors to find the completion item.
+ item.lookup_by(format_smolstr!("{}.{}", receiver_text, label));
let postfix_match = if ctx.original_token.text() == label {
cov_mark::hit!(postfix_exact_match_is_high_priority);
Some(CompletionRelevancePostfixMatch::Exact)
@@ -351,7 +358,7 @@ fn build_postfix_snippet_builder<'ctx>(
item
}
}
- Some(build(ctx, cap, delete_range))
+ Some(build(ctx, cap, receiver_text, delete_range))
}
fn add_custom_postfix_completions(
@@ -512,7 +519,7 @@ fn main() {
#[test]
fn option_iflet() {
check_edit(
- "ifl",
+ "bar.ifl",
r#"
//- minicore: option
fn main() {
@@ -534,7 +541,7 @@ fn main() {
#[test]
fn option_letelse() {
check_edit(
- "lete",
+ "bar.lete",
r#"
//- minicore: option
fn main() {
@@ -557,7 +564,7 @@ $0
#[test]
fn result_match() {
check_edit(
- "match",
+ "bar.match",
r#"
//- minicore: result
fn main() {
@@ -579,13 +586,13 @@ fn main() {
#[test]
fn postfix_completion_works_for_ambiguous_float_literal() {
- check_edit("refm", r#"fn main() { 42.$0 }"#, r#"fn main() { &mut 42 }"#)
+ check_edit("42.refm", r#"fn main() { 42.$0 }"#, r#"fn main() { &mut 42 }"#)
}
#[test]
fn works_in_simple_macro() {
check_edit(
- "dbg",
+ "bar.dbg",
r#"
macro_rules! m { ($e:expr) => { $e } }
fn main() {
@@ -605,10 +612,10 @@ fn main() {
#[test]
fn postfix_completion_for_references() {
- check_edit("dbg", r#"fn main() { &&42.$0 }"#, r#"fn main() { dbg!(&&42) }"#);
- check_edit("refm", r#"fn main() { &&42.$0 }"#, r#"fn main() { &&&mut 42 }"#);
+ check_edit("&&42.dbg", r#"fn main() { &&42.$0 }"#, r#"fn main() { dbg!(&&42) }"#);
+ check_edit("42.refm", r#"fn main() { &&42.$0 }"#, r#"fn main() { &&&mut 42 }"#);
check_edit(
- "ifl",
+ "bar.ifl",
r#"
//- minicore: option
fn main() {
@@ -629,35 +636,39 @@ fn main() {
#[test]
fn postfix_completion_for_unsafe() {
- check_edit("unsafe", r#"fn main() { foo.$0 }"#, r#"fn main() { unsafe { foo } }"#);
- check_edit("unsafe", r#"fn main() { { foo }.$0 }"#, r#"fn main() { unsafe { foo } }"#);
+ check_edit("foo.unsafe", r#"fn main() { foo.$0 }"#, r#"fn main() { unsafe { foo } }"#);
check_edit(
- "unsafe",
+ "{ foo }.unsafe",
+ r#"fn main() { { foo }.$0 }"#,
+ r#"fn main() { unsafe { foo } }"#,
+ );
+ check_edit(
+ "if x { foo }.unsafe",
r#"fn main() { if x { foo }.$0 }"#,
r#"fn main() { unsafe { if x { foo } } }"#,
);
check_edit(
- "unsafe",
+ "loop { foo }.unsafe",
r#"fn main() { loop { foo }.$0 }"#,
r#"fn main() { unsafe { loop { foo } } }"#,
);
check_edit(
- "unsafe",
+ "if true {}.unsafe",
r#"fn main() { if true {}.$0 }"#,
r#"fn main() { unsafe { if true {} } }"#,
);
check_edit(
- "unsafe",
+ "while true {}.unsafe",
r#"fn main() { while true {}.$0 }"#,
r#"fn main() { unsafe { while true {} } }"#,
);
check_edit(
- "unsafe",
+ "for i in 0..10 {}.unsafe",
r#"fn main() { for i in 0..10 {}.$0 }"#,
r#"fn main() { unsafe { for i in 0..10 {} } }"#,
);
check_edit(
- "unsafe",
+ "if true {1} else {2}.unsafe",
r#"fn main() { let x = if true {1} else {2}.$0 }"#,
r#"fn main() { let x = unsafe { if true {1} else {2} } }"#,
);
@@ -687,7 +698,7 @@ fn main() {
check_edit_with_config(
config.clone(),
- "break",
+ "42.break",
r#"
//- minicore: try
fn main() { 42.$0 }
@@ -706,7 +717,7 @@ fn main() { ControlFlow::Break(42) }
// what users would see. Unescaping happens thereafter.
check_edit_with_config(
config.clone(),
- "break",
+ r#"'\\\\'.break"#,
r#"
//- minicore: try
fn main() { '\\'.$0 }
@@ -720,7 +731,10 @@ fn main() { ControlFlow::Break('\\\\') }
check_edit_with_config(
config,
- "break",
+ r#"match true {
+ true => "\${1:placeholder}",
+ false => "\\\$",
+ }.break"#,
r#"
//- minicore: try
fn main() {
@@ -746,39 +760,47 @@ fn main() {
#[test]
fn postfix_completion_for_format_like_strings() {
check_edit(
- "format",
+ r#""{some_var:?}".format"#,
r#"fn main() { "{some_var:?}".$0 }"#,
r#"fn main() { format!("{some_var:?}") }"#,
);
check_edit(
- "panic",
+ r#""Panic with {a}".panic"#,
r#"fn main() { "Panic with {a}".$0 }"#,
r#"fn main() { panic!("Panic with {a}") }"#,
);
check_edit(
- "println",
+ r#""{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".println"#,
r#"fn main() { "{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".$0 }"#,
r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }) }"#,
);
check_edit(
- "loge",
+ r#""{2+2}".loge"#,
r#"fn main() { "{2+2}".$0 }"#,
r#"fn main() { log::error!("{}", 2+2) }"#,
);
check_edit(
- "logt",
+ r#""{2+2}".logt"#,
r#"fn main() { "{2+2}".$0 }"#,
r#"fn main() { log::trace!("{}", 2+2) }"#,
);
check_edit(
- "logd",
+ r#""{2+2}".logd"#,
r#"fn main() { "{2+2}".$0 }"#,
r#"fn main() { log::debug!("{}", 2+2) }"#,
);
- check_edit("logi", r#"fn main() { "{2+2}".$0 }"#, r#"fn main() { log::info!("{}", 2+2) }"#);
- check_edit("logw", r#"fn main() { "{2+2}".$0 }"#, r#"fn main() { log::warn!("{}", 2+2) }"#);
check_edit(
- "loge",
+ r#""{2+2}".logi"#,
+ r#"fn main() { "{2+2}".$0 }"#,
+ r#"fn main() { log::info!("{}", 2+2) }"#,
+ );
+ check_edit(
+ r#""{2+2}".logw"#,
+ r#"fn main() { "{2+2}".$0 }"#,
+ r#"fn main() { log::warn!("{}", 2+2) }"#,
+ );
+ check_edit(
+ r#""{2+2}".loge"#,
r#"fn main() { "{2+2}".$0 }"#,
r#"fn main() { log::error!("{}", 2+2) }"#,
);
@@ -800,21 +822,21 @@ fn main() {
check_edit_with_config(
CompletionConfig { snippets: vec![snippet.clone()], ..TEST_CONFIG },
- "ok",
+ "&&42.ok",
r#"fn main() { &&42.o$0 }"#,
r#"fn main() { Ok(&&42) }"#,
);
check_edit_with_config(
CompletionConfig { snippets: vec![snippet.clone()], ..TEST_CONFIG },
- "ok",
+ "&&42.ok",
r#"fn main() { &&42.$0 }"#,
r#"fn main() { Ok(&&42) }"#,
);
check_edit_with_config(
CompletionConfig { snippets: vec![snippet], ..TEST_CONFIG },
- "ok",
+ "&a.a.ok",
r#"
struct A {
a: i32,
diff --git a/crates/ide-completion/src/completions/postfix/format_like.rs b/crates/ide-completion/src/completions/postfix/format_like.rs
index fd50fd4e8c..8eb6940350 100644
--- a/crates/ide-completion/src/completions/postfix/format_like.rs
+++ b/crates/ide-completion/src/completions/postfix/format_like.rs
@@ -48,10 +48,11 @@ pub(crate) fn add_format_like_completions(
cap: SnippetCap,
receiver_text: &ast::String,
) {
- let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, dot_receiver) {
- Some(it) => it,
- None => return,
- };
+ let postfix_snippet =
+ match build_postfix_snippet_builder(ctx, cap, dot_receiver, receiver_text.text()) {
+ Some(it) => it,
+ None => return,
+ };
if let Ok((mut out, mut exprs)) = parse_format_exprs(receiver_text.text()) {
// Escape any snippet bits in the out text and any of the exprs.