@@ -32,7 +32,7 @@ use crate::SourceChange;
32
32
pub ( crate ) use on_enter:: on_enter;
33
33
34
34
// 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 = ".=<>{( " ;
36
36
37
37
struct ExtendedTextEdit {
38
38
edit : TextEdit ,
@@ -94,36 +94,49 @@ fn on_char_typed_inner(
94
94
'=' => conv ( on_eq_typed ( & file. tree ( ) , offset) ) ,
95
95
'<' => on_left_angle_typed ( & file. tree ( ) , offset) ,
96
96
'>' => 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, '(' ) ) ,
98
99
_ => None ,
99
100
}
100
101
}
101
102
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) ) {
106
117
return None ;
107
118
}
108
119
109
120
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 {
111
122
return None ;
112
123
}
113
124
114
- // Remove the `{` to get a better parse tree, and reparse.
125
+ // Remove the opening bracket to get a better parse tree, and reparse.
115
126
let range = brace_token. text_range ( ) ;
116
- if !stdx:: always!( range. len( ) == TextSize :: of( '{' ) ) {
127
+ if !stdx:: always!( range. len( ) == TextSize :: of( opening_bracket ) ) {
117
128
return None ;
118
129
}
119
130
let file = file. reparse ( & Indel :: delete ( range) ) ;
120
131
121
- if let Some ( edit) = brace_expr ( & file. tree ( ) , offset) {
132
+ if let Some ( edit) = bracket_expr ( & file. tree ( ) , offset, opening_bracket , closing_bracket ) {
122
133
return Some ( edit) ;
123
134
}
124
135
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
+ }
127
140
}
128
141
129
142
return None ;
@@ -142,7 +155,12 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<
142
155
) )
143
156
}
144
157
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 > {
146
164
let mut expr: ast:: Expr = find_node_at_offset ( file. syntax ( ) , offset) ?;
147
165
if expr. syntax ( ) . text_range ( ) . start ( ) != offset {
148
166
return None ;
@@ -165,10 +183,10 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<
165
183
return None ;
166
184
}
167
185
168
- // Insert `}` right after the expression.
186
+ // Insert the closing bracket right after the expression.
169
187
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 ( ) ,
172
190
) )
173
191
}
174
192
}
@@ -936,6 +954,193 @@ use some::pa$0th::to::Item;
936
954
) ;
937
955
}
938
956
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
+
939
1144
#[ test]
940
1145
fn adds_closing_angle_bracket_for_generic_args ( ) {
941
1146
type_char (
0 commit comments