@@ -2426,170 +2426,132 @@ fn renderArrayInit(
24262426
24272427 try ais .pushIndent (.normal );
24282428 try renderToken (r , array_init .ast .lbrace , .newline );
2429-
2430- var expr_index : usize = 0 ;
2431- while (true ) {
2432- const row_size = rowSize (tree , array_init .ast .elements [expr_index .. ], rbrace );
2433- const row_exprs = array_init .ast .elements [expr_index .. ];
2434- // A place to store the width of each expression and its column's maximum
2435- const widths = try gpa .alloc (usize , row_exprs .len + row_size );
2436- defer gpa .free (widths );
2437- @memset (widths , 0 );
2438-
2439- const expr_newlines = try gpa .alloc (bool , row_exprs .len );
2440- defer gpa .free (expr_newlines );
2441- @memset (expr_newlines , false );
2442-
2443- const expr_widths = widths [0.. row_exprs .len ];
2444- const column_widths = widths [row_exprs .len .. ];
2445-
2446- // Find next row with trailing comment (if any) to end the current section.
2447- const section_end = sec_end : {
2448- var this_line_first_expr : usize = 0 ;
2449- var this_line_size = rowSize (tree , row_exprs , rbrace );
2450- for (row_exprs , 0.. ) | expr , i | {
2451- // Ignore comment on first line of this section.
2452- if (i == 0 ) continue ;
2453- const expr_last_token = tree .lastToken (expr );
2454- if (tree .tokensOnSameLine (tree .firstToken (row_exprs [0 ]), expr_last_token ))
2455- continue ;
2456- // Track start of line containing comment.
2457- if (! tree .tokensOnSameLine (tree .firstToken (row_exprs [this_line_first_expr ]), expr_last_token )) {
2458- this_line_first_expr = i ;
2459- this_line_size = rowSize (tree , row_exprs [this_line_first_expr .. ], rbrace );
2460- }
2461-
2462- const maybe_comma = expr_last_token + 1 ;
2463- if (tree .tokenTag (maybe_comma ) == .comma ) {
2464- if (hasSameLineComment (tree , maybe_comma ))
2465- break :sec_end i - this_line_size + 1 ;
2466- }
2467- }
2468- break :sec_end row_exprs .len ;
2469- };
2470- expr_index += section_end ;
2471-
2472- const section_exprs = row_exprs [0.. section_end ];
2473-
2474- var sub_expr_buffer : std.io.Writer.Allocating = .init (gpa );
2475- defer sub_expr_buffer .deinit ();
2476-
2477- const sub_expr_buffer_starts = try gpa .alloc (usize , section_exprs .len + 1 );
2478- defer gpa .free (sub_expr_buffer_starts );
2479-
2480- var auto_indenting_stream : AutoIndentingStream = .init (gpa , & sub_expr_buffer .writer , indent_delta );
2481- defer auto_indenting_stream .deinit ();
2482- var sub_render : Render = .{
2429+ try ais .pushSpace (.comma );
2430+
2431+ const expr_widths = try gpa .alloc (enum (usize ) {
2432+ /// The expression contains non-printable characters (e.g. unicode / newlines)
2433+ /// or has formatting disabled at the start or end.
2434+ nonprint = std .math .maxInt (usize ),
2435+ _ ,
2436+ }, array_init .ast .elements .len );
2437+ defer gpa .free (expr_widths );
2438+ {
2439+ var buf : std.Io.Writer.Allocating = .init (gpa );
2440+ defer buf .deinit ();
2441+ var sub_ais : AutoIndentingStream = .init (gpa , & buf .writer , indent_delta );
2442+ sub_ais .disabled_offset = ais .disabled_offset ;
2443+ defer sub_ais .deinit ();
2444+ var sub_r : Render = .{
24832445 .gpa = r .gpa ,
2484- .ais = & auto_indenting_stream ,
2446+ .ais = & sub_ais ,
24852447 .tree = r .tree ,
24862448 .fixups = r .fixups ,
24872449 };
2488-
2489- // Calculate size of columns in current section
2490- var column_counter : usize = 0 ;
2491- var single_line = true ;
2492- var contains_newline = false ;
2493- for (section_exprs , 0.. ) | expr , i | {
2494- const start = sub_expr_buffer .getWritten ().len ;
2495- sub_expr_buffer_starts [i ] = start ;
2496-
2497- if (i + 1 < section_exprs .len ) {
2498- try renderExpression (& sub_render , expr , .none );
2499- const written = sub_expr_buffer .getWritten ();
2500- const width = written .len - start ;
2501- const this_contains_newline = mem .indexOfScalar (u8 , written [start .. ], '\n ' ) != null ;
2502- contains_newline = contains_newline or this_contains_newline ;
2503- expr_widths [i ] = width ;
2504- expr_newlines [i ] = this_contains_newline ;
2505-
2506- if (! this_contains_newline ) {
2507- const column = column_counter % row_size ;
2508- column_widths [column ] = @max (column_widths [column ], width );
2509-
2510- const expr_last_token = tree .lastToken (expr ) + 1 ;
2511- const next_expr = section_exprs [i + 1 ];
2512- column_counter += 1 ;
2513- if (! tree .tokensOnSameLine (expr_last_token , tree .firstToken (next_expr ))) single_line = false ;
2514- } else {
2515- single_line = false ;
2516- column_counter = 0 ;
2517- }
2450+ for (array_init .ast .elements , expr_widths ) | e , * width | {
2451+ const begin_disabled = sub_ais .disabled_offset != null ;
2452+ // `.skip` space so trailing commments aren't included
2453+ try renderExpressionComma (& sub_r , e , .skip );
2454+ if (! begin_disabled and sub_ais .disabled_offset == null ) {
2455+ const w = buf .getWritten ();
2456+ width .* = for (w ) | c | {
2457+ if (! std .ascii .isPrint (c ))
2458+ break .nonprint ;
2459+ } else @enumFromInt (w .len - @intFromBool (w [w .len - 1 ] == ',' ));
25182460 } else {
2519- try ais .pushSpace (.comma );
2520- try renderExpression (& sub_render , expr , .comma );
2521- ais .popSpace ();
2522-
2523- const written = sub_expr_buffer .getWritten ();
2524- const width = written .len - start - 2 ;
2525- const this_contains_newline = mem .indexOfScalar (u8 , written [start .. written .len - 1 ], '\n ' ) != null ;
2526- contains_newline = contains_newline or this_contains_newline ;
2527- expr_widths [i ] = width ;
2528- expr_newlines [i ] = contains_newline ;
2529-
2530- if (! contains_newline ) {
2531- const column = column_counter % row_size ;
2532- column_widths [column ] = @max (column_widths [column ], width );
2533- }
2461+ width .* = .nonprint ;
25342462 }
2535- }
2536- sub_expr_buffer_starts [section_exprs .len ] = sub_expr_buffer .getWritten ().len ;
25372463
2538- // Render exprs in current section.
2539- column_counter = 0 ;
2540- for (section_exprs , 0.. ) | expr , i | {
2541- const start = sub_expr_buffer_starts [i ];
2542- const end = sub_expr_buffer_starts [i + 1 ];
2543- const expr_text = sub_expr_buffer .getWritten ()[start .. end ];
2544- if (! expr_newlines [i ]) {
2545- try ais .writeAll (expr_text );
2546- } else {
2547- var by_line = std .mem .splitScalar (u8 , expr_text , '\n ' );
2548- var last_line_was_empty = false ;
2549- try ais .writeAll (by_line .first ());
2550- while (by_line .next ()) | line | {
2551- if (std .mem .startsWith (u8 , line , "//" ) and last_line_was_empty ) {
2552- try ais .insertNewline ();
2553- } else {
2554- try ais .maybeInsertNewline ();
2555- }
2556- last_line_was_empty = (line .len == 0 );
2557- try ais .writeAll (line );
2558- }
2559- }
2560-
2561- if (i + 1 < section_exprs .len ) {
2562- const next_expr = section_exprs [i + 1 ];
2563- const comma = tree .lastToken (expr ) + 1 ;
2464+ // Write trailing comments since they may enable/disable zig fmt
2465+ buf .clearRetainingCapacity ();
2466+ var after_expr = tree .lastToken (e );
2467+ after_expr += @intFromBool (tree .tokenTag (after_expr + 1 ) == .comma );
2468+ try renderSpace (& sub_r , after_expr , tokenSliceForRender (tree , after_expr ).len , .none );
25642469
2565- if (column_counter != row_size - 1 ) {
2566- if (! expr_newlines [i ] and ! expr_newlines [i + 1 ]) {
2567- // Neither the current or next expression is multiline
2568- try renderToken (r , comma , .space ); // ,
2569- assert (column_widths [column_counter % row_size ] >= expr_widths [i ]);
2570- const padding = column_widths [column_counter % row_size ] - expr_widths [i ];
2571- try ais .splatByteAll (' ' , padding );
2470+ buf .clearRetainingCapacity ();
2471+ }
2472+ }
25722473
2573- column_counter += 1 ;
2574- continue ;
2575- }
2576- }
2474+ var remaining_exprs = array_init .ast .elements ;
2475+ var remaining_widths = expr_widths ;
2476+ while (remaining_exprs .len != 0 ) {
2477+ var row_size : usize = 1 ;
2478+ for (1.. , remaining_exprs , remaining_widths ) | len , e , w | {
2479+ if (w == .nonprint ) break ;
2480+ row_size = len ;
25772481
2578- if (single_line and row_size != 1 ) {
2579- try renderToken (r , comma , .space ); // ,
2580- continue ;
2482+ var after_expr = tree .lastToken (e );
2483+ after_expr += @intFromBool (tree .tokenTag (after_expr + 1 ) == .comma );
2484+ assert (tree .tokenTag (after_expr ) == .comma or after_expr + 1 == rbrace );
2485+ if (! tree .tokensOnSameLine (after_expr , after_expr + 1 ))
2486+ break ;
2487+ } else {
2488+ // All the expressions are on the same line.
2489+ // However, if there is a trailing comma, we put them each on their own line.
2490+ if (tree .tokenTag (rbrace - 1 ) == .comma )
2491+ row_size = 1 ;
2492+ }
2493+
2494+ // Determine the size of this section
2495+ const section_end = end : {
2496+ var line_start = row_size ; // Start after the first row to ignore comments on it
2497+ break :end for (line_start .. , remaining_exprs [line_start .. ]) | i , e | {
2498+ const expr_first = tree .firstToken (e );
2499+ // Any nonprint character terminates the line because they are always put on their
2500+ // own line, so they will not end up on the same line as the trailing comment.
2501+ if (expr_widths [i - 1 ] == .nonprint or ! tree .tokensOnSameLine (expr_first - 1 , expr_first )) {
2502+ line_start = i ;
25812503 }
25822504
2583- column_counter = 0 ;
2584- try renderToken (r , comma , .newline ); // ,
2585- try renderExtraNewline (r , next_expr );
2505+ var after_expr = tree .lastToken (e );
2506+ after_expr += @intFromBool (tree .tokenTag (after_expr + 1 ) == .comma );
2507+ assert (tree .tokenTag (after_expr ) == .comma or after_expr + 1 == rbrace );
2508+ if (hasTrailingComment (tree , after_expr ))
2509+ break line_start ;
2510+ } else remaining_exprs .len ;
2511+ };
2512+ const section_exprs = remaining_exprs [0.. section_end ];
2513+ const section_widths = remaining_widths [0.. section_end ];
2514+ remaining_exprs = remaining_exprs [section_end .. ];
2515+ remaining_widths = remaining_widths [section_end .. ];
2516+
2517+ // Determine the width of each column
2518+ var col_widths = try gpa .alloc (usize , row_size );
2519+ defer gpa .free (col_widths );
2520+ @memset (col_widths , 0 );
2521+
2522+ var col : usize = 0 ;
2523+ for (section_widths ) | w | {
2524+ if (w == .nonprint ) {
2525+ col = 0 ;
2526+ continue ;
2527+ }
2528+ col_widths [col ] = @max (col_widths [col ], @intFromEnum (w ));
2529+ col += 1 ;
2530+ if (col == row_size ) {
2531+ col = 0 ;
25862532 }
25872533 }
25882534
2589- if (expr_index == array_init .ast .elements .len )
2590- break ;
2535+ // Render each expression
2536+ col = 0 ;
2537+ for (0.. , section_exprs , section_widths ) | i , e , w | {
2538+ if (i + 1 == section_end or col + 1 == row_size or
2539+ w == .nonprint or section_widths [i + 1 ] == .nonprint )
2540+ {
2541+ try renderExpression (r , e , .comma );
2542+ col = 0 ;
2543+ if (i + 1 != section_end ) {
2544+ try renderExtraNewline (r , section_exprs [i + 1 ]);
2545+ }
2546+ } else {
2547+ try renderExpression (r , e , .comma_space );
2548+ try ais .splatByteAll (' ' , col_widths [col ] - @intFromEnum (w ));
2549+ col += 1 ;
2550+ }
2551+ }
25912552 }
25922553
2554+ ais .popSpace ();
25932555 ais .popIndent ();
25942556 return renderToken (r , rbrace , space ); // rbrace
25952557}
@@ -3437,7 +3399,7 @@ fn hasComment(tree: Ast, start_token: Ast.TokenIndex, end_token: Ast.TokenIndex)
34373399 const token : Ast.TokenIndex = @intCast (i );
34383400 const start = tree .tokenStart (token ) + tree .tokenSlice (token ).len ;
34393401 const end = tree .tokenStart (token + 1 );
3440- if (mem .indexOf (u8 , tree .source [start .. end ], "//" ) != null ) return true ;
3402+ if (mem .indexOfScalar (u8 , tree .source [start .. end ], '/' ) != null ) return true ;
34413403 }
34423404
34433405 return false ;
@@ -3647,9 +3609,10 @@ fn writeStringLiteralAsIdentifier(r: *Render, token_index: Ast.TokenIndex) Error
36473609 return lexeme .len ;
36483610}
36493611
3650- fn hasSameLineComment (tree : Ast , token_index : Ast.TokenIndex ) bool {
3651- const between_source = tree .source [tree .tokenStart (token_index ).. tree .tokenStart (token_index + 1 )];
3652- for (between_source ) | byte | switch (byte ) {
3612+ fn hasTrailingComment (tree : Ast , t : Ast.TokenIndex ) bool {
3613+ const start = tree .tokenStart (t ) + tree .tokenSlice (t ).len ;
3614+ const between = tree .source [start .. tree .tokenStart (t + 1 )];
3615+ for (between ) | byte | switch (byte ) {
36533616 '\n ' = > return false ,
36543617 '/' = > return true ,
36553618 else = > continue ,
@@ -3661,12 +3624,7 @@ fn hasSameLineComment(tree: Ast, token_index: Ast.TokenIndex) bool {
36613624/// start_token and end_token.
36623625fn anythingBetween (tree : Ast , start_token : Ast.TokenIndex , end_token : Ast.TokenIndex ) bool {
36633626 if (start_token + 1 != end_token ) return true ;
3664- const between_source = tree .source [tree .tokenStart (start_token ).. tree .tokenStart (start_token + 1 )];
3665- for (between_source ) | byte | switch (byte ) {
3666- '/' = > return true ,
3667- else = > continue ,
3668- };
3669- return false ;
3627+ return hasComment (tree , start_token , end_token );
36703628}
36713629
36723630fn writeFixingWhitespace (w : * Writer , slice : []const u8 ) Error ! void {
@@ -3753,29 +3711,6 @@ fn nodeCausesSliceOpSpace(tag: Ast.Node.Tag) bool {
37533711 };
37543712}
37553713
3756- // Returns the number of nodes in `exprs` that are on the same line as `rtoken`.
3757- fn rowSize (tree : Ast , exprs : []const Ast.Node.Index , rtoken : Ast.TokenIndex ) usize {
3758- const first_token = tree .firstToken (exprs [0 ]);
3759- if (tree .tokensOnSameLine (first_token , rtoken )) {
3760- const maybe_comma = rtoken - 1 ;
3761- if (tree .tokenTag (maybe_comma ) == .comma )
3762- return 1 ;
3763- return exprs .len ; // no newlines
3764- }
3765-
3766- var count : usize = 1 ;
3767- for (exprs , 0.. ) | expr , i | {
3768- if (i + 1 < exprs .len ) {
3769- const expr_last_token = tree .lastToken (expr ) + 1 ;
3770- if (! tree .tokensOnSameLine (expr_last_token , tree .firstToken (exprs [i + 1 ]))) return count ;
3771- count += 1 ;
3772- } else {
3773- return count ;
3774- }
3775- }
3776- unreachable ;
3777- }
3778-
37793714/// Automatically inserts indentation of written data by keeping
37803715/// track of the current indentation level
37813716///
0 commit comments