@@ -102,6 +102,28 @@ fn count_indentation(code: &str, line_numbers: &LineNumbers, line: u32) -> usize
102102 indent_size
103103}
104104
105+ // Given a string and a position in it, if the position points to whitespace,
106+ // this function returns the next position which doesn't.
107+ fn next_nonwhitespace ( string : & EcoString , position : u32 ) -> u32 {
108+ let mut n = position;
109+ let mut chars = string[ position as usize ..] . chars ( ) ;
110+ while chars. next ( ) . is_some_and ( char:: is_whitespace) {
111+ n += 1 ;
112+ }
113+ n
114+ }
115+
116+ // Given a string and a position in it, if the position points after whitespace,
117+ // this function returns the previous position which doesn't.
118+ fn previous_nonwhitespace ( string : & EcoString , position : u32 ) -> u32 {
119+ let mut n = position;
120+ let mut chars = string[ ..position as usize ] . chars ( ) ;
121+ while chars. next_back ( ) . is_some_and ( char:: is_whitespace) {
122+ n -= 1 ;
123+ }
124+ n
125+ }
126+
105127/// Code action to remove literal tuples in case subjects, essentially making
106128/// the elements of the tuples into the case's subjects.
107129///
@@ -842,6 +864,7 @@ impl<'ast> ast::visit::Visit<'ast> for FillInMissingLabelledArgs<'ast> {
842864 type_ : & ' ast Arc < Type > ,
843865 fun : & ' ast TypedExpr ,
844866 arguments : & ' ast [ TypedCallArg ] ,
867+ arguments_start : & ' ast Option < u32 > ,
845868 ) {
846869 let call_range = self . edits . src_span_to_lsp_range ( * location) ;
847870 if !within ( self . params . range , call_range) {
@@ -864,7 +887,7 @@ impl<'ast> ast::visit::Visit<'ast> for FillInMissingLabelledArgs<'ast> {
864887 // we're inside a nested call.
865888 let previous = self . use_right_hand_side_location ;
866889 self . use_right_hand_side_location = None ;
867- ast:: visit:: visit_typed_expr_call ( self , location, type_, fun, arguments) ;
890+ ast:: visit:: visit_typed_expr_call ( self , location, type_, fun, arguments, arguments_start ) ;
868891 self . use_right_hand_side_location = previous;
869892 }
870893
@@ -1263,7 +1286,7 @@ impl<'ast> ast::visit::Visit<'ast> for AddAnnotations<'_> {
12631286 let location = match kind {
12641287 // Function captures don't need any type annotations
12651288 FunctionLiteralKind :: Capture { .. } => return ,
1266- FunctionLiteralKind :: Anonymous { head } => head,
1289+ FunctionLiteralKind :: Anonymous { head, .. } => head,
12671290 FunctionLiteralKind :: Use { location } => location,
12681291 } ;
12691292
@@ -5269,6 +5292,7 @@ impl<'ast> ast::visit::Visit<'ast> for GenerateFunction<'ast> {
52695292 type_ : & ' ast Arc < Type > ,
52705293 fun : & ' ast TypedExpr ,
52715294 arguments : & ' ast [ TypedCallArg ] ,
5295+ arguments_start : & ' ast Option < u32 > ,
52725296 ) {
52735297 // If the function being called is invalid we need to generate a
52745298 // function that has the proper labels.
@@ -5302,8 +5326,7 @@ impl<'ast> ast::visit::Visit<'ast> for GenerateFunction<'ast> {
53025326 _ => { }
53035327 }
53045328 }
5305-
5306- ast:: visit:: visit_typed_expr_call ( self , location, type_, fun, arguments) ;
5329+ ast:: visit:: visit_typed_expr_call ( self , location, type_, fun, arguments, arguments_start) ;
53075330 }
53085331}
53095332
@@ -5626,6 +5649,7 @@ where
56265649 type_ : & ' ast Arc < Type > ,
56275650 fun : & ' ast TypedExpr ,
56285651 arguments : & ' ast [ TypedCallArg ] ,
5652+ arguments_start : & ' ast Option < u32 > ,
56295653 ) {
56305654 // If the function being called is invalid we need to generate a
56315655 // function that has the proper labels.
@@ -5639,7 +5663,14 @@ where
56395663 ) ;
56405664 }
56415665 } else {
5642- ast:: visit:: visit_typed_expr_call ( self , location, type_, fun, arguments) ;
5666+ ast:: visit:: visit_typed_expr_call (
5667+ self ,
5668+ location,
5669+ type_,
5670+ fun,
5671+ arguments,
5672+ arguments_start,
5673+ ) ;
56435674 }
56445675 }
56455676
@@ -6102,12 +6133,7 @@ impl<'a> InlineVariable<'a> {
61026133 }
61036134
61046135 let mut location = assignment. location ;
6105-
6106- let mut chars = self . module . code [ location. end as usize ..] . chars ( ) ;
6107- // Delete any whitespace after the removed statement
6108- while chars. next ( ) . is_some_and ( char:: is_whitespace) {
6109- location. end += 1 ;
6110- }
6136+ location. end = next_nonwhitespace ( & self . module . code , location. end ) ;
61116137
61126138 self . edits . delete ( location) ;
61136139
@@ -6336,6 +6362,7 @@ impl<'ast> ast::visit::Visit<'ast> for ConvertToPipe<'ast> {
63366362 _type_ : & ' ast Arc < Type > ,
63376363 fun : & ' ast TypedExpr ,
63386364 arguments : & ' ast [ TypedCallArg ] ,
6365+ _arguments_start : & ' ast Option < u32 > ,
63396366 ) {
63406367 if arguments. iter ( ) . any ( |arg| arg. is_capture_hole ( ) ) {
63416368 return ;
@@ -8313,6 +8340,7 @@ impl<'ast> ast::visit::Visit<'ast> for WrapInAnonymousFunction<'ast> {
83138340 _type : & ' ast Arc < Type > ,
83148341 fun : & ' ast TypedExpr ,
83158342 arguments : & ' ast [ TypedCallArg ] ,
8343+ _arguments_start : & ' ast Option < u32 > ,
83168344 ) {
83178345 // We only need to do this interception for explicit calls, so if any
83188346 // of our arguments are explicit we re-enter the visitor as usual.
@@ -8355,11 +8383,15 @@ pub struct UnwrapAnonymousFunction<'a> {
83558383
83568384/// Helper struct, a target for [UnwrapAnonymousFunction]
83578385struct FunctionToUnwrap {
8358- /// Location of the anonymous function to apply the action to
8386+ /// Location of the anonymous function to apply the action to.
83598387 outer_function : SrcSpan ,
8388+ /// Location of the opening brace of the anonymous function.
8389+ outer_function_body_start : u32 ,
83608390 /// Location of the function being called inside the anonymous function.
83618391 /// This will be all that's left after the action, plus any comments.
83628392 inner_function : SrcSpan ,
8393+ // Location of the opening parenthesis of the inner function's argument list.
8394+ inner_function_arguments_start : u32 ,
83638395}
83648396
83658397impl < ' a > UnwrapAnonymousFunction < ' a > {
@@ -8383,25 +8415,29 @@ impl<'a> UnwrapAnonymousFunction<'a> {
83838415 for function in & self . functions {
83848416 let mut edits = TextEdits :: new ( self . line_numbers ) ;
83858417
8386- // We need to delete the anonymous function's head but preserve
8387- // comments between it and the inner function call.
8388- edits. delete ( self . span_until_comment ( SrcSpan {
8418+ // We need to delete the anonymous function's head and the opening
8419+ // brace but preserve comments between it and the inner function call.
8420+ // We set our endpoint at the start of the function body, and move
8421+ // it on through any whitespace.
8422+ let head_deletion_end =
8423+ next_nonwhitespace ( & self . module . code , function. outer_function_body_start + 1 ) ;
8424+ edits. delete ( SrcSpan {
83898425 start : function. outer_function . start ,
8390- end : function . inner_function . start ,
8391- } ) ) ;
8392-
8393- // Now we need to delete the inner function call's arguments,
8394- // preserving comments before the outer function tail.
8395- edits . delete ( self . span_until_comment ( SrcSpan {
8396- start : function. inner_function . end ,
8397- end : function . outer_function . end - 1 ,
8398- } ) ) ;
8399-
8400- // To delete the tail we nip one character to make sure we get the
8401- // `}`. This could be redundant with the above if there were no
8402- // comments, but that's fine.
8426+ end : head_deletion_end ,
8427+ } ) ;
8428+
8429+ // Delete the inner function call's arguments.
8430+ edits . delete ( SrcSpan {
8431+ start : function . inner_function_arguments_start ,
8432+ end : function. inner_function . end ,
8433+ } ) ;
8434+
8435+ // To delete the tail we remove the function end (the '}') and any
8436+ // whitespace before it.
8437+ let tail_deletion_start =
8438+ previous_nonwhitespace ( & self . module . code , function . outer_function . end - 1 ) ;
84038439 edits. delete ( SrcSpan {
8404- start : function . outer_function . end - 1 ,
8440+ start : tail_deletion_start ,
84058441 end : function. outer_function . end ,
84068442 } ) ;
84078443
@@ -8413,24 +8449,6 @@ impl<'a> UnwrapAnonymousFunction<'a> {
84138449 actions
84148450 }
84158451
8416- // Returns the given span, but with the end point adjusted to the start
8417- // of the first comment in the span, if any.
8418- fn span_until_comment ( & self , span : SrcSpan ) -> SrcSpan {
8419- let SrcSpan { start, end } = span;
8420- let adjusted_end = self
8421- . module
8422- . extra
8423- . first_comment_between ( start, end)
8424- // The above will return the start of the comment's text, so we need
8425- // to step backwards a bit to get the `//`.
8426- . map ( |comment| comment. start - 2 )
8427- . unwrap_or ( end) ;
8428- SrcSpan {
8429- start,
8430- end : adjusted_end,
8431- }
8432- }
8433-
84348452 /// If an anonymous function can be unwrapped, save it to our list
84358453 ///
84368454 /// We need to ensure our subjects:
@@ -8446,16 +8464,17 @@ impl<'a> UnwrapAnonymousFunction<'a> {
84468464 arguments : & ' a [ TypedArg ] ,
84478465 body : & ' a Vec1 < TypedStatement > ,
84488466 ) {
8449- match kind {
8450- FunctionLiteralKind :: Anonymous { .. } => ( ) ,
8467+ let outer_body = match kind {
8468+ FunctionLiteralKind :: Anonymous { body , .. } => body ,
84518469 _ => return ,
8452- }
8470+ } ;
84538471
84548472 // We can only apply to anonymous functions containing a single function call
84558473 let [
84568474 TypedStatement :: Expression ( TypedExpr :: Call {
8457- fun : called_function ,
8475+ location : call_location ,
84588476 arguments : call_arguments,
8477+ arguments_start : Some ( arguments_start) ,
84598478 ..
84608479 } ) ,
84618480 ] = body. as_slice ( )
@@ -8490,7 +8509,9 @@ impl<'a> UnwrapAnonymousFunction<'a> {
84908509
84918510 self . functions . push ( FunctionToUnwrap {
84928511 outer_function : * location,
8493- inner_function : called_function. location ( ) ,
8512+ outer_function_body_start : outer_body. start ,
8513+ inner_function : * call_location,
8514+ inner_function_arguments_start : * arguments_start,
84948515 } )
84958516 }
84968517}
0 commit comments