11#[ cfg( feature = "luau" ) ]
22use full_moon:: ast:: types:: TypeSpecifier ;
3- use full_moon:: ast:: {
4- punctuated:: { Pair , Punctuated } ,
5- Assignment , Expression , LocalAssignment ,
3+ use full_moon:: tokenizer:: { Token , TokenReference } ;
4+ use full_moon:: {
5+ ast:: {
6+ punctuated:: { Pair , Punctuated } ,
7+ Assignment , Expression , LocalAssignment ,
8+ } ,
9+ tokenizer:: TokenType ,
610} ;
7- use full_moon:: tokenizer:: { Token , TokenKind , TokenReference } ;
811
912#[ cfg( feature = "luau" ) ]
1013use crate :: formatters:: luau:: format_type_specifier;
@@ -72,20 +75,22 @@ fn hang_equal_token<'ast>(
7275 ctx : & Context ,
7376 equal_token : TokenReference < ' ast > ,
7477 shape : Shape ,
78+ indent_first_item : bool ,
7579) -> TokenReference < ' ast > {
76- let equal_token_trailing_trivia = vec ! [
77- create_newline_trivia( ctx) ,
78- create_indent_trivia( ctx, shape. increment_additional_indent( ) ) ,
79- ]
80- . iter ( )
81- . chain (
82- // Remove the space that was present after the equal token
83- equal_token
84- . trailing_trivia ( )
85- . skip_while ( |x| x. token_kind ( ) == TokenKind :: Whitespace ) ,
86- )
87- . map ( |x| x. to_owned ( ) )
88- . collect ( ) ;
80+ let mut equal_token_trailing_trivia = vec ! [ create_newline_trivia( ctx) ] ;
81+ if indent_first_item {
82+ equal_token_trailing_trivia. push ( create_indent_trivia (
83+ ctx,
84+ shape. increment_additional_indent ( ) ,
85+ ) )
86+ }
87+
88+ let equal_token_trailing_trivia = equal_token
89+ . trailing_trivia ( )
90+ . filter ( |x| trivia_util:: trivia_is_comment ( x) )
91+ . flat_map ( |x| vec ! [ Token :: new( TokenType :: spaces( 1 ) ) , x. to_owned( ) ] )
92+ . chain ( equal_token_trailing_trivia. iter ( ) . map ( |x| x. to_owned ( ) ) )
93+ . collect ( ) ;
8994
9095 equal_token. update_trailing_trivia ( FormatTriviaType :: Replace ( equal_token_trailing_trivia) )
9196}
@@ -102,7 +107,7 @@ fn attempt_assignment_tactics<'ast>(
102107 // If there is, we should put it on multiple lines
103108 if expressions. len ( ) > 1 {
104109 // First try hanging at the equal token, using an infinite width, to see if its enough
105- let hanging_equal_token = hang_equal_token ( ctx, equal_token. to_owned ( ) , shape) ;
110+ let hanging_equal_token = hang_equal_token ( ctx, equal_token. to_owned ( ) , shape, true ) ;
106111 let hanging_shape = shape. reset ( ) . increment_additional_indent ( ) ;
107112 let expr_list = format_punctuated (
108113 ctx,
@@ -131,6 +136,46 @@ fn attempt_assignment_tactics<'ast>(
131136 }
132137 } else {
133138 // There is only a single element in the list
139+ let expression = expressions. iter ( ) . next ( ) . unwrap ( ) ;
140+
141+ // Special case: there is a comment in between the equals and the expression
142+ if trivia_util:: token_contains_comments ( & equal_token)
143+ || !trivia_util:: expression_leading_comments ( expression) . is_empty ( )
144+ {
145+ // We will hang at the equals token, and then format the expression as necessary
146+ let equal_token = hang_equal_token ( ctx, equal_token, shape, false ) ;
147+
148+ let shape = shape. reset ( ) . increment_additional_indent ( ) ;
149+
150+ // As we know that there is only a single element in the list, we can extract it to work with it
151+ let expression = format_expression ( ctx, expression, shape) ;
152+
153+ // We need to take all the leading trivia from the expr_list
154+ let ( expression, leading_comments) =
155+ trivia_util:: take_expression_leading_comments ( & expression) ;
156+
157+ // Indent each comment and trail them with a newline
158+ let leading_comments = leading_comments
159+ . iter ( )
160+ . flat_map ( |x| {
161+ vec ! [
162+ create_indent_trivia( ctx, shape) ,
163+ x. to_owned( ) ,
164+ create_newline_trivia( ctx) ,
165+ ]
166+ } )
167+ . chain ( std:: iter:: once ( create_indent_trivia ( ctx, shape) ) )
168+ . collect ( ) ;
169+
170+ let expression =
171+ expression. update_leading_trivia ( FormatTriviaType :: Replace ( leading_comments) ) ;
172+
173+ // Rebuild expression back into a list
174+ let expr_list = std:: iter:: once ( Pair :: new ( expression, None ) ) . collect ( ) ;
175+
176+ return ( expr_list, equal_token) ;
177+ }
178+
134179 // Create an example hanging the expression - we need to create a new context so that we don't overwrite it
135180 let hanging_expr_list = hang_punctuated_list ( ctx, expressions, shape) ;
136181 let hanging_shape = shape. take_first_line ( & strip_trivia ( & hanging_expr_list) ) ;
@@ -147,7 +192,7 @@ fn attempt_assignment_tactics<'ast>(
147192 // Normal format is better: but check to see if the formatting is still over budget
148193 if formatting_shape. over_budget ( ) {
149194 // Hang at the equal token
150- let equal_token = hang_equal_token ( ctx, equal_token, shape) ;
195+ let equal_token = hang_equal_token ( ctx, equal_token, shape, true ) ;
151196 // Add the expression list into the indent range, as it will be indented by one
152197 let shape = shape. increment_additional_indent ( ) ;
153198 let expr_list = format_punctuated ( ctx, expressions, shape, format_expression) ;
@@ -169,13 +214,14 @@ pub fn format_assignment<'ast>(
169214 let leading_trivia = vec ! [ create_indent_trivia( ctx, shape) ] ;
170215 let trailing_trivia = vec ! [ create_newline_trivia( ctx) ] ;
171216
172- // Check if the assignment expressions contain comments. If they do, we bail out of determining any tactics
217+ // Check if the assignment expressions or equal token contain comments. If they do, we bail out of determining any tactics
173218 // and format multiline
174- let contains_comments = assignment. expressions ( ) . pairs ( ) . any ( |pair| {
175- pair. punctuation ( )
176- . map_or ( false , |x| trivia_util:: token_contains_comments ( x) )
177- || trivia_util:: expression_contains_inline_comments ( pair. value ( ) )
178- } ) ;
219+ let contains_comments = trivia_util:: token_contains_comments ( assignment. equal_token ( ) )
220+ || assignment. expressions ( ) . pairs ( ) . any ( |pair| {
221+ pair. punctuation ( )
222+ . map_or ( false , |x| trivia_util:: token_contains_comments ( x) )
223+ || trivia_util:: expression_contains_inline_comments ( pair. value ( ) )
224+ } ) ;
179225
180226 // Firstly attempt to format the assignment onto a single line, using an infinite column width shape
181227 let mut var_list = try_format_punctuated (
@@ -280,13 +326,16 @@ pub fn format_local_assignment<'ast>(
280326 if assignment. expressions ( ) . is_empty ( ) {
281327 format_local_no_assignment ( ctx, assignment, shape, leading_trivia, trailing_trivia)
282328 } else {
283- // Check if the assignment expressions contain comments. If they do, we bail out of determining any tactics
329+ // Check if the assignment expression or equals token contain comments. If they do, we bail out of determining any tactics
284330 // and format multiline
285- let contains_comments = assignment. expressions ( ) . pairs ( ) . any ( |pair| {
286- pair. punctuation ( )
287- . map_or ( false , |x| trivia_util:: token_contains_comments ( x) )
288- || trivia_util:: expression_contains_inline_comments ( pair. value ( ) )
289- } ) ;
331+ let contains_comments = assignment
332+ . equal_token ( )
333+ . map_or ( false , |x| trivia_util:: token_contains_comments ( x) )
334+ || assignment. expressions ( ) . pairs ( ) . any ( |pair| {
335+ pair. punctuation ( )
336+ . map_or ( false , |x| trivia_util:: token_contains_comments ( x) )
337+ || trivia_util:: expression_contains_inline_comments ( pair. value ( ) )
338+ } ) ;
290339
291340 // Firstly attempt to format the assignment onto a single line, using an infinite column width shape
292341 let local_token = fmt_symbol ! ( ctx, assignment. local_token( ) , "local " , shape)
0 commit comments