@@ -33,7 +33,8 @@ use crate::SourceChange;
33
33
34
34
pub ( crate ) use on_enter:: on_enter;
35
35
36
- pub ( crate ) const TRIGGER_CHARS : & str = ".=>" ;
36
+ // Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
37
+ pub ( crate ) const TRIGGER_CHARS : & str = ".=>{" ;
37
38
38
39
// Feature: On Typing Assists
39
40
//
@@ -70,10 +71,47 @@ fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) ->
70
71
'.' => on_dot_typed ( file, offset) ,
71
72
'=' => on_eq_typed ( file, offset) ,
72
73
'>' => on_arrow_typed ( file, offset) ,
74
+ '{' => on_opening_brace_typed ( file, offset) ,
73
75
_ => unreachable ! ( ) ,
74
76
}
75
77
}
76
78
79
+ /// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a
80
+ /// block.
81
+ fn on_opening_brace_typed ( file : & SourceFile , offset : TextSize ) -> Option < TextEdit > {
82
+ assert_eq ! ( file. syntax( ) . text( ) . char_at( offset) , Some ( '{' ) ) ;
83
+ let brace_token = file. syntax ( ) . token_at_offset ( offset) . right_biased ( ) ?;
84
+ let block = ast:: BlockExpr :: cast ( brace_token. parent ( ) ?) ?;
85
+
86
+ // We expect a block expression enclosing exactly 1 preexisting expression. It can be parsed as
87
+ // either the trailing expr or an ExprStmt.
88
+ let offset = {
89
+ match block. tail_expr ( ) {
90
+ Some ( expr) => {
91
+ if block. statements ( ) . next ( ) . is_some ( ) {
92
+ return None ;
93
+ }
94
+ expr. syntax ( ) . text_range ( ) . end ( )
95
+ }
96
+ None => {
97
+ if block. statements ( ) . count ( ) != 1 {
98
+ return None ;
99
+ }
100
+
101
+ match block. statements ( ) . next ( ) ? {
102
+ ast:: Stmt :: ExprStmt ( it) => {
103
+ // Use the expression span to place `}` before the `;`
104
+ it. expr ( ) ?. syntax ( ) . text_range ( ) . end ( )
105
+ }
106
+ _ => return None ,
107
+ }
108
+ }
109
+ }
110
+ } ;
111
+
112
+ Some ( TextEdit :: insert ( offset, "}" . to_string ( ) ) )
113
+ }
114
+
77
115
/// Returns an edit which should be applied after `=` was typed. Primarily,
78
116
/// this works when adding `let =`.
79
117
// FIXME: use a snippet completion instead of this hack here.
@@ -373,4 +411,11 @@ fn main() {
373
411
fn adds_space_after_return_type ( ) {
374
412
type_char ( '>' , "fn foo() -$0{ 92 }" , "fn foo() -> { 92 }" )
375
413
}
414
+
415
+ #[ test]
416
+ fn adds_closing_brace ( ) {
417
+ type_char ( '{' , r"fn f() { match () { _ => $0() } }" , r"fn f() { match () { _ => {()} } }" ) ;
418
+ type_char ( '{' , r"fn f() { $0(); }" , r"fn f() { {()}; }" ) ;
419
+ type_char ( '{' , r"fn f() { let x = $0(); }" , r"fn f() { let x = {()}; }" ) ;
420
+ }
376
421
}
0 commit comments