Auto merge of #17431 - roife:fix-issue-17428, r=Veykril

feat: add space after specific keywords in completion

fix #17428.

When completing some specific keywords, it would be convenient if r-a could automatically add a space afterwards.

This PR implements this feature for the following keywords:

- Visibility: `pub`, `pub(crate)`, `pub(super)`, `pub(in xxx)`
- Pattern: `ref` / `mut`
- Others: `unsafe` / `for` / `where`
This commit is contained in:
bors 2024-06-19 08:26:32 +00:00
commit 50ba0c0d56
9 changed files with 193 additions and 24 deletions

View File

@ -20,9 +20,9 @@ pub(crate) fn complete_field_list_tuple_variant(
} = path_ctx } = path_ctx
{ {
let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet); let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
add_keyword("pub(crate)", "pub(crate)"); add_keyword("pub(crate)", "pub(crate) $0");
add_keyword("pub(super)", "pub(super)"); add_keyword("pub(super)", "pub(super) $0");
add_keyword("pub", "pub"); add_keyword("pub", "pub $0");
} }
} }
@ -32,8 +32,8 @@ pub(crate) fn complete_field_list_record_variant(
) { ) {
if ctx.qualifier_ctx.vis_node.is_none() { if ctx.qualifier_ctx.vis_node.is_none() {
let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet); let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
add_keyword("pub(crate)", "pub(crate)"); add_keyword("pub(crate)", "pub(crate) $0");
add_keyword("pub(super)", "pub(super)"); add_keyword("pub(super)", "pub(super) $0");
add_keyword("pub", "pub"); add_keyword("pub", "pub $0");
} }
} }

View File

@ -79,7 +79,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
let in_trait = matches!(kind, Some(ItemListKind::Trait)); let in_trait = matches!(kind, Some(ItemListKind::Trait));
let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl(_))); let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl(_)));
let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl)); let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl));
let no_qualifiers = ctx.qualifier_ctx.vis_node.is_none(); let no_vis_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
let in_block = kind.is_none(); let in_block = kind.is_none();
if !in_trait_impl { if !in_trait_impl {
@ -89,7 +89,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
} }
if in_item_list { if in_item_list {
add_keyword("trait", "trait $1 {\n $0\n}"); add_keyword("trait", "trait $1 {\n $0\n}");
if no_qualifiers { if no_vis_qualifiers {
add_keyword("impl", "impl $1 {\n $0\n}"); add_keyword("impl", "impl $1 {\n $0\n}");
} }
} }
@ -104,15 +104,15 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
add_keyword("trait", "trait $1 {\n $0\n}"); add_keyword("trait", "trait $1 {\n $0\n}");
add_keyword("union", "union $1 {\n $0\n}"); add_keyword("union", "union $1 {\n $0\n}");
add_keyword("use", "use $0"); add_keyword("use", "use $0");
if no_qualifiers { if no_vis_qualifiers {
add_keyword("impl", "impl $1 {\n $0\n}"); add_keyword("impl", "impl $1 {\n $0\n}");
} }
} }
if !in_trait && !in_block && no_qualifiers { if !in_trait && !in_block && no_vis_qualifiers {
add_keyword("pub(crate)", "pub(crate)"); add_keyword("pub(crate)", "pub(crate) $0");
add_keyword("pub(super)", "pub(super)"); add_keyword("pub(super)", "pub(super) $0");
add_keyword("pub", "pub"); add_keyword("pub", "pub $0");
} }
if in_extern_block { if in_extern_block {
@ -126,7 +126,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
} }
add_keyword("fn", "fn $1($2) {\n $0\n}"); add_keyword("fn", "fn $1($2) {\n $0\n}");
add_keyword("unsafe", "unsafe"); add_keyword("unsafe", "unsafe $0");
add_keyword("const", "const $0"); add_keyword("const", "const $0");
} }
} }

View File

@ -14,9 +14,9 @@ pub(crate) fn complete_for_and_where(
match keyword_item { match keyword_item {
Item::Impl(it) => { Item::Impl(it) => {
if it.for_token().is_none() && it.trait_().is_none() && it.self_ty().is_some() { if it.for_token().is_none() && it.trait_().is_none() && it.self_ty().is_some() {
add_keyword("for", "for"); add_keyword("for", "for $0");
} }
add_keyword("where", "where"); add_keyword("where", "where $0");
} }
Item::Enum(_) Item::Enum(_)
| Item::Fn(_) | Item::Fn(_)
@ -24,7 +24,7 @@ pub(crate) fn complete_for_and_where(
| Item::Trait(_) | Item::Trait(_)
| Item::TypeAlias(_) | Item::TypeAlias(_)
| Item::Union(_) => { | Item::Union(_) => {
add_keyword("where", "where"); add_keyword("where", "where $0");
} }
_ => (), _ => (),
} }

View File

@ -14,25 +14,27 @@ pub(crate) fn complete_pattern(
ctx: &CompletionContext<'_>, ctx: &CompletionContext<'_>,
pattern_ctx: &PatternContext, pattern_ctx: &PatternContext,
) { ) {
let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
match pattern_ctx.parent_pat.as_ref() { match pattern_ctx.parent_pat.as_ref() {
Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (), Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (),
Some(Pat::RefPat(r)) => { Some(Pat::RefPat(r)) => {
if r.mut_token().is_none() { if r.mut_token().is_none() {
acc.add_keyword(ctx, "mut"); add_keyword("mut", "mut $0");
} }
} }
_ => { _ => {
let tok = ctx.token.text_range().start(); let tok = ctx.token.text_range().start();
match (pattern_ctx.ref_token.as_ref(), pattern_ctx.mut_token.as_ref()) { match (pattern_ctx.ref_token.as_ref(), pattern_ctx.mut_token.as_ref()) {
(None, None) => { (None, None) => {
acc.add_keyword(ctx, "ref"); add_keyword("ref", "ref $0");
acc.add_keyword(ctx, "mut"); add_keyword("mut", "mut $0");
} }
(None, Some(m)) if tok < m.text_range().start() => { (None, Some(m)) if tok < m.text_range().start() => {
acc.add_keyword(ctx, "ref"); add_keyword("ref", "ref $0");
} }
(Some(r), None) if tok > r.text_range().end() => { (Some(r), None) if tok > r.text_range().end() => {
acc.add_keyword(ctx, "mut"); add_keyword("mut", "mut $0");
} }
_ => (), _ => (),
} }

View File

@ -668,7 +668,7 @@ fn main() {
check_edit( check_edit(
"unsafe", "unsafe",
r#"fn main() { let x = true else {panic!()}.$0}"#, r#"fn main() { let x = true else {panic!()}.$0}"#,
r#"fn main() { let x = true else {panic!()}.unsafe}"#, r#"fn main() { let x = true else {panic!()}.unsafe $0}"#,
); );
} }

View File

@ -33,7 +33,7 @@ pub(crate) fn complete_vis_path(
Qualified::No => { Qualified::No => {
if !has_in_token { if !has_in_token {
cov_mark::hit!(kw_completion_in); cov_mark::hit!(kw_completion_in);
acc.add_keyword(ctx, "in"); acc.add_keyword_snippet(ctx, "in", "in $0");
} }
acc.add_nameref_keywords(ctx); acc.add_nameref_keywords(ctx);
} }

View File

@ -6,6 +6,8 @@ use expect_test::{expect, Expect};
use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; use crate::tests::{completion_list, BASE_ITEMS_FIXTURE};
use super::check_edit;
fn check(ra_fixture: &str, expect: Expect) { fn check(ra_fixture: &str, expect: Expect) {
let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}")); let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}"));
expect.assert_eq(&actual) expect.assert_eq(&actual)
@ -152,3 +154,90 @@ struct Foo {
"#]], "#]],
) )
} }
#[test]
fn add_space_after_vis_kw() {
check_edit(
"pub(crate)",
r"
$0
",
r#"
pub(crate) $0
"#,
);
check_edit(
"pub",
r"
$0
",
r#"
pub $0
"#,
);
check_edit(
"pub(super)",
r"
$0
",
r#"
pub(super) $0
"#,
);
check_edit(
"in",
r"
pub($0)
",
r#"
pub(in $0)
"#,
);
}
#[test]
fn add_space_after_unsafe_kw() {
check_edit(
"unsafe",
r"
$0
",
r#"
unsafe $0
"#,
);
}
#[test]
fn add_space_after_for_where_kw() {
check_edit(
"for",
r#"
struct S {}
impl Copy $0
"#,
r#"
struct S {}
impl Copy for $0
"#,
);
check_edit(
"where",
r#"
struct S {}
impl Copy for S $0
"#,
r#"
struct S {}
impl Copy for S where $0
"#,
);
}

View File

@ -819,3 +819,34 @@ pub enum Enum {
"#]], "#]],
); );
} }
#[test]
fn add_space_after_mut_ref_kw() {
check_edit(
"mut",
r#"
fn foo() {
let $0
}
"#,
r#"
fn foo() {
let mut $0
}
"#,
);
check_edit(
"ref",
r#"
fn foo() {
let $0
}
"#,
r#"
fn foo() {
let ref $0
}
"#,
);
}

View File

@ -2,6 +2,8 @@ use expect_test::{expect, Expect};
use crate::tests::completion_list; use crate::tests::completion_list;
use super::check_edit;
fn check(ra_fixture: &str, expect: Expect) { fn check(ra_fixture: &str, expect: Expect) {
let actual = completion_list(ra_fixture); let actual = completion_list(ra_fixture);
expect.assert_eq(&actual); expect.assert_eq(&actual);
@ -301,3 +303,48 @@ fn foo() {
expect![[r#""#]], expect![[r#""#]],
) )
} }
#[test]
fn add_space_after_vis_kw() {
check_edit(
"pub(crate)",
r"
pub(crate) struct S {
$0
}
",
r#"
pub(crate) struct S {
pub(crate) $0
}
"#,
);
check_edit(
"pub",
r"
pub struct S {
$0
}
",
r#"
pub struct S {
pub $0
}
"#,
);
check_edit(
"pub(super)",
r"
pub(super) struct S {
$0
}
",
r#"
pub(super) struct S {
pub(super) $0
}
"#,
);
}