Skip to content

Commit fd109fb

Browse files
Merge #8784
8784: feat: auto-insert `}` when typing `{` in use item r=jonas-schievink a=jonas-schievink ![Peek 2021-05-09 22-14](https://user-images.githubusercontent.com/1786438/117585742-45983f80-b114-11eb-80fc-d44f480fd012.gif) cc #8636 bors r+ Co-authored-by: Jonas Schievink <[email protected]>
2 parents 75a5c0a + 64f97fb commit fd109fb

File tree

1 file changed

+131
-19
lines changed

1 file changed

+131
-19
lines changed

crates/ide/src/typing.rs

Lines changed: 131 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ fn on_char_typed_inner(
8888
}
8989

9090
/// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a
91-
/// block.
91+
/// block, or a part of a `use` item.
9292
fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<TextEdit> {
9393
if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some('{')) {
9494
return None;
@@ -99,30 +99,59 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<
9999
// Remove the `{` to get a better parse tree, and reparse
100100
let file = file.reparse(&Indel::delete(brace_token.text_range()));
101101

102-
let mut expr: ast::Expr = find_node_at_offset(file.tree().syntax(), offset)?;
103-
if expr.syntax().text_range().start() != offset {
104-
return None;
102+
if let Some(edit) = brace_expr(&file.tree(), offset) {
103+
return Some(edit);
105104
}
106105

107-
// Enclose the outermost expression starting at `offset`
108-
while let Some(parent) = expr.syntax().parent() {
109-
if parent.text_range().start() != expr.syntax().text_range().start() {
110-
break;
111-
}
106+
if let Some(edit) = brace_use_path(&file.tree(), offset) {
107+
return Some(edit);
108+
}
112109

113-
match ast::Expr::cast(parent) {
114-
Some(parent) => expr = parent,
115-
None => break,
110+
return None;
111+
112+
fn brace_use_path(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
113+
let segment: ast::PathSegment = find_node_at_offset(file.syntax(), offset)?;
114+
if segment.syntax().text_range().start() != offset {
115+
return None;
116116
}
117-
}
118117

119-
// If it's a statement in a block, we don't know how many statements should be included
120-
if ast::ExprStmt::can_cast(expr.syntax().parent()?.kind()) {
121-
return None;
118+
let tree: ast::UseTree = find_node_at_offset(file.syntax(), offset)?;
119+
120+
Some(TextEdit::insert(
121+
tree.syntax().text_range().end() + TextSize::of("{"),
122+
"}".to_string(),
123+
))
122124
}
123125

124-
// Insert `}` right after the expression.
125-
Some(TextEdit::insert(expr.syntax().text_range().end() + TextSize::of("{"), "}".to_string()))
126+
fn brace_expr(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
127+
let mut expr: ast::Expr = find_node_at_offset(file.syntax(), offset)?;
128+
if expr.syntax().text_range().start() != offset {
129+
return None;
130+
}
131+
132+
// Enclose the outermost expression starting at `offset`
133+
while let Some(parent) = expr.syntax().parent() {
134+
if parent.text_range().start() != expr.syntax().text_range().start() {
135+
break;
136+
}
137+
138+
match ast::Expr::cast(parent) {
139+
Some(parent) => expr = parent,
140+
None => break,
141+
}
142+
}
143+
144+
// If it's a statement in a block, we don't know how many statements should be included
145+
if ast::ExprStmt::can_cast(expr.syntax().parent()?.kind()) {
146+
return None;
147+
}
148+
149+
// Insert `}` right after the expression.
150+
Some(TextEdit::insert(
151+
expr.syntax().text_range().end() + TextSize::of("{"),
152+
"}".to_string(),
153+
))
154+
}
126155
}
127156

128157
/// Returns an edit which should be applied after `=` was typed. Primarily,
@@ -440,7 +469,7 @@ fn foo() -> { 92 }
440469
}
441470

442471
#[test]
443-
fn adds_closing_brace() {
472+
fn adds_closing_brace_for_expr() {
444473
type_char(
445474
'{',
446475
r#"
@@ -519,4 +548,87 @@ fn f() {
519548
"#,
520549
);
521550
}
551+
552+
#[test]
553+
fn adds_closing_brace_for_use_tree() {
554+
type_char(
555+
'{',
556+
r#"
557+
use some::$0Path;
558+
"#,
559+
r#"
560+
use some::{Path};
561+
"#,
562+
);
563+
type_char(
564+
'{',
565+
r#"
566+
use some::{Path, $0Other};
567+
"#,
568+
r#"
569+
use some::{Path, {Other}};
570+
"#,
571+
);
572+
type_char(
573+
'{',
574+
r#"
575+
use some::{$0Path, Other};
576+
"#,
577+
r#"
578+
use some::{{Path}, Other};
579+
"#,
580+
);
581+
type_char(
582+
'{',
583+
r#"
584+
use some::path::$0to::Item;
585+
"#,
586+
r#"
587+
use some::path::{to::Item};
588+
"#,
589+
);
590+
type_char(
591+
'{',
592+
r#"
593+
use some::$0path::to::Item;
594+
"#,
595+
r#"
596+
use some::{path::to::Item};
597+
"#,
598+
);
599+
type_char(
600+
'{',
601+
r#"
602+
use $0some::path::to::Item;
603+
"#,
604+
r#"
605+
use {some::path::to::Item};
606+
"#,
607+
);
608+
type_char(
609+
'{',
610+
r#"
611+
use some::path::$0to::{Item};
612+
"#,
613+
r#"
614+
use some::path::{to::{Item}};
615+
"#,
616+
);
617+
type_char(
618+
'{',
619+
r#"
620+
use $0Thing as _;
621+
"#,
622+
r#"
623+
use {Thing as _};
624+
"#,
625+
);
626+
627+
type_char_noop(
628+
'{',
629+
r#"
630+
use some::pa$0th::to::Item;
631+
"#,
632+
);
633+
}
522634
}

0 commit comments

Comments
 (0)