Skip to content

Commit 4c14c52

Browse files
committed
Add heuristic sensing is_in_block
Example --- ```rust fn foo() -> [i32; 2] { l$0 [0, n] } ``` **Before this PR**: ```text loop~ line!(…)~ macro_rules! line ``` **After this PR**: ```text let~ loop~ letm~ line!(…)~ macro_rules! line ```
1 parent 57875bd commit 4c14c52

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed

crates/ide-completion/src/context/analysis.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,11 +1890,37 @@ fn is_in_breakable(node: &SyntaxNode) -> Option<(BreakableKind, SyntaxNode)> {
18901890
}
18911891

18921892
fn is_in_block(node: &SyntaxNode) -> bool {
1893+
if has_in_newline_expr_first(node) {
1894+
return true;
1895+
};
18931896
node.parent()
18941897
.map(|node| ast::ExprStmt::can_cast(node.kind()) || ast::StmtList::can_cast(node.kind()))
18951898
.unwrap_or(false)
18961899
}
18971900

1901+
/// Similar to `has_parens`, heuristic sensing incomplete statement before ambigiguous `Expr`
1902+
///
1903+
/// Heuristic:
1904+
///
1905+
/// If the `PathExpr` is left part of the `Expr` and there is a newline after the `PathExpr`,
1906+
/// it is considered that the `PathExpr` is not part of the `Expr`.
1907+
fn has_in_newline_expr_first(node: &SyntaxNode) -> bool {
1908+
if ast::PathExpr::can_cast(node.kind())
1909+
&& let Some(NodeOrToken::Token(next)) = node.next_sibling_or_token()
1910+
&& next.kind() == SyntaxKind::WHITESPACE
1911+
&& next.text().contains('\n')
1912+
&& let Some(stmt_like) = node
1913+
.ancestors()
1914+
.take_while(|it| it.text_range().start() == node.text_range().start())
1915+
.filter_map(Either::<ast::ExprStmt, ast::Expr>::cast)
1916+
.last()
1917+
{
1918+
stmt_like.syntax().parent().and_then(ast::StmtList::cast).is_some()
1919+
} else {
1920+
false
1921+
}
1922+
}
1923+
18981924
fn next_non_trivia_token(e: impl Into<SyntaxElement>) -> Option<SyntaxToken> {
18991925
let mut token = match e.into() {
19001926
SyntaxElement::Node(n) => n.last_token()?,

crates/ide-completion/src/tests/expression.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2946,6 +2946,173 @@ fn let_in_let_chain() {
29462946
check_edit("let", r#"fn f() { if true && $0 {} }"#, r#"fn f() { if true && let $1 = $0 {} }"#);
29472947
}
29482948

2949+
#[test]
2950+
fn let_in_previous_line_of_ambiguous_expr() {
2951+
check_edit(
2952+
"let",
2953+
r#"
2954+
fn f() {
2955+
$0
2956+
(1, 2).foo();
2957+
}"#,
2958+
r#"
2959+
fn f() {
2960+
let $1 = $0;
2961+
(1, 2).foo();
2962+
}"#,
2963+
);
2964+
2965+
check_edit(
2966+
"let",
2967+
r#"
2968+
fn f() {
2969+
$0
2970+
(1, 2)
2971+
}"#,
2972+
r#"
2973+
fn f() {
2974+
let $1 = $0;
2975+
(1, 2)
2976+
}"#,
2977+
);
2978+
2979+
check_edit(
2980+
"let",
2981+
r#"
2982+
fn f() -> i32 {
2983+
$0
2984+
-2
2985+
}"#,
2986+
r#"
2987+
fn f() -> i32 {
2988+
let $1 = $0;
2989+
-2
2990+
}"#,
2991+
);
2992+
2993+
check_edit(
2994+
"let",
2995+
r#"
2996+
fn f() -> [i32; 2] {
2997+
$0
2998+
[1, 2]
2999+
}"#,
3000+
r#"
3001+
fn f() -> [i32; 2] {
3002+
let $1 = $0;
3003+
[1, 2]
3004+
}"#,
3005+
);
3006+
3007+
check_edit(
3008+
"let",
3009+
r#"
3010+
fn f() -> [u8; 2] {
3011+
$0
3012+
*b"01"
3013+
}"#,
3014+
r#"
3015+
fn f() -> [u8; 2] {
3016+
let $1 = $0;
3017+
*b"01"
3018+
}"#,
3019+
);
3020+
3021+
check(
3022+
r#"
3023+
fn foo() {
3024+
$0
3025+
*b"01"
3026+
}"#,
3027+
expect![[r#"
3028+
fn foo() fn()
3029+
bt u32 u32
3030+
kw async
3031+
kw const
3032+
kw crate::
3033+
kw enum
3034+
kw extern
3035+
kw false
3036+
kw fn
3037+
kw for
3038+
kw if
3039+
kw if let
3040+
kw impl
3041+
kw impl for
3042+
kw let
3043+
kw letm
3044+
kw loop
3045+
kw match
3046+
kw mod
3047+
kw return
3048+
kw self::
3049+
kw static
3050+
kw struct
3051+
kw trait
3052+
kw true
3053+
kw type
3054+
kw union
3055+
kw unsafe
3056+
kw use
3057+
kw while
3058+
kw while let
3059+
sn macro_rules
3060+
sn pd
3061+
sn ppd
3062+
"#]],
3063+
);
3064+
3065+
check(
3066+
r#"
3067+
fn foo() {
3068+
match $0 {}
3069+
}"#,
3070+
expect![[r#"
3071+
fn foo() fn()
3072+
bt u32 u32
3073+
kw const
3074+
kw crate::
3075+
kw false
3076+
kw for
3077+
kw if
3078+
kw if let
3079+
kw loop
3080+
kw match
3081+
kw return
3082+
kw self::
3083+
kw true
3084+
kw unsafe
3085+
kw while
3086+
kw while let
3087+
"#]],
3088+
);
3089+
3090+
check(
3091+
r#"
3092+
fn foo() {
3093+
$0 *b"01"
3094+
}"#,
3095+
expect![[r#"
3096+
fn foo() fn()
3097+
bt u32 u32
3098+
kw const
3099+
kw crate::
3100+
kw false
3101+
kw for
3102+
kw if
3103+
kw if let
3104+
kw loop
3105+
kw match
3106+
kw return
3107+
kw self::
3108+
kw true
3109+
kw unsafe
3110+
kw while
3111+
kw while let
3112+
"#]],
3113+
);
3114+
}
3115+
29493116
#[test]
29503117
fn private_inherent_and_public_trait() {
29513118
check(

0 commit comments

Comments
 (0)