@@ -32,7 +32,7 @@ use crate::SourceChange;
3232pub ( crate ) use on_enter:: on_enter;
3333
3434// Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
35- pub ( crate ) const TRIGGER_CHARS : & str = ".=<>{" ;
35+ pub ( crate ) const TRIGGER_CHARS : & str = ".=<>{( " ;
3636
3737struct ExtendedTextEdit {
3838 edit : TextEdit ,
@@ -94,36 +94,49 @@ fn on_char_typed_inner(
9494 '=' => conv ( on_eq_typed ( & file. tree ( ) , offset) ) ,
9595 '<' => on_left_angle_typed ( & file. tree ( ) , offset) ,
9696 '>' => conv ( on_right_angle_typed ( & file. tree ( ) , offset) ) ,
97- '{' => conv ( on_opening_brace_typed ( file, offset) ) ,
97+ '{' => conv ( on_opening_bracket_typed ( file, offset, '{' ) ) ,
98+ '(' => conv ( on_opening_bracket_typed ( file, offset, '(' ) ) ,
9899 _ => None ,
99100 }
100101}
101102
102- /// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a
103- /// block, or a part of a `use` item.
104- fn on_opening_brace_typed ( file : & Parse < SourceFile > , offset : TextSize ) -> Option < TextEdit > {
105- if !stdx:: always!( file. tree( ) . syntax( ) . text( ) . char_at( offset) == Some ( '{' ) ) {
103+ /// Inserts a closing bracket when the user types an opening bracket, wrapping an existing expression in a
104+ /// block, or a part of a `use` item (for `{`).
105+ fn on_opening_bracket_typed (
106+ file : & Parse < SourceFile > ,
107+ offset : TextSize ,
108+ opening_bracket : char ,
109+ ) -> Option < TextEdit > {
110+ let ( closing_bracket, expected_ast_bracket) = match opening_bracket {
111+ '{' => ( '}' , SyntaxKind :: L_CURLY ) ,
112+ '(' => ( ')' , SyntaxKind :: L_PAREN ) ,
113+ _ => return None ,
114+ } ;
115+
116+ if !stdx:: always!( file. tree( ) . syntax( ) . text( ) . char_at( offset) == Some ( opening_bracket) ) {
106117 return None ;
107118 }
108119
109120 let brace_token = file. tree ( ) . syntax ( ) . token_at_offset ( offset) . right_biased ( ) ?;
110- if brace_token. kind ( ) != SyntaxKind :: L_CURLY {
121+ if brace_token. kind ( ) != expected_ast_bracket {
111122 return None ;
112123 }
113124
114- // Remove the `{` to get a better parse tree, and reparse.
125+ // Remove the opening bracket to get a better parse tree, and reparse.
115126 let range = brace_token. text_range ( ) ;
116- if !stdx:: always!( range. len( ) == TextSize :: of( '{' ) ) {
127+ if !stdx:: always!( range. len( ) == TextSize :: of( opening_bracket ) ) {
117128 return None ;
118129 }
119130 let file = file. reparse ( & Indel :: delete ( range) ) ;
120131
121- if let Some ( edit) = brace_expr ( & file. tree ( ) , offset) {
132+ if let Some ( edit) = bracket_expr ( & file. tree ( ) , offset, opening_bracket , closing_bracket ) {
122133 return Some ( edit) ;
123134 }
124135
125- if let Some ( edit) = brace_use_path ( & file. tree ( ) , offset) {
126- return Some ( edit) ;
136+ if closing_bracket == '}' {
137+ if let Some ( edit) = brace_use_path ( & file. tree ( ) , offset) {
138+ return Some ( edit) ;
139+ }
127140 }
128141
129142 return None ;
@@ -142,7 +155,12 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<
142155 ) )
143156 }
144157
145- fn brace_expr ( file : & SourceFile , offset : TextSize ) -> Option < TextEdit > {
158+ fn bracket_expr (
159+ file : & SourceFile ,
160+ offset : TextSize ,
161+ opening_bracket : char ,
162+ closing_bracket : char ,
163+ ) -> Option < TextEdit > {
146164 let mut expr: ast:: Expr = find_node_at_offset ( file. syntax ( ) , offset) ?;
147165 if expr. syntax ( ) . text_range ( ) . start ( ) != offset {
148166 return None ;
@@ -165,10 +183,10 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<
165183 return None ;
166184 }
167185
168- // Insert `}` right after the expression.
186+ // Insert the closing bracket right after the expression.
169187 Some ( TextEdit :: insert (
170- expr. syntax ( ) . text_range ( ) . end ( ) + TextSize :: of ( "{" ) ,
171- "}" . to_string ( ) ,
188+ expr. syntax ( ) . text_range ( ) . end ( ) + TextSize :: of ( opening_bracket ) ,
189+ closing_bracket . to_string ( ) ,
172190 ) )
173191 }
174192}
@@ -936,6 +954,193 @@ use some::pa$0th::to::Item;
936954 ) ;
937955 }
938956
957+ #[ test]
958+ fn adds_closing_parenthesis_for_expr ( ) {
959+ type_char (
960+ '(' ,
961+ r#"
962+ fn f() { match () { _ => $0() } }
963+ "# ,
964+ r#"
965+ fn f() { match () { _ => (()) } }
966+ "# ,
967+ ) ;
968+ type_char (
969+ '(' ,
970+ r#"
971+ fn f() { $0() }
972+ "# ,
973+ r#"
974+ fn f() { (()) }
975+ "# ,
976+ ) ;
977+ type_char (
978+ '(' ,
979+ r#"
980+ fn f() { let x = $0(); }
981+ "# ,
982+ r#"
983+ fn f() { let x = (()); }
984+ "# ,
985+ ) ;
986+ type_char (
987+ '(' ,
988+ r#"
989+ fn f() { let x = $0a.b(); }
990+ "# ,
991+ r#"
992+ fn f() { let x = (a.b()); }
993+ "# ,
994+ ) ;
995+ type_char (
996+ '(' ,
997+ r#"
998+ const S: () = $0();
999+ fn f() {}
1000+ "# ,
1001+ r#"
1002+ const S: () = (());
1003+ fn f() {}
1004+ "# ,
1005+ ) ;
1006+ type_char (
1007+ '(' ,
1008+ r#"
1009+ const S: () = $0a.b();
1010+ fn f() {}
1011+ "# ,
1012+ r#"
1013+ const S: () = (a.b());
1014+ fn f() {}
1015+ "# ,
1016+ ) ;
1017+ type_char (
1018+ '(' ,
1019+ r#"
1020+ fn f() {
1021+ match x {
1022+ 0 => $0(),
1023+ 1 => (),
1024+ }
1025+ }
1026+ "# ,
1027+ r#"
1028+ fn f() {
1029+ match x {
1030+ 0 => (()),
1031+ 1 => (),
1032+ }
1033+ }
1034+ "# ,
1035+ ) ;
1036+ type_char (
1037+ '(' ,
1038+ r#"
1039+ fn f() {
1040+ let z = Some($03);
1041+ }
1042+ "# ,
1043+ r#"
1044+ fn f() {
1045+ let z = Some((3));
1046+ }
1047+ "# ,
1048+ ) ;
1049+ }
1050+
1051+ #[ test]
1052+ fn parenthesis_noop_in_string_literal ( ) {
1053+ // Regression test for #9351
1054+ type_char_noop (
1055+ '(' ,
1056+ r##"
1057+ fn check_with(ra_fixture: &str, expect: Expect) {
1058+ let base = r#"
1059+ enum E { T(), R$0, C }
1060+ use self::E::X;
1061+ const Z: E = E::C;
1062+ mod m {}
1063+ asdasdasdasdasdasda
1064+ sdasdasdasdasdasda
1065+ sdasdasdasdasd
1066+ "#;
1067+ let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
1068+ expect.assert_eq(&actual)
1069+ }
1070+ "## ,
1071+ ) ;
1072+ }
1073+
1074+ #[ test]
1075+ fn parenthesis_noop_in_item_position_with_macro ( ) {
1076+ type_char_noop ( '(' , r#"$0println!();"# ) ;
1077+ type_char_noop (
1078+ '(' ,
1079+ r#"
1080+ fn main() $0println!("hello");
1081+ }"# ,
1082+ ) ;
1083+ }
1084+
1085+ #[ test]
1086+ fn parenthesis_noop_in_use_tree ( ) {
1087+ type_char_noop (
1088+ '(' ,
1089+ r#"
1090+ use some::$0Path;
1091+ "# ,
1092+ ) ;
1093+ type_char_noop (
1094+ '(' ,
1095+ r#"
1096+ use some::{Path, $0Other};
1097+ "# ,
1098+ ) ;
1099+ type_char_noop (
1100+ '(' ,
1101+ r#"
1102+ use some::{$0Path, Other};
1103+ "# ,
1104+ ) ;
1105+ type_char_noop (
1106+ '(' ,
1107+ r#"
1108+ use some::path::$0to::Item;
1109+ "# ,
1110+ ) ;
1111+ type_char_noop (
1112+ '(' ,
1113+ r#"
1114+ use some::$0path::to::Item;
1115+ "# ,
1116+ ) ;
1117+ type_char_noop (
1118+ '(' ,
1119+ r#"
1120+ use $0some::path::to::Item;
1121+ "# ,
1122+ ) ;
1123+ type_char_noop (
1124+ '(' ,
1125+ r#"
1126+ use some::path::$0to::{Item};
1127+ "# ,
1128+ ) ;
1129+ type_char_noop (
1130+ '(' ,
1131+ r#"
1132+ use $0Thing as _;
1133+ "# ,
1134+ ) ;
1135+
1136+ type_char_noop (
1137+ '(' ,
1138+ r#"
1139+ use some::pa$0th::to::Item;
1140+ "# ,
1141+ ) ;
1142+ }
1143+
9391144 #[ test]
9401145 fn adds_closing_angle_bracket_for_generic_args ( ) {
9411146 type_char (
0 commit comments