Skip to content

Commit cde2a1d

Browse files
author
Jonas Schievink
committed
Add trailing ; when typing = in assignment
1 parent 7ce2df4 commit cde2a1d

File tree

1 file changed

+95
-9
lines changed

1 file changed

+95
-9
lines changed

crates/ide/src/typing.rs

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -166,23 +166,61 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
166166
if !stdx::always!(file.syntax().text().char_at(offset) == Some('=')) {
167167
return None;
168168
}
169-
let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
170-
if let_stmt.semicolon_token().is_some() {
171-
return None;
169+
170+
if let Some(edit) = let_stmt(file, offset) {
171+
return Some(edit);
172+
}
173+
if let Some(edit) = assign_expr(file, offset) {
174+
return Some(edit);
172175
}
173-
if let Some(expr) = let_stmt.initializer() {
176+
177+
return None;
178+
179+
fn assign_expr(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
180+
let binop: ast::BinExpr = find_node_at_offset(file.syntax(), offset)?;
181+
if !matches!(binop.op_kind(), Some(ast::BinaryOp::Assignment { op: None })) {
182+
return None;
183+
}
184+
185+
if let Some(expr_stmt) = ast::ExprStmt::cast(binop.syntax().parent()?) {
186+
if expr_stmt.semicolon_token().is_some() {
187+
return None;
188+
}
189+
} else {
190+
if !ast::StmtList::can_cast(binop.syntax().parent()?.kind()) {
191+
// Parent must be `ExprStmt` or `StmtList` for `;` to be valid.
192+
return None;
193+
}
194+
}
195+
196+
let expr = binop.rhs()?;
174197
let expr_range = expr.syntax().text_range();
175198
if expr_range.contains(offset) && offset != expr_range.start() {
176199
return None;
177200
}
178201
if file.syntax().text().slice(offset..expr_range.start()).contains_char('\n') {
179202
return None;
180203
}
181-
} else {
182-
return None;
204+
let offset = expr.syntax().text_range().end();
205+
Some(TextEdit::insert(offset, ";".to_string()))
206+
}
207+
208+
fn let_stmt(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
209+
let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
210+
if let_stmt.semicolon_token().is_some() {
211+
return None;
212+
}
213+
let expr = let_stmt.initializer()?;
214+
let expr_range = expr.syntax().text_range();
215+
if expr_range.contains(offset) && offset != expr_range.start() {
216+
return None;
217+
}
218+
if file.syntax().text().slice(offset..expr_range.start()).contains_char('\n') {
219+
return None;
220+
}
221+
let offset = let_stmt.syntax().text_range().end();
222+
Some(TextEdit::insert(offset, ";".to_string()))
183223
}
184-
let offset = let_stmt.syntax().text_range().end();
185-
Some(TextEdit::insert(offset, ";".to_string()))
186224
}
187225

188226
/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately.
@@ -286,7 +324,7 @@ mod tests {
286324
}
287325

288326
#[test]
289-
fn test_on_eq_typed() {
327+
fn test_semi_after_let() {
290328
// do_check(r"
291329
// fn foo() {
292330
// let foo =$0
@@ -322,6 +360,54 @@ fn foo() {
322360
// ");
323361
}
324362

363+
#[test]
364+
fn test_semi_after_assign() {
365+
type_char(
366+
'=',
367+
r#"
368+
fn f() {
369+
i $0 0
370+
}
371+
"#,
372+
r#"
373+
fn f() {
374+
i = 0;
375+
}
376+
"#,
377+
);
378+
type_char(
379+
'=',
380+
r#"
381+
fn f() {
382+
i $0 0
383+
i
384+
}
385+
"#,
386+
r#"
387+
fn f() {
388+
i = 0;
389+
i
390+
}
391+
"#,
392+
);
393+
type_char_noop(
394+
'=',
395+
r#"
396+
fn f(x: u8) {
397+
if x $0
398+
}
399+
"#,
400+
);
401+
type_char_noop(
402+
'=',
403+
r#"
404+
fn f() {
405+
g(i $0 0);
406+
}
407+
"#,
408+
);
409+
}
410+
325411
#[test]
326412
fn indents_new_chain_call() {
327413
type_char(

0 commit comments

Comments
 (0)