Unnamed repository; edit this file 'description' to name the repository.
Fix complete after `extern`, add `crate` completion
Example
---
```rust
extern "C" $0
```
**Before this PR**
Can't be completion
**After this PR**
```text
kw async
kw const
kw enum
kw fn
kw impl
kw impl for
kw mod
kw pub
kw pub(crate)
kw pub(super)
kw static
kw struct
kw trait
kw type
kw union
kw unsafe
kw use
```
---
```rust
extern $0
```
**Before this PR**
Can't be completion
**After this PR**
```rust
extern crate $0;
```
| -rw-r--r-- | crates/ide-completion/src/completions/item_list.rs | 10 | ||||
| -rw-r--r-- | crates/ide-completion/src/context.rs | 2 | ||||
| -rw-r--r-- | crates/ide-completion/src/context/analysis.rs | 1 | ||||
| -rw-r--r-- | crates/ide-completion/src/tests/item_list.rs | 99 |
4 files changed, 110 insertions, 2 deletions
diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs index 6c001bd16b..39048e4400 100644 --- a/crates/ide-completion/src/completions/item_list.rs +++ b/crates/ide-completion/src/completions/item_list.rs @@ -87,6 +87,9 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option let in_block = kind.is_none(); let no_vis_qualifiers = ctx.qualifier_ctx.vis_node.is_none(); + let no_abi_qualifiers = ctx.qualifier_ctx.abi_node.is_none(); + let has_extern_kw = + ctx.qualifier_ctx.abi_node.as_ref().is_some_and(|it| it.string_token().is_none()); let has_unsafe_kw = ctx.qualifier_ctx.unsafe_tok.is_some(); let has_async_kw = ctx.qualifier_ctx.async_tok.is_some(); let has_safe_kw = ctx.qualifier_ctx.safe_tok.is_some(); @@ -118,7 +121,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option } } - if !has_async_kw && no_vis_qualifiers && in_item_list { + if !has_async_kw && no_vis_qualifiers && no_abi_qualifiers && in_item_list { add_keyword("extern", "extern $0"); } @@ -159,11 +162,14 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option add_keyword("static", "static $1: $2;"); } else { if !in_inherent_impl { - if !in_trait { + if !in_trait && no_abi_qualifiers { add_keyword("extern", "extern $0"); } add_keyword("type", "type $0"); } + if has_extern_kw { + add_keyword("crate", "crate $0;"); + } add_keyword("fn", "fn $1($2) {\n $0\n}"); add_keyword("unsafe", "unsafe $0"); diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 31a9a74aa8..23318e1d19 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -53,6 +53,7 @@ pub(crate) struct QualifierCtx { pub(crate) unsafe_tok: Option<SyntaxToken>, pub(crate) safe_tok: Option<SyntaxToken>, pub(crate) vis_node: Option<ast::Visibility>, + pub(crate) abi_node: Option<ast::Abi>, } impl QualifierCtx { @@ -61,6 +62,7 @@ impl QualifierCtx { && self.unsafe_tok.is_none() && self.safe_tok.is_none() && self.vis_node.is_none() + && self.abi_node.is_none() } } diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index e84c065336..da9464f48a 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -1628,6 +1628,7 @@ fn classify_name_ref<'db>( } } qualifier_ctx.vis_node = error_node.children().find_map(ast::Visibility::cast); + qualifier_ctx.abi_node = error_node.children().find_map(ast::Abi::cast); } if let PathKind::Item { .. } = path_ctx.kind diff --git a/crates/ide-completion/src/tests/item_list.rs b/crates/ide-completion/src/tests/item_list.rs index ac32649d4f..9afc8b49d6 100644 --- a/crates/ide-completion/src/tests/item_list.rs +++ b/crates/ide-completion/src/tests/item_list.rs @@ -177,6 +177,105 @@ fn after_visibility_unsafe() { } #[test] +fn after_abi() { + check_with_base_items( + r#"extern "C" $0"#, + expect![[r#" + kw async + kw const + kw enum + kw fn + kw impl + kw impl for + kw mod + kw pub + kw pub(crate) + kw pub(super) + kw static + kw struct + kw trait + kw type + kw union + kw unsafe + kw use + "#]], + ); + check_with_base_items( + r#"extern "C" f$0"#, + expect![[r#" + kw async + kw const + kw enum + kw fn + kw impl + kw impl for + kw mod + kw pub + kw pub(crate) + kw pub(super) + kw static + kw struct + kw trait + kw type + kw union + kw unsafe + kw use + "#]], + ); +} + +#[test] +fn after_extern_token() { + check_with_base_items( + r#"extern $0"#, + expect![[r#" + kw async + kw const + kw crate + kw enum + kw fn + kw impl + kw impl for + kw mod + kw pub + kw pub(crate) + kw pub(super) + kw static + kw struct + kw trait + kw type + kw union + kw unsafe + kw use + "#]], + ); + check_with_base_items( + r#"extern cr$0"#, + expect![[r#" + kw async + kw const + kw crate + kw enum + kw fn + kw impl + kw impl for + kw mod + kw pub + kw pub(crate) + kw pub(super) + kw static + kw struct + kw trait + kw type + kw union + kw unsafe + kw use + "#]], + ); + check_edit("crate", "extern $0", "extern crate $0;"); +} + +#[test] fn in_impl_assoc_item_list() { check_with_base_items( r#"impl Struct { $0 }"#, |