@@ -11,6 +11,7 @@ use ide_db::{
1111 text_edit:: TextEdit ,
1212 ty_filter:: TryEnum ,
1313} ;
14+ use itertools:: Either ;
1415use stdx:: never;
1516use syntax:: {
1617 SyntaxKind :: { BLOCK_EXPR , EXPR_STMT , FOR_EXPR , IF_EXPR , LOOP_EXPR , STMT_LIST , WHILE_EXPR } ,
@@ -86,98 +87,10 @@ pub(crate) fn complete_postfix(
8687 }
8788 }
8889
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-
15490 postfix_snippet ( "ref" , "&expr" , & format ! ( "&{receiver_text}" ) ) . add_to ( acc, ctx. db ) ;
15591 postfix_snippet ( "refm" , "&mut expr" , & format ! ( "&mut {receiver_text}" ) ) . add_to ( acc, ctx. db ) ;
15692 postfix_snippet ( "deref" , "*expr" , & format ! ( "*{receiver_text}" ) ) . add_to ( acc, ctx. db ) ;
15793
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-
18194 // The rest of the postfix completions create an expression that moves an argument,
18295 // so it's better to consider references now to avoid breaking the compilation
18396
@@ -195,51 +108,192 @@ pub(crate) fn complete_postfix(
195108 add_custom_postfix_completions ( acc, ctx, & postfix_snippet, & receiver_text) ;
196109 }
197110
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 (
202178 "match" ,
203179 "match expr {}" ,
204180 & format ! ( "match {receiver_text} {{\n Ok(${{1:_}}) => {{$2}},\n Err(${{3:_}}) => {{$0}},\n }}" ) ,
205181 )
206182 . add_to ( acc, ctx. db ) ;
207- }
208- TryEnum :: Option => {
209- postfix_snippet (
183+ }
184+ TryEnum :: Option => {
185+ postfix_snippet (
210186 "match" ,
211187 "match expr {}" ,
212188 & format ! (
213189 "match {receiver_text} {{\n Some(${{1:_}}) => {{$2}},\n None => {{$0}},\n }}"
214190 ) ,
215191 )
216192 . 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 ) ;
217202 }
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 ) ;
220254 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 }}" ) ,
224258 )
225259 . 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+ }
226270 }
227271 }
228272
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+ }
242280 }
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 ) ;
243297 }
244298
245299 if let ast:: Expr :: Literal ( literal) = dot_receiver_including_refs. clone ( ) {
@@ -567,6 +621,54 @@ fn main() {
567621 ) ;
568622 }
569623
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+
570672 #[ test]
571673 fn option_letelse ( ) {
572674 check_edit (
0 commit comments