@@ -11,6 +11,7 @@ use ide_db::{
11
11
text_edit:: TextEdit ,
12
12
ty_filter:: TryEnum ,
13
13
} ;
14
+ use itertools:: Either ;
14
15
use stdx:: never;
15
16
use syntax:: {
16
17
SyntaxKind :: { BLOCK_EXPR , EXPR_STMT , FOR_EXPR , IF_EXPR , LOOP_EXPR , STMT_LIST , WHILE_EXPR } ,
@@ -86,98 +87,10 @@ pub(crate) fn complete_postfix(
86
87
}
87
88
}
88
89
89
- let try_enum = TryEnum :: from_ty ( & ctx. sema , & receiver_ty. strip_references ( ) ) ;
90
- if let Some ( try_enum) = & try_enum {
91
- match try_enum {
92
- TryEnum :: Result => {
93
- postfix_snippet (
94
- "ifl" ,
95
- "if let Ok {}" ,
96
- & format ! ( "if let Ok($1) = {receiver_text} {{\n $0\n }}" ) ,
97
- )
98
- . add_to ( acc, ctx. db ) ;
99
-
100
- postfix_snippet (
101
- "lete" ,
102
- "let Ok else {}" ,
103
- & format ! ( "let Ok($1) = {receiver_text} else {{\n $2\n }};\n $0" ) ,
104
- )
105
- . add_to ( acc, ctx. db ) ;
106
-
107
- postfix_snippet (
108
- "while" ,
109
- "while let Ok {}" ,
110
- & format ! ( "while let Ok($1) = {receiver_text} {{\n $0\n }}" ) ,
111
- )
112
- . add_to ( acc, ctx. db ) ;
113
- }
114
- TryEnum :: Option => {
115
- postfix_snippet (
116
- "ifl" ,
117
- "if let Some {}" ,
118
- & format ! ( "if let Some($1) = {receiver_text} {{\n $0\n }}" ) ,
119
- )
120
- . add_to ( acc, ctx. db ) ;
121
-
122
- postfix_snippet (
123
- "lete" ,
124
- "let Some else {}" ,
125
- & format ! ( "let Some($1) = {receiver_text} else {{\n $2\n }};\n $0" ) ,
126
- )
127
- . add_to ( acc, ctx. db ) ;
128
-
129
- postfix_snippet (
130
- "while" ,
131
- "while let Some {}" ,
132
- & format ! ( "while let Some($1) = {receiver_text} {{\n $0\n }}" ) ,
133
- )
134
- . add_to ( acc, ctx. db ) ;
135
- }
136
- }
137
- } else if receiver_ty. is_bool ( ) || receiver_ty. is_unknown ( ) {
138
- postfix_snippet ( "if" , "if expr {}" , & format ! ( "if {receiver_text} {{\n $0\n }}" ) )
139
- . add_to ( acc, ctx. db ) ;
140
- postfix_snippet ( "while" , "while expr {}" , & format ! ( "while {receiver_text} {{\n $0\n }}" ) )
141
- . add_to ( acc, ctx. db ) ;
142
- postfix_snippet ( "not" , "!expr" , & format ! ( "!{receiver_text}" ) ) . add_to ( acc, ctx. db ) ;
143
- } else if let Some ( trait_) = ctx. famous_defs ( ) . core_iter_IntoIterator ( ) {
144
- if receiver_ty. impls_trait ( ctx. db , trait_, & [ ] ) {
145
- postfix_snippet (
146
- "for" ,
147
- "for ele in expr {}" ,
148
- & format ! ( "for ele in {receiver_text} {{\n $0\n }}" ) ,
149
- )
150
- . add_to ( acc, ctx. db ) ;
151
- }
152
- }
153
-
154
90
postfix_snippet ( "ref" , "&expr" , & format ! ( "&{receiver_text}" ) ) . add_to ( acc, ctx. db ) ;
155
91
postfix_snippet ( "refm" , "&mut expr" , & format ! ( "&mut {receiver_text}" ) ) . add_to ( acc, ctx. db ) ;
156
92
postfix_snippet ( "deref" , "*expr" , & format ! ( "*{receiver_text}" ) ) . add_to ( acc, ctx. db ) ;
157
93
158
- let mut block_should_be_wrapped = true ;
159
- if dot_receiver. syntax ( ) . kind ( ) == BLOCK_EXPR {
160
- block_should_be_wrapped = false ;
161
- if let Some ( parent) = dot_receiver. syntax ( ) . parent ( ) {
162
- if matches ! ( parent. kind( ) , IF_EXPR | WHILE_EXPR | LOOP_EXPR | FOR_EXPR ) {
163
- block_should_be_wrapped = true ;
164
- }
165
- }
166
- } ;
167
- let unsafe_completion_string = if block_should_be_wrapped {
168
- format ! ( "unsafe {{ {receiver_text} }}" )
169
- } else {
170
- format ! ( "unsafe {receiver_text}" )
171
- } ;
172
- postfix_snippet ( "unsafe" , "unsafe {}" , & unsafe_completion_string) . add_to ( acc, ctx. db ) ;
173
-
174
- let const_completion_string = if block_should_be_wrapped {
175
- format ! ( "const {{ {receiver_text} }}" )
176
- } else {
177
- format ! ( "const {receiver_text}" )
178
- } ;
179
- postfix_snippet ( "const" , "const {}" , & const_completion_string) . add_to ( acc, ctx. db ) ;
180
-
181
94
// The rest of the postfix completions create an expression that moves an argument,
182
95
// so it's better to consider references now to avoid breaking the compilation
183
96
@@ -195,51 +108,192 @@ pub(crate) fn complete_postfix(
195
108
add_custom_postfix_completions ( acc, ctx, & postfix_snippet, & receiver_text) ;
196
109
}
197
110
198
- match try_enum {
199
- Some ( try_enum) => match try_enum {
200
- TryEnum :: Result => {
201
- postfix_snippet (
111
+ postfix_snippet ( "box" , "Box::new(expr)" , & format ! ( "Box::new({receiver_text})" ) )
112
+ . add_to ( acc, ctx. db ) ;
113
+ postfix_snippet ( "dbg" , "dbg!(expr)" , & format ! ( "dbg!({receiver_text})" ) ) . add_to ( acc, ctx. db ) ; // fixme
114
+ postfix_snippet ( "dbgr" , "dbg!(&expr)" , & format ! ( "dbg!(&{receiver_text})" ) ) . add_to ( acc, ctx. db ) ;
115
+ postfix_snippet ( "call" , "function(expr)" , & format ! ( "${{1}}({receiver_text})" ) )
116
+ . add_to ( acc, ctx. db ) ;
117
+
118
+ let try_enum = TryEnum :: from_ty ( & ctx. sema , & receiver_ty. strip_references ( ) ) ;
119
+ let mut is_in_cond = false ;
120
+ if let Some ( parent) = dot_receiver_including_refs. syntax ( ) . parent ( ) {
121
+ if let Some ( second_ancestor) = parent. parent ( ) {
122
+ let sec_ancestor_kind = second_ancestor. kind ( ) ;
123
+ if let Some ( expr) = <Either < ast:: IfExpr , ast:: WhileExpr > >:: cast ( second_ancestor) {
124
+ is_in_cond = match expr {
125
+ Either :: Left ( it) => it. condition ( ) . is_some_and ( |cond| * cond. syntax ( ) == parent) ,
126
+ Either :: Right ( it) => {
127
+ it. condition ( ) . is_some_and ( |cond| * cond. syntax ( ) == parent)
128
+ }
129
+ }
130
+ }
131
+ match & try_enum {
132
+ Some ( try_enum) if is_in_cond => match try_enum {
133
+ TryEnum :: Result => {
134
+ postfix_snippet (
135
+ "let" ,
136
+ "let Ok(_)" ,
137
+ & format ! ( "let Ok($0) = {receiver_text}" ) ,
138
+ )
139
+ . add_to ( acc, ctx. db ) ;
140
+ postfix_snippet (
141
+ "letm" ,
142
+ "let Ok(mut _)" ,
143
+ & format ! ( "let Ok(mut $0) = {receiver_text}" ) ,
144
+ )
145
+ . add_to ( acc, ctx. db ) ;
146
+ }
147
+ TryEnum :: Option => {
148
+ postfix_snippet (
149
+ "let" ,
150
+ "let Some(_)" ,
151
+ & format ! ( "let Some($0) = {receiver_text}" ) ,
152
+ )
153
+ . add_to ( acc, ctx. db ) ;
154
+ postfix_snippet (
155
+ "letm" ,
156
+ "let Some(mut _)" ,
157
+ & format ! ( "let Some(mut $0) = {receiver_text}" ) ,
158
+ )
159
+ . add_to ( acc, ctx. db ) ;
160
+ }
161
+ } ,
162
+ _ if matches ! ( sec_ancestor_kind, STMT_LIST | EXPR_STMT ) => {
163
+ postfix_snippet ( "let" , "let" , & format ! ( "let $0 = {receiver_text};" ) )
164
+ . add_to ( acc, ctx. db ) ;
165
+ postfix_snippet ( "letm" , "let mut" , & format ! ( "let mut $0 = {receiver_text};" ) )
166
+ . add_to ( acc, ctx. db ) ;
167
+ }
168
+ _ => ( ) ,
169
+ }
170
+ }
171
+ }
172
+
173
+ if !is_in_cond {
174
+ match try_enum {
175
+ Some ( try_enum) => match try_enum {
176
+ TryEnum :: Result => {
177
+ postfix_snippet (
202
178
"match" ,
203
179
"match expr {}" ,
204
180
& format ! ( "match {receiver_text} {{\n Ok(${{1:_}}) => {{$2}},\n Err(${{3:_}}) => {{$0}},\n }}" ) ,
205
181
)
206
182
. add_to ( acc, ctx. db ) ;
207
- }
208
- TryEnum :: Option => {
209
- postfix_snippet (
183
+ }
184
+ TryEnum :: Option => {
185
+ postfix_snippet (
210
186
"match" ,
211
187
"match expr {}" ,
212
188
& format ! (
213
189
"match {receiver_text} {{\n Some(${{1:_}}) => {{$2}},\n None => {{$0}},\n }}"
214
190
) ,
215
191
)
216
192
. add_to ( acc, ctx. db ) ;
193
+ }
194
+ } ,
195
+ None => {
196
+ postfix_snippet (
197
+ "match" ,
198
+ "match expr {}" ,
199
+ & format ! ( "match {receiver_text} {{\n ${{1:_}} => {{$0}},\n }}" ) ,
200
+ )
201
+ . add_to ( acc, ctx. db ) ;
217
202
}
218
- } ,
219
- None => {
203
+ }
204
+ if let Some ( try_enum) = & try_enum {
205
+ match try_enum {
206
+ TryEnum :: Result => {
207
+ postfix_snippet (
208
+ "ifl" ,
209
+ "if let Ok {}" ,
210
+ & format ! ( "if let Ok($1) = {receiver_text} {{\n $0\n }}" ) ,
211
+ )
212
+ . add_to ( acc, ctx. db ) ;
213
+
214
+ postfix_snippet (
215
+ "lete" ,
216
+ "let Ok else {}" ,
217
+ & format ! ( "let Ok($1) = {receiver_text} else {{\n $2\n }};\n $0" ) ,
218
+ )
219
+ . add_to ( acc, ctx. db ) ;
220
+
221
+ postfix_snippet (
222
+ "while" ,
223
+ "while let Ok {}" ,
224
+ & format ! ( "while let Ok($1) = {receiver_text} {{\n $0\n }}" ) ,
225
+ )
226
+ . add_to ( acc, ctx. db ) ;
227
+ }
228
+ TryEnum :: Option => {
229
+ postfix_snippet (
230
+ "ifl" ,
231
+ "if let Some {}" ,
232
+ & format ! ( "if let Some($1) = {receiver_text} {{\n $0\n }}" ) ,
233
+ )
234
+ . add_to ( acc, ctx. db ) ;
235
+
236
+ postfix_snippet (
237
+ "lete" ,
238
+ "let Some else {}" ,
239
+ & format ! ( "let Some($1) = {receiver_text} else {{\n $2\n }};\n $0" ) ,
240
+ )
241
+ . add_to ( acc, ctx. db ) ;
242
+
243
+ postfix_snippet (
244
+ "while" ,
245
+ "while let Some {}" ,
246
+ & format ! ( "while let Some($1) = {receiver_text} {{\n $0\n }}" ) ,
247
+ )
248
+ . add_to ( acc, ctx. db ) ;
249
+ }
250
+ }
251
+ } else if receiver_ty. is_bool ( ) || receiver_ty. is_unknown ( ) {
252
+ postfix_snippet ( "if" , "if expr {}" , & format ! ( "if {receiver_text} {{\n $0\n }}" ) )
253
+ . add_to ( acc, ctx. db ) ;
220
254
postfix_snippet (
221
- "match " ,
222
- "match expr {}" ,
223
- & format ! ( "match {receiver_text} {{\n ${{1:_}} => {{$0}}, \n }}" ) ,
255
+ "while " ,
256
+ "while expr {}" ,
257
+ & format ! ( "while {receiver_text} {{\n $0 \n }}" ) ,
224
258
)
225
259
. add_to ( acc, ctx. db ) ;
260
+ postfix_snippet ( "not" , "!expr" , & format ! ( "!{receiver_text}" ) ) . add_to ( acc, ctx. db ) ;
261
+ } else if let Some ( trait_) = ctx. famous_defs ( ) . core_iter_IntoIterator ( ) {
262
+ if receiver_ty. impls_trait ( ctx. db , trait_, & [ ] ) {
263
+ postfix_snippet (
264
+ "for" ,
265
+ "for ele in expr {}" ,
266
+ & format ! ( "for ele in {receiver_text} {{\n $0\n }}" ) ,
267
+ )
268
+ . add_to ( acc, ctx. db ) ;
269
+ }
226
270
}
227
271
}
228
272
229
- postfix_snippet ( "box" , "Box::new(expr)" , & format ! ( "Box::new({receiver_text})" ) )
230
- . add_to ( acc, ctx. db ) ;
231
- postfix_snippet ( "dbg" , "dbg!(expr)" , & format ! ( "dbg!({receiver_text})" ) ) . add_to ( acc, ctx. db ) ; // fixme
232
- postfix_snippet ( "dbgr" , "dbg!(&expr)" , & format ! ( "dbg!(&{receiver_text})" ) ) . add_to ( acc, ctx. db ) ;
233
- postfix_snippet ( "call" , "function(expr)" , & format ! ( "${{1}}({receiver_text})" ) )
234
- . add_to ( acc, ctx. db ) ;
235
-
236
- if let Some ( parent) = dot_receiver_including_refs. syntax ( ) . parent ( ) . and_then ( |p| p. parent ( ) ) {
237
- if matches ! ( parent. kind( ) , STMT_LIST | EXPR_STMT ) {
238
- postfix_snippet ( "let" , "let" , & format ! ( "let $0 = {receiver_text};" ) )
239
- . add_to ( acc, ctx. db ) ;
240
- postfix_snippet ( "letm" , "let mut" , & format ! ( "let mut $0 = {receiver_text};" ) )
241
- . add_to ( acc, ctx. db ) ;
273
+ let mut block_should_be_wrapped = true ;
274
+ if dot_receiver. syntax ( ) . kind ( ) == BLOCK_EXPR {
275
+ block_should_be_wrapped = false ;
276
+ if let Some ( parent) = dot_receiver. syntax ( ) . parent ( ) {
277
+ if matches ! ( parent. kind( ) , IF_EXPR | WHILE_EXPR | LOOP_EXPR | FOR_EXPR ) {
278
+ block_should_be_wrapped = true ;
279
+ }
242
280
}
281
+ } ;
282
+ {
283
+ let ( open_brace, close_brace) =
284
+ if block_should_be_wrapped { ( "{ " , " }" ) } else { ( "" , "" ) } ;
285
+ let ( open_paren, close_paren) = if is_in_cond { ( "(" , ")" ) } else { ( "" , "" ) } ;
286
+ let unsafe_completion_string = format ! (
287
+ "{}unsafe {}{receiver_text}{}{}" ,
288
+ open_paren, open_brace, close_brace, close_paren
289
+ ) ;
290
+ postfix_snippet ( "unsafe" , "unsafe {}" , & unsafe_completion_string) . add_to ( acc, ctx. db ) ;
291
+
292
+ let const_completion_string = format ! (
293
+ "{}const {}{receiver_text}{}{}" ,
294
+ open_paren, open_brace, close_brace, close_paren
295
+ ) ;
296
+ postfix_snippet ( "const" , "const {}" , & const_completion_string) . add_to ( acc, ctx. db ) ;
243
297
}
244
298
245
299
if let ast:: Expr :: Literal ( literal) = dot_receiver_including_refs. clone ( ) {
@@ -567,6 +621,54 @@ fn main() {
567
621
) ;
568
622
}
569
623
624
+ #[ test]
625
+ fn option_iflet_cond ( ) {
626
+ check (
627
+ r#"
628
+ //- minicore: option
629
+ fn main() {
630
+ let bar = Some(true);
631
+ if bar.$0
632
+ }
633
+ "# ,
634
+ expect ! [ [ r#"
635
+ me and(…) fn(self, Option<U>) -> Option<U>
636
+ me as_ref() const fn(&self) -> Option<&T>
637
+ me ok_or(…) const fn(self, E) -> Result<T, E>
638
+ me unwrap() const fn(self) -> T
639
+ me unwrap_or(…) fn(self, T) -> T
640
+ sn box Box::new(expr)
641
+ sn call function(expr)
642
+ sn const const {}
643
+ sn dbg dbg!(expr)
644
+ sn dbgr dbg!(&expr)
645
+ sn deref *expr
646
+ sn let let Some(_)
647
+ sn letm let Some(mut _)
648
+ sn ref &expr
649
+ sn refm &mut expr
650
+ sn return return expr
651
+ sn unsafe unsafe {}
652
+ "# ] ] ,
653
+ ) ;
654
+ check_edit (
655
+ "let" ,
656
+ r#"
657
+ //- minicore: option
658
+ fn main() {
659
+ let bar = Some(true);
660
+ if bar.$0
661
+ }
662
+ "# ,
663
+ r#"
664
+ fn main() {
665
+ let bar = Some(true);
666
+ if let Some($0) = bar
667
+ }
668
+ "# ,
669
+ ) ;
670
+ }
671
+
570
672
#[ test]
571
673
fn option_letelse ( ) {
572
674
check_edit (
0 commit comments