Support else completion for more expressions
- Support else completion in ArrayExpr, ReturnExpr and PrefixExpr etc
- Support else completion after MatchArm expression
Before this PR, the else branch could not be completed in most expressions
Example
---
```rust
fn foo() -> [i32; 1] {
[if true {
2
} $0]
}
```
->
```rust
fn foo() -> [i32; 1] {
[if true {
2
} else {
$0
}]
}
```
---
```rust
fn foo() -> i32 {
match () {
() => if true {
2
} $0
}
}
```
->
```rust
fn foo() -> i32 {
match () {
() => if true {
2
} else {
$0
}
}
}
```
This commit is contained in:
@@ -42,6 +42,11 @@ pub(crate) fn complete_pattern(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pattern_ctx.after_if_expr {
|
||||||
|
add_keyword("else", "else {\n $0\n}");
|
||||||
|
add_keyword("else if", "else if $1 {\n $0\n}");
|
||||||
|
}
|
||||||
|
|
||||||
if pattern_ctx.record_pat.is_some() {
|
if pattern_ctx.record_pat.is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -279,6 +279,7 @@ pub(crate) struct PatternContext {
|
|||||||
pub(crate) param_ctx: Option<ParamContext>,
|
pub(crate) param_ctx: Option<ParamContext>,
|
||||||
pub(crate) has_type_ascription: bool,
|
pub(crate) has_type_ascription: bool,
|
||||||
pub(crate) should_suggest_name: bool,
|
pub(crate) should_suggest_name: bool,
|
||||||
|
pub(crate) after_if_expr: bool,
|
||||||
pub(crate) parent_pat: Option<ast::Pat>,
|
pub(crate) parent_pat: Option<ast::Pat>,
|
||||||
pub(crate) ref_token: Option<SyntaxToken>,
|
pub(crate) ref_token: Option<SyntaxToken>,
|
||||||
pub(crate) mut_token: Option<SyntaxToken>,
|
pub(crate) mut_token: Option<SyntaxToken>,
|
||||||
|
|||||||
@@ -999,10 +999,6 @@ fn classify_name_ref<'db>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let after_if_expr = |node: SyntaxNode| {
|
|
||||||
let prev_expr = prev_expr(node);
|
|
||||||
matches!(prev_expr, Some(ast::Expr::IfExpr(_)))
|
|
||||||
};
|
|
||||||
let after_incomplete_let = |node: SyntaxNode| {
|
let after_incomplete_let = |node: SyntaxNode| {
|
||||||
prev_expr(node).and_then(|it| it.syntax().parent()).and_then(ast::LetStmt::cast)
|
prev_expr(node).and_then(|it| it.syntax().parent()).and_then(ast::LetStmt::cast)
|
||||||
};
|
};
|
||||||
@@ -1242,7 +1238,7 @@ fn classify_name_ref<'db>(
|
|||||||
let it = expr.syntax();
|
let it = expr.syntax();
|
||||||
let in_block_expr = is_in_block(it);
|
let in_block_expr = is_in_block(it);
|
||||||
let (in_loop_body, innermost_breakable) = is_in_breakable(it).unzip();
|
let (in_loop_body, innermost_breakable) = is_in_breakable(it).unzip();
|
||||||
let after_if_expr = after_if_expr(it.clone());
|
let after_if_expr = is_after_if_expr(it.clone());
|
||||||
let ref_expr_parent =
|
let ref_expr_parent =
|
||||||
path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
|
path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
|
||||||
let after_amp = non_trivia_sibling(it.clone().into(), Direction::Prev)
|
let after_amp = non_trivia_sibling(it.clone().into(), Direction::Prev)
|
||||||
@@ -1763,6 +1759,7 @@ fn pattern_context_for(
|
|||||||
param_ctx,
|
param_ctx,
|
||||||
has_type_ascription,
|
has_type_ascription,
|
||||||
should_suggest_name,
|
should_suggest_name,
|
||||||
|
after_if_expr: is_after_if_expr(pat.syntax().clone()),
|
||||||
parent_pat: pat.syntax().parent().and_then(ast::Pat::cast),
|
parent_pat: pat.syntax().parent().and_then(ast::Pat::cast),
|
||||||
mut_token,
|
mut_token,
|
||||||
ref_token,
|
ref_token,
|
||||||
@@ -1933,6 +1930,18 @@ fn has_in_newline_expr_first(node: &SyntaxNode) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_after_if_expr(node: SyntaxNode) -> bool {
|
||||||
|
let node = match node.parent().and_then(Either::<ast::ExprStmt, ast::MatchArm>::cast) {
|
||||||
|
Some(stmt) => stmt.syntax().clone(),
|
||||||
|
None => node,
|
||||||
|
};
|
||||||
|
let prev_sibling =
|
||||||
|
non_trivia_sibling(node.into(), Direction::Prev).and_then(NodeOrToken::into_node);
|
||||||
|
iter::successors(prev_sibling, |it| it.last_child_or_token()?.into_node())
|
||||||
|
.find_map(ast::IfExpr::cast)
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
fn next_non_trivia_token(e: impl Into<SyntaxElement>) -> Option<SyntaxToken> {
|
fn next_non_trivia_token(e: impl Into<SyntaxElement>) -> Option<SyntaxToken> {
|
||||||
let mut token = match e.into() {
|
let mut token = match e.into() {
|
||||||
SyntaxElement::Node(n) => n.last_token()?,
|
SyntaxElement::Node(n) => n.last_token()?,
|
||||||
|
|||||||
@@ -1869,6 +1869,298 @@ fn foo() { let x = if foo {} $0 else if true {} else {}; }
|
|||||||
sn ppd
|
sn ppd
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn foo() { [if foo {} $0]}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
fn foo() fn()
|
||||||
|
bt u32 u32
|
||||||
|
kw async
|
||||||
|
kw const
|
||||||
|
kw crate::
|
||||||
|
kw else
|
||||||
|
kw else if
|
||||||
|
kw enum
|
||||||
|
kw extern
|
||||||
|
kw false
|
||||||
|
kw fn
|
||||||
|
kw for
|
||||||
|
kw if
|
||||||
|
kw if let
|
||||||
|
kw impl
|
||||||
|
kw impl for
|
||||||
|
kw let
|
||||||
|
kw letm
|
||||||
|
kw loop
|
||||||
|
kw match
|
||||||
|
kw mod
|
||||||
|
kw return
|
||||||
|
kw self::
|
||||||
|
kw static
|
||||||
|
kw struct
|
||||||
|
kw trait
|
||||||
|
kw true
|
||||||
|
kw type
|
||||||
|
kw union
|
||||||
|
kw unsafe
|
||||||
|
kw use
|
||||||
|
kw while
|
||||||
|
kw while let
|
||||||
|
sn macro_rules
|
||||||
|
sn pd
|
||||||
|
sn ppd
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn foo() { [if foo {} el$0]}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
fn foo() fn()
|
||||||
|
bt u32 u32
|
||||||
|
kw async
|
||||||
|
kw const
|
||||||
|
kw crate::
|
||||||
|
kw else
|
||||||
|
kw else if
|
||||||
|
kw enum
|
||||||
|
kw extern
|
||||||
|
kw false
|
||||||
|
kw fn
|
||||||
|
kw for
|
||||||
|
kw if
|
||||||
|
kw if let
|
||||||
|
kw impl
|
||||||
|
kw impl for
|
||||||
|
kw let
|
||||||
|
kw letm
|
||||||
|
kw loop
|
||||||
|
kw match
|
||||||
|
kw mod
|
||||||
|
kw return
|
||||||
|
kw self::
|
||||||
|
kw static
|
||||||
|
kw struct
|
||||||
|
kw trait
|
||||||
|
kw true
|
||||||
|
kw type
|
||||||
|
kw union
|
||||||
|
kw unsafe
|
||||||
|
kw use
|
||||||
|
kw while
|
||||||
|
kw while let
|
||||||
|
sn macro_rules
|
||||||
|
sn pd
|
||||||
|
sn ppd
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn foo() { 2 + if foo {} $0 }
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
fn foo() fn()
|
||||||
|
bt u32 u32
|
||||||
|
kw async
|
||||||
|
kw const
|
||||||
|
kw crate::
|
||||||
|
kw else
|
||||||
|
kw else if
|
||||||
|
kw enum
|
||||||
|
kw extern
|
||||||
|
kw false
|
||||||
|
kw fn
|
||||||
|
kw for
|
||||||
|
kw if
|
||||||
|
kw if let
|
||||||
|
kw impl
|
||||||
|
kw impl for
|
||||||
|
kw let
|
||||||
|
kw letm
|
||||||
|
kw loop
|
||||||
|
kw match
|
||||||
|
kw mod
|
||||||
|
kw return
|
||||||
|
kw self::
|
||||||
|
kw static
|
||||||
|
kw struct
|
||||||
|
kw trait
|
||||||
|
kw true
|
||||||
|
kw type
|
||||||
|
kw union
|
||||||
|
kw unsafe
|
||||||
|
kw use
|
||||||
|
kw while
|
||||||
|
kw while let
|
||||||
|
sn macro_rules
|
||||||
|
sn pd
|
||||||
|
sn ppd
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn foo() { -if foo {} $0 }
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
fn foo() fn()
|
||||||
|
bt u32 u32
|
||||||
|
kw async
|
||||||
|
kw const
|
||||||
|
kw crate::
|
||||||
|
kw else
|
||||||
|
kw else if
|
||||||
|
kw enum
|
||||||
|
kw extern
|
||||||
|
kw false
|
||||||
|
kw fn
|
||||||
|
kw for
|
||||||
|
kw if
|
||||||
|
kw if let
|
||||||
|
kw impl
|
||||||
|
kw impl for
|
||||||
|
kw let
|
||||||
|
kw letm
|
||||||
|
kw loop
|
||||||
|
kw match
|
||||||
|
kw mod
|
||||||
|
kw return
|
||||||
|
kw self::
|
||||||
|
kw static
|
||||||
|
kw struct
|
||||||
|
kw trait
|
||||||
|
kw true
|
||||||
|
kw type
|
||||||
|
kw union
|
||||||
|
kw unsafe
|
||||||
|
kw use
|
||||||
|
kw while
|
||||||
|
kw while let
|
||||||
|
sn macro_rules
|
||||||
|
sn pd
|
||||||
|
sn ppd
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn foo() { &mut if foo {} $0 }
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
fn foo() fn()
|
||||||
|
bt u32 u32
|
||||||
|
kw async
|
||||||
|
kw const
|
||||||
|
kw crate::
|
||||||
|
kw else
|
||||||
|
kw else if
|
||||||
|
kw enum
|
||||||
|
kw extern
|
||||||
|
kw false
|
||||||
|
kw fn
|
||||||
|
kw for
|
||||||
|
kw if
|
||||||
|
kw if let
|
||||||
|
kw impl
|
||||||
|
kw impl for
|
||||||
|
kw let
|
||||||
|
kw letm
|
||||||
|
kw loop
|
||||||
|
kw match
|
||||||
|
kw mod
|
||||||
|
kw return
|
||||||
|
kw self::
|
||||||
|
kw static
|
||||||
|
kw struct
|
||||||
|
kw trait
|
||||||
|
kw true
|
||||||
|
kw type
|
||||||
|
kw union
|
||||||
|
kw unsafe
|
||||||
|
kw use
|
||||||
|
kw while
|
||||||
|
kw while let
|
||||||
|
sn macro_rules
|
||||||
|
sn pd
|
||||||
|
sn ppd
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn foo() { return if foo {} $0 }
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
fn foo() fn()
|
||||||
|
bt u32 u32
|
||||||
|
kw async
|
||||||
|
kw const
|
||||||
|
kw crate::
|
||||||
|
kw else
|
||||||
|
kw else if
|
||||||
|
kw enum
|
||||||
|
kw extern
|
||||||
|
kw false
|
||||||
|
kw fn
|
||||||
|
kw for
|
||||||
|
kw if
|
||||||
|
kw if let
|
||||||
|
kw impl
|
||||||
|
kw impl for
|
||||||
|
kw let
|
||||||
|
kw letm
|
||||||
|
kw loop
|
||||||
|
kw match
|
||||||
|
kw mod
|
||||||
|
kw return
|
||||||
|
kw self::
|
||||||
|
kw static
|
||||||
|
kw struct
|
||||||
|
kw trait
|
||||||
|
kw true
|
||||||
|
kw type
|
||||||
|
kw union
|
||||||
|
kw unsafe
|
||||||
|
kw use
|
||||||
|
kw while
|
||||||
|
kw while let
|
||||||
|
sn macro_rules
|
||||||
|
sn pd
|
||||||
|
sn ppd
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn foo() { match () { () => if foo {} $0 } }
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
kw else
|
||||||
|
kw else if
|
||||||
|
kw mut
|
||||||
|
kw ref
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn foo() { match () { () => if foo {} $0, } }
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
kw else
|
||||||
|
kw else if
|
||||||
|
kw mut
|
||||||
|
kw ref
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn foo() { match () { () => if foo {} $0, _ => (), } }
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
kw else
|
||||||
|
kw else if
|
||||||
|
kw mut
|
||||||
|
kw ref
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
// FIXME: support else completion after ast::RecordExprField
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user