@@ -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 ,
@@ -91,7 +91,8 @@ fn on_char_typed_inner(
9191 '=' => conv ( on_eq_typed ( & file. tree ( ) , offset) ) ,
9292 '<' => on_left_angle_typed ( & file. tree ( ) , offset) ,
9393 '>' => conv ( on_right_angle_typed ( & file. tree ( ) , offset) ) ,
94- '{' => conv ( on_opening_brace_typed ( file, offset) ) ,
94+ '{' => conv ( on_opening_bracket_typed ( file, offset, '{' ) ) ,
95+ '(' => conv ( on_opening_bracket_typed ( file, offset, '(' ) ) ,
9596 _ => return None ,
9697 } ;
9798
@@ -100,31 +101,43 @@ fn on_char_typed_inner(
100101 }
101102}
102103
103- /// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a
104- /// block, or a part of a `use` item.
105- fn on_opening_brace_typed ( file : & Parse < SourceFile > , offset : TextSize ) -> Option < TextEdit > {
106- if !stdx:: always!( file. tree( ) . syntax( ) . text( ) . char_at( offset) == Some ( '{' ) ) {
104+ /// Inserts a closing bracket when the user types an opening bracket, wrapping an existing expression in a
105+ /// block, or a part of a `use` item (for `{`).
106+ fn on_opening_bracket_typed (
107+ file : & Parse < SourceFile > ,
108+ offset : TextSize ,
109+ opening_bracket : char ,
110+ ) -> Option < TextEdit > {
111+ let ( closing_bracket, expected_ast_bracket) = match opening_bracket {
112+ '{' => ( '}' , SyntaxKind :: L_CURLY ) ,
113+ '(' => ( ')' , SyntaxKind :: L_PAREN ) ,
114+ _ => return None ,
115+ } ;
116+
117+ if !stdx:: always!( file. tree( ) . syntax( ) . text( ) . char_at( offset) == Some ( opening_bracket) ) {
107118 return None ;
108119 }
109120
110121 let brace_token = file. tree ( ) . syntax ( ) . token_at_offset ( offset) . right_biased ( ) ?;
111- if brace_token. kind ( ) != SyntaxKind :: L_CURLY {
122+ if brace_token. kind ( ) != expected_ast_bracket {
112123 return None ;
113124 }
114125
115- // Remove the `{` to get a better parse tree, and reparse.
126+ // Remove the opening bracket to get a better parse tree, and reparse.
116127 let range = brace_token. text_range ( ) ;
117- if !stdx:: always!( range. len( ) == TextSize :: of( '{' ) ) {
128+ if !stdx:: always!( range. len( ) == TextSize :: of( opening_bracket ) ) {
118129 return None ;
119130 }
120131 let file = file. reparse ( & Indel :: delete ( range) ) ;
121132
122- if let Some ( edit) = brace_expr ( & file. tree ( ) , offset) {
133+ if let Some ( edit) = bracket_expr ( & file. tree ( ) , offset, opening_bracket , closing_bracket ) {
123134 return Some ( edit) ;
124135 }
125136
126- if let Some ( edit) = brace_use_path ( & file. tree ( ) , offset) {
127- return Some ( edit) ;
137+ if closing_bracket == '}' {
138+ if let Some ( edit) = brace_use_path ( & file. tree ( ) , offset) {
139+ return Some ( edit) ;
140+ }
128141 }
129142
130143 return None ;
@@ -143,7 +156,12 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<
143156 ) )
144157 }
145158
146- fn brace_expr ( file : & SourceFile , offset : TextSize ) -> Option < TextEdit > {
159+ fn bracket_expr (
160+ file : & SourceFile ,
161+ offset : TextSize ,
162+ opening_bracket : char ,
163+ closing_bracket : char ,
164+ ) -> Option < TextEdit > {
147165 let mut expr: ast:: Expr = find_node_at_offset ( file. syntax ( ) , offset) ?;
148166 if expr. syntax ( ) . text_range ( ) . start ( ) != offset {
149167 return None ;
@@ -166,10 +184,10 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<
166184 return None ;
167185 }
168186
169- // Insert `}` right after the expression.
187+ // Insert the closing bracket right after the expression.
170188 Some ( TextEdit :: insert (
171- expr. syntax ( ) . text_range ( ) . end ( ) + TextSize :: of ( "{" ) ,
172- "}" . to_string ( ) ,
189+ expr. syntax ( ) . text_range ( ) . end ( ) + TextSize :: of ( opening_bracket ) ,
190+ closing_bracket . to_string ( ) ,
173191 ) )
174192 }
175193}
@@ -937,6 +955,193 @@ use some::pa$0th::to::Item;
937955 ) ;
938956 }
939957
958+ #[ test]
959+ fn adds_closing_parenthesis_for_expr ( ) {
960+ type_char (
961+ '(' ,
962+ r#"
963+ fn f() { match () { _ => $0() } }
964+ "# ,
965+ r#"
966+ fn f() { match () { _ => (()) } }
967+ "# ,
968+ ) ;
969+ type_char (
970+ '(' ,
971+ r#"
972+ fn f() { $0() }
973+ "# ,
974+ r#"
975+ fn f() { (()) }
976+ "# ,
977+ ) ;
978+ type_char (
979+ '(' ,
980+ r#"
981+ fn f() { let x = $0(); }
982+ "# ,
983+ r#"
984+ fn f() { let x = (()); }
985+ "# ,
986+ ) ;
987+ type_char (
988+ '(' ,
989+ r#"
990+ fn f() { let x = $0a.b(); }
991+ "# ,
992+ r#"
993+ fn f() { let x = (a.b()); }
994+ "# ,
995+ ) ;
996+ type_char (
997+ '(' ,
998+ r#"
999+ const S: () = $0();
1000+ fn f() {}
1001+ "# ,
1002+ r#"
1003+ const S: () = (());
1004+ fn f() {}
1005+ "# ,
1006+ ) ;
1007+ type_char (
1008+ '(' ,
1009+ r#"
1010+ const S: () = $0a.b();
1011+ fn f() {}
1012+ "# ,
1013+ r#"
1014+ const S: () = (a.b());
1015+ fn f() {}
1016+ "# ,
1017+ ) ;
1018+ type_char (
1019+ '(' ,
1020+ r#"
1021+ fn f() {
1022+ match x {
1023+ 0 => $0(),
1024+ 1 => (),
1025+ }
1026+ }
1027+ "# ,
1028+ r#"
1029+ fn f() {
1030+ match x {
1031+ 0 => (()),
1032+ 1 => (),
1033+ }
1034+ }
1035+ "# ,
1036+ ) ;
1037+ type_char (
1038+ '(' ,
1039+ r#"
1040+ fn f() {
1041+ let z = Some($03);
1042+ }
1043+ "# ,
1044+ r#"
1045+ fn f() {
1046+ let z = Some((3));
1047+ }
1048+ "# ,
1049+ ) ;
1050+ }
1051+
1052+ #[ test]
1053+ fn parenthesis_noop_in_string_literal ( ) {
1054+ // Regression test for #9351
1055+ type_char_noop (
1056+ '(' ,
1057+ r##"
1058+ fn check_with(ra_fixture: &str, expect: Expect) {
1059+ let base = r#"
1060+ enum E { T(), R$0, C }
1061+ use self::E::X;
1062+ const Z: E = E::C;
1063+ mod m {}
1064+ asdasdasdasdasdasda
1065+ sdasdasdasdasdasda
1066+ sdasdasdasdasd
1067+ "#;
1068+ let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
1069+ expect.assert_eq(&actual)
1070+ }
1071+ "## ,
1072+ ) ;
1073+ }
1074+
1075+ #[ test]
1076+ fn parenthesis_noop_in_item_position_with_macro ( ) {
1077+ type_char_noop ( '(' , r#"$0println!();"# ) ;
1078+ type_char_noop (
1079+ '(' ,
1080+ r#"
1081+ fn main() $0println!("hello");
1082+ }"# ,
1083+ ) ;
1084+ }
1085+
1086+ #[ test]
1087+ fn parenthesis_noop_in_use_tree ( ) {
1088+ type_char_noop (
1089+ '(' ,
1090+ r#"
1091+ use some::$0Path;
1092+ "# ,
1093+ ) ;
1094+ type_char_noop (
1095+ '(' ,
1096+ r#"
1097+ use some::{Path, $0Other};
1098+ "# ,
1099+ ) ;
1100+ type_char_noop (
1101+ '(' ,
1102+ r#"
1103+ use some::{$0Path, Other};
1104+ "# ,
1105+ ) ;
1106+ type_char_noop (
1107+ '(' ,
1108+ r#"
1109+ use some::path::$0to::Item;
1110+ "# ,
1111+ ) ;
1112+ type_char_noop (
1113+ '(' ,
1114+ r#"
1115+ use some::$0path::to::Item;
1116+ "# ,
1117+ ) ;
1118+ type_char_noop (
1119+ '(' ,
1120+ r#"
1121+ use $0some::path::to::Item;
1122+ "# ,
1123+ ) ;
1124+ type_char_noop (
1125+ '(' ,
1126+ r#"
1127+ use some::path::$0to::{Item};
1128+ "# ,
1129+ ) ;
1130+ type_char_noop (
1131+ '(' ,
1132+ r#"
1133+ use $0Thing as _;
1134+ "# ,
1135+ ) ;
1136+
1137+ type_char_noop (
1138+ '(' ,
1139+ r#"
1140+ use some::pa$0th::to::Item;
1141+ "# ,
1142+ ) ;
1143+ }
1144+
9401145 #[ test]
9411146 fn adds_closing_angle_bracket_for_generic_args ( ) {
9421147 type_char (
0 commit comments