@@ -2467,170 +2467,132 @@ fn renderArrayInit(
24672467
24682468 try ais .pushIndent (.normal );
24692469 try renderToken (r , array_init .ast .lbrace , .newline );
2470-
2471- var expr_index : usize = 0 ;
2472- while (true ) {
2473- const row_size = rowSize (tree , array_init .ast .elements [expr_index .. ], rbrace );
2474- const row_exprs = array_init .ast .elements [expr_index .. ];
2475- // A place to store the width of each expression and its column's maximum
2476- const widths = try gpa .alloc (usize , row_exprs .len + row_size );
2477- defer gpa .free (widths );
2478- @memset (widths , 0 );
2479-
2480- const expr_newlines = try gpa .alloc (bool , row_exprs .len );
2481- defer gpa .free (expr_newlines );
2482- @memset (expr_newlines , false );
2483-
2484- const expr_widths = widths [0.. row_exprs .len ];
2485- const column_widths = widths [row_exprs .len .. ];
2486-
2487- // Find next row with trailing comment (if any) to end the current section.
2488- const section_end = sec_end : {
2489- var this_line_first_expr : usize = 0 ;
2490- var this_line_size = rowSize (tree , row_exprs , rbrace );
2491- for (row_exprs , 0.. ) | expr , i | {
2492- // Ignore comment on first line of this section.
2493- if (i == 0 ) continue ;
2494- const expr_last_token = tree .lastToken (expr );
2495- if (tree .tokensOnSameLine (tree .firstToken (row_exprs [0 ]), expr_last_token ))
2496- continue ;
2497- // Track start of line containing comment.
2498- if (! tree .tokensOnSameLine (tree .firstToken (row_exprs [this_line_first_expr ]), expr_last_token )) {
2499- this_line_first_expr = i ;
2500- this_line_size = rowSize (tree , row_exprs [this_line_first_expr .. ], rbrace );
2501- }
2502-
2503- const maybe_comma = expr_last_token + 1 ;
2504- if (tree .tokenTag (maybe_comma ) == .comma ) {
2505- if (hasSameLineComment (tree , maybe_comma ))
2506- break :sec_end i - this_line_size + 1 ;
2507- }
2508- }
2509- break :sec_end row_exprs .len ;
2510- };
2511- expr_index += section_end ;
2512-
2513- const section_exprs = row_exprs [0.. section_end ];
2514-
2515- var sub_expr_buffer : Writer.Allocating = .init (gpa );
2516- defer sub_expr_buffer .deinit ();
2517-
2518- const sub_expr_buffer_starts = try gpa .alloc (usize , section_exprs .len + 1 );
2519- defer gpa .free (sub_expr_buffer_starts );
2520-
2521- var auto_indenting_stream : AutoIndentingStream = .init (gpa , & sub_expr_buffer .writer , indent_delta );
2522- defer auto_indenting_stream .deinit ();
2523- var sub_render : Render = .{
2470+ try ais .pushSpace (.comma );
2471+
2472+ const expr_widths = try gpa .alloc (enum (usize ) {
2473+ /// The expression contains non-printable characters (e.g. unicode / newlines)
2474+ /// or has formatting disabled at the start or end.
2475+ nonprint = std .math .maxInt (usize ),
2476+ _ ,
2477+ }, array_init .ast .elements .len );
2478+ defer gpa .free (expr_widths );
2479+ {
2480+ var buf : Writer.Allocating = .init (gpa );
2481+ defer buf .deinit ();
2482+ var sub_ais : AutoIndentingStream = .init (gpa , & buf .writer , indent_delta );
2483+ sub_ais .disabled_offset = ais .disabled_offset ;
2484+ defer sub_ais .deinit ();
2485+ var sub_r : Render = .{
25242486 .gpa = r .gpa ,
2525- .ais = & auto_indenting_stream ,
2487+ .ais = & sub_ais ,
25262488 .tree = r .tree ,
25272489 .fixups = r .fixups ,
25282490 };
2529-
2530- // Calculate size of columns in current section
2531- var column_counter : usize = 0 ;
2532- var single_line = true ;
2533- var contains_newline = false ;
2534- for (section_exprs , 0.. ) | expr , i | {
2535- const start = sub_expr_buffer .written ().len ;
2536- sub_expr_buffer_starts [i ] = start ;
2537-
2538- if (i + 1 < section_exprs .len ) {
2539- try renderExpression (& sub_render , expr , .none );
2540- const written = sub_expr_buffer .written ();
2541- const width = written .len - start ;
2542- const this_contains_newline = mem .indexOfScalar (u8 , written [start .. ], '\n ' ) != null ;
2543- contains_newline = contains_newline or this_contains_newline ;
2544- expr_widths [i ] = width ;
2545- expr_newlines [i ] = this_contains_newline ;
2546-
2547- if (! this_contains_newline ) {
2548- const column = column_counter % row_size ;
2549- column_widths [column ] = @max (column_widths [column ], width );
2550-
2551- const expr_last_token = tree .lastToken (expr ) + 1 ;
2552- const next_expr = section_exprs [i + 1 ];
2553- column_counter += 1 ;
2554- if (! tree .tokensOnSameLine (expr_last_token , tree .firstToken (next_expr ))) single_line = false ;
2555- } else {
2556- single_line = false ;
2557- column_counter = 0 ;
2558- }
2491+ for (array_init .ast .elements , expr_widths ) | e , * width | {
2492+ const begin_disabled = sub_ais .disabled_offset != null ;
2493+ // `.skip` space so trailing commments aren't included
2494+ try renderExpressionComma (& sub_r , e , .skip );
2495+ if (! begin_disabled and sub_ais .disabled_offset == null ) {
2496+ const w = buf .written ();
2497+ width .* = for (w ) | c | {
2498+ if (! std .ascii .isPrint (c ))
2499+ break .nonprint ;
2500+ } else @enumFromInt (w .len - @intFromBool (w [w .len - 1 ] == ',' ));
25592501 } else {
2560- try ais .pushSpace (.comma );
2561- try renderExpression (& sub_render , expr , .comma );
2562- ais .popSpace ();
2563-
2564- const written = sub_expr_buffer .written ();
2565- const width = written .len - start - 2 ;
2566- const this_contains_newline = mem .indexOfScalar (u8 , written [start .. written .len - 1 ], '\n ' ) != null ;
2567- contains_newline = contains_newline or this_contains_newline ;
2568- expr_widths [i ] = width ;
2569- expr_newlines [i ] = contains_newline ;
2570-
2571- if (! contains_newline ) {
2572- const column = column_counter % row_size ;
2573- column_widths [column ] = @max (column_widths [column ], width );
2574- }
2502+ width .* = .nonprint ;
25752503 }
2576- }
2577- sub_expr_buffer_starts [section_exprs .len ] = sub_expr_buffer .written ().len ;
25782504
2579- // Render exprs in current section.
2580- column_counter = 0 ;
2581- for (section_exprs , 0.. ) | expr , i | {
2582- const start = sub_expr_buffer_starts [i ];
2583- const end = sub_expr_buffer_starts [i + 1 ];
2584- const expr_text = sub_expr_buffer .written ()[start .. end ];
2585- if (! expr_newlines [i ]) {
2586- try ais .writeAll (expr_text );
2587- } else {
2588- var by_line = std .mem .splitScalar (u8 , expr_text , '\n ' );
2589- var last_line_was_empty = false ;
2590- try ais .writeAll (by_line .first ());
2591- while (by_line .next ()) | line | {
2592- if (std .mem .startsWith (u8 , line , "//" ) and last_line_was_empty ) {
2593- try ais .insertNewline ();
2594- } else {
2595- try ais .maybeInsertNewline ();
2596- }
2597- last_line_was_empty = (line .len == 0 );
2598- try ais .writeAll (line );
2599- }
2600- }
2601-
2602- if (i + 1 < section_exprs .len ) {
2603- const next_expr = section_exprs [i + 1 ];
2604- const comma = tree .lastToken (expr ) + 1 ;
2505+ // Write trailing comments since they may enable/disable zig fmt
2506+ buf .clearRetainingCapacity ();
2507+ var after_expr = tree .lastToken (e );
2508+ after_expr += @intFromBool (tree .tokenTag (after_expr + 1 ) == .comma );
2509+ try renderSpace (& sub_r , after_expr , tokenSliceForRender (tree , after_expr ).len , .none );
26052510
2606- if (column_counter != row_size - 1 ) {
2607- if (! expr_newlines [i ] and ! expr_newlines [i + 1 ]) {
2608- // Neither the current or next expression is multiline
2609- try renderToken (r , comma , .space ); // ,
2610- assert (column_widths [column_counter % row_size ] >= expr_widths [i ]);
2611- const padding = column_widths [column_counter % row_size ] - expr_widths [i ];
2612- try ais .splatByteAll (' ' , padding );
2511+ buf .clearRetainingCapacity ();
2512+ }
2513+ }
26132514
2614- column_counter += 1 ;
2615- continue ;
2616- }
2617- }
2515+ var remaining_exprs = array_init .ast .elements ;
2516+ var remaining_widths = expr_widths ;
2517+ while (remaining_exprs .len != 0 ) {
2518+ var row_size : usize = 1 ;
2519+ for (1.. , remaining_exprs , remaining_widths ) | len , e , w | {
2520+ if (w == .nonprint ) break ;
2521+ row_size = len ;
26182522
2619- if (single_line and row_size != 1 ) {
2620- try renderToken (r , comma , .space ); // ,
2621- continue ;
2523+ var after_expr = tree .lastToken (e );
2524+ after_expr += @intFromBool (tree .tokenTag (after_expr + 1 ) == .comma );
2525+ assert (tree .tokenTag (after_expr ) == .comma or after_expr + 1 == rbrace );
2526+ if (! tree .tokensOnSameLine (after_expr , after_expr + 1 ))
2527+ break ;
2528+ } else {
2529+ // All the expressions are on the same line.
2530+ // However, if there is a trailing comma, we put them each on their own line.
2531+ if (tree .tokenTag (rbrace - 1 ) == .comma )
2532+ row_size = 1 ;
2533+ }
2534+
2535+ // Determine the size of this section
2536+ const section_end = end : {
2537+ var line_start = row_size ; // Start after the first row to ignore comments on it
2538+ break :end for (line_start .. , remaining_exprs [line_start .. ]) | i , e | {
2539+ const expr_first = tree .firstToken (e );
2540+ // Any nonprint character terminates the line because they are always put on their
2541+ // own line, so they will not end up on the same line as the trailing comment.
2542+ if (expr_widths [i - 1 ] == .nonprint or ! tree .tokensOnSameLine (expr_first - 1 , expr_first )) {
2543+ line_start = i ;
26222544 }
26232545
2624- column_counter = 0 ;
2625- try renderToken (r , comma , .newline ); // ,
2626- try renderExtraNewline (r , next_expr );
2546+ var after_expr = tree .lastToken (e );
2547+ after_expr += @intFromBool (tree .tokenTag (after_expr + 1 ) == .comma );
2548+ assert (tree .tokenTag (after_expr ) == .comma or after_expr + 1 == rbrace );
2549+ if (hasTrailingComment (tree , after_expr ))
2550+ break line_start ;
2551+ } else remaining_exprs .len ;
2552+ };
2553+ const section_exprs = remaining_exprs [0.. section_end ];
2554+ const section_widths = remaining_widths [0.. section_end ];
2555+ remaining_exprs = remaining_exprs [section_end .. ];
2556+ remaining_widths = remaining_widths [section_end .. ];
2557+
2558+ // Determine the width of each column
2559+ var col_widths = try gpa .alloc (usize , row_size );
2560+ defer gpa .free (col_widths );
2561+ @memset (col_widths , 0 );
2562+
2563+ var col : usize = 0 ;
2564+ for (section_widths ) | w | {
2565+ if (w == .nonprint ) {
2566+ col = 0 ;
2567+ continue ;
2568+ }
2569+ col_widths [col ] = @max (col_widths [col ], @intFromEnum (w ));
2570+ col += 1 ;
2571+ if (col == row_size ) {
2572+ col = 0 ;
26272573 }
26282574 }
26292575
2630- if (expr_index == array_init .ast .elements .len )
2631- break ;
2576+ // Render each expression
2577+ col = 0 ;
2578+ for (0.. , section_exprs , section_widths ) | i , e , w | {
2579+ if (i + 1 == section_end or col + 1 == row_size or
2580+ w == .nonprint or section_widths [i + 1 ] == .nonprint )
2581+ {
2582+ try renderExpression (r , e , .comma );
2583+ col = 0 ;
2584+ if (i + 1 != section_end ) {
2585+ try renderExtraNewline (r , section_exprs [i + 1 ]);
2586+ }
2587+ } else {
2588+ try renderExpression (r , e , .comma_space );
2589+ try ais .splatByteAll (' ' , col_widths [col ] - @intFromEnum (w ));
2590+ col += 1 ;
2591+ }
2592+ }
26322593 }
26332594
2595+ ais .popSpace ();
26342596 ais .popIndent ();
26352597 return renderToken (r , rbrace , space ); // rbrace
26362598}
@@ -3478,7 +3440,7 @@ fn hasComment(tree: Ast, start_token: Ast.TokenIndex, end_token: Ast.TokenIndex)
34783440 const token : Ast.TokenIndex = @intCast (i );
34793441 const start = tree .tokenStart (token ) + tree .tokenSlice (token ).len ;
34803442 const end = tree .tokenStart (token + 1 );
3481- if (mem .indexOf (u8 , tree .source [start .. end ], "//" ) != null ) return true ;
3443+ if (mem .indexOfScalar (u8 , tree .source [start .. end ], '/' ) != null ) return true ;
34823444 }
34833445
34843446 return false ;
@@ -3688,9 +3650,10 @@ fn writeStringLiteralAsIdentifier(r: *Render, token_index: Ast.TokenIndex) Error
36883650 return lexeme .len ;
36893651}
36903652
3691- fn hasSameLineComment (tree : Ast , token_index : Ast.TokenIndex ) bool {
3692- const between_source = tree .source [tree .tokenStart (token_index ).. tree .tokenStart (token_index + 1 )];
3693- for (between_source ) | byte | switch (byte ) {
3653+ fn hasTrailingComment (tree : Ast , t : Ast.TokenIndex ) bool {
3654+ const start = tree .tokenStart (t ) + tree .tokenSlice (t ).len ;
3655+ const between = tree .source [start .. tree .tokenStart (t + 1 )];
3656+ for (between ) | byte | switch (byte ) {
36943657 '\n ' = > return false ,
36953658 '/' = > return true ,
36963659 else = > continue ,
@@ -3702,12 +3665,7 @@ fn hasSameLineComment(tree: Ast, token_index: Ast.TokenIndex) bool {
37023665/// start_token and end_token.
37033666fn anythingBetween (tree : Ast , start_token : Ast.TokenIndex , end_token : Ast.TokenIndex ) bool {
37043667 if (start_token + 1 != end_token ) return true ;
3705- const between_source = tree .source [tree .tokenStart (start_token ).. tree .tokenStart (start_token + 1 )];
3706- for (between_source ) | byte | switch (byte ) {
3707- '/' = > return true ,
3708- else = > continue ,
3709- };
3710- return false ;
3668+ return hasComment (tree , start_token , end_token );
37113669}
37123670
37133671fn writeFixingWhitespace (w : * Writer , slice : []const u8 ) Error ! void {
@@ -3794,29 +3752,6 @@ fn nodeCausesSliceOpSpace(tag: Ast.Node.Tag) bool {
37943752 };
37953753}
37963754
3797- // Returns the number of nodes in `exprs` that are on the same line as `rtoken`.
3798- fn rowSize (tree : Ast , exprs : []const Ast.Node.Index , rtoken : Ast.TokenIndex ) usize {
3799- const first_token = tree .firstToken (exprs [0 ]);
3800- if (tree .tokensOnSameLine (first_token , rtoken )) {
3801- const maybe_comma = rtoken - 1 ;
3802- if (tree .tokenTag (maybe_comma ) == .comma )
3803- return 1 ;
3804- return exprs .len ; // no newlines
3805- }
3806-
3807- var count : usize = 1 ;
3808- for (exprs , 0.. ) | expr , i | {
3809- if (i + 1 < exprs .len ) {
3810- const expr_last_token = tree .lastToken (expr ) + 1 ;
3811- if (! tree .tokensOnSameLine (expr_last_token , tree .firstToken (exprs [i + 1 ]))) return count ;
3812- count += 1 ;
3813- } else {
3814- return count ;
3815- }
3816- }
3817- unreachable ;
3818- }
3819-
38203755/// Automatically inserts indentation of written data by keeping
38213756/// track of the current indentation level
38223757///
0 commit comments