From b6d6277362366e7ddd2b355d83227041d8b6fa12 Mon Sep 17 00:00:00 2001 From: Steffen Lyngbaek Date: Mon, 9 Mar 2020 18:10:25 -0700 Subject: Completition for type name? #3418 Iterate through TupleStructPat's until a MatchArm if one exists. Store in a new is_pat_bind_and_path bool and allow the `complete_scope` to find matches. Added some tests to ensure it works in simple and nested cases. --- crates/ra_ide/src/completion/complete_scope.rs | 107 ++++++++++++++++++++- crates/ra_ide/src/completion/completion_context.rs | 16 ++- 2 files changed, 120 insertions(+), 3 deletions(-) (limited to 'crates/ra_ide') diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs index 81d3cc1b6..82842e7e3 100644 --- a/crates/ra_ide/src/completion/complete_scope.rs +++ b/crates/ra_ide/src/completion/complete_scope.rs @@ -3,7 +3,7 @@ use crate::completion::{CompletionContext, Completions}; pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { - if !ctx.is_trivial_path { + if !ctx.is_trivial_path && !ctx.is_pat_binding_and_path { return; } @@ -20,6 +20,111 @@ mod tests { do_completion(ra_fixture, CompletionKind::Reference) } + #[test] + fn nested_bind_pat_and_path() { + assert_debug_snapshot!( + do_reference_completion( + r" + enum First { + A, + B, + } + enum Second { + A(First), + B(First), + } + fn quux(x: Option>>) { + match x { + None => (), + Some(Some(Second(Fi<|>))) => (), + } + } + " + ), + @r###" + [ + CompletionItem { + label: "First", + source_range: [363; 365), + delete: [363; 365), + insert: "First", + kind: Enum, + }, + CompletionItem { + label: "Second", + source_range: [363; 365), + delete: [363; 365), + insert: "Second", + kind: Enum, + }, + CompletionItem { + label: "quux(…)", + source_range: [363; 365), + delete: [363; 365), + insert: "quux(${1:x})$0", + kind: Function, + lookup: "quux", + detail: "fn quux(x: Option>)", + }, + ] + "### + ); + } + + #[test] + fn bind_pat_and_path() { + assert_debug_snapshot!( + do_reference_completion( + r" + enum Enum { + A, + B, + } + fn quux(x: Option) { + match x { + None => (), + Some(en<|>) => (), + } + } + " + ), + @r###" + [ + CompletionItem { + label: "Enum", + source_range: [231; 233), + delete: [231; 233), + insert: "Enum", + kind: Enum, + }, + CompletionItem { + label: "None", + source_range: [231; 233), + delete: [231; 233), + insert: "None", + kind: Binding, + }, + CompletionItem { + label: "quux(…)", + source_range: [231; 233), + delete: [231; 233), + insert: "quux(${1:x})$0", + kind: Function, + lookup: "quux", + detail: "fn quux(x: Option)", + }, + CompletionItem { + label: "x", + source_range: [231; 233), + delete: [231; 233), + insert: "x", + kind: Binding, + }, + ] + "### + ); + } + #[test] fn completes_bindings_from_let() { assert_debug_snapshot!( diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 54589a2a8..d867ff6b2 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs @@ -36,6 +36,9 @@ pub(crate) struct CompletionContext<'a> { /// If a name-binding or reference to a const in a pattern. /// Irrefutable patterns (like let) are excluded. pub(super) is_pat_binding: bool, + // A bind battern which may also be part of a path. + // if let Some(En<|>) = Some(Enum::A) + pub(super) is_pat_binding_and_path: bool, /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. pub(super) is_trivial_path: bool, /// If not a trivial path, the prefix (qualifier). @@ -95,6 +98,7 @@ impl<'a> CompletionContext<'a> { impl_def: None, is_param: false, is_pat_binding: false, + is_pat_binding_and_path: false, is_trivial_path: false, path_prefix: None, after_if: false, @@ -186,12 +190,20 @@ impl<'a> CompletionContext<'a> { // suggest declaration names, see `CompletionKind::Magic`. if let Some(name) = find_node_at_offset::(&file_with_fake_ident, offset) { if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { - let parent = bind_pat.syntax().parent(); + let mut parent = bind_pat.syntax().parent(); if parent.clone().and_then(ast::MatchArm::cast).is_some() - || parent.and_then(ast::Condition::cast).is_some() + || parent.clone().and_then(ast::Condition::cast).is_some() { self.is_pat_binding = true; } + + while let Some(_) = parent.clone().and_then(ast::TupleStructPat::cast) { + parent = parent.and_then(|p| p.parent()); + if parent.clone().and_then(ast::MatchArm::cast).is_some() { + self.is_pat_binding_and_path = true; + break; + } + } } if is_node::(name.syntax()) { self.is_param = true; -- cgit v1.2.3