authorgravatar for 178735591+87flowers@users.noreply.github.com87flowers <178735591+87flowers@users.noreply.github.com> 2024-10-16 20:14:46+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-22 17:09:20-08:00
log9b2677c639da2ea9b54c778bb4543abfc8595de9
tree4f07a8ea0d6da78452bfa378907dffe041872670
parentec3e4cc14b004496d8d2ab0d15d03c0c22c3d95c

std/zig/render: Implement space mode to fix comment indentation


1 files changed, 89 insertions(+), 7 deletions(-)

lib/std/zig/render.zig+89-7
...@@ -295,7 +295,11 @@ fn renderMember(...@@ -295,7 +295,11 @@ fn renderMember(
295 .local_var_decl,295 .local_var_decl,
296 .simple_var_decl,296 .simple_var_decl,
297 .aligned_var_decl,297 .aligned_var_decl,
298 => return renderVarDecl(r, tree.fullVarDecl(decl).?, false, .semicolon),298 => {
299 try ais.pushSpace(.semicolon);
300 try renderVarDecl(r, tree.fullVarDecl(decl).?, false, .semicolon);
301 ais.popSpace();
302 },
299303
300 .test_decl => {304 .test_decl => {
301 const test_token = main_tokens[decl];305 const test_token = main_tokens[decl];
...@@ -372,8 +376,16 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {...@@ -372,8 +376,16 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
372376
373 switch (space) {377 switch (space) {
374 .none, .space, .newline, .skip => {},378 .none, .space, .newline, .skip => {},
375 .semicolon => if (token_tags[i] == .semicolon) try renderToken(r, i, .newline),379 .semicolon => if (token_tags[i] == .semicolon) {
376 .comma => if (token_tags[i] == .comma) try renderToken(r, i, .newline),380 ais.enableSpaceMode(.semicolon);
381 try renderToken(r, i, .newline);
382 ais.disableSpaceMode();
383 },
384 .comma => if (token_tags[i] == .comma) {
385 ais.enableSpaceMode(.comma);
386 try renderToken(r, i, .newline);
387 ais.disableSpaceMode();
388 },
377 .comma_space => if (token_tags[i] == .comma) try renderToken(r, i, .space),389 .comma_space => if (token_tags[i] == .comma) try renderToken(r, i, .space),
378 }390 }
379 },391 },
...@@ -764,7 +776,11 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {...@@ -764,7 +776,11 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
764 if (i > lbrace + 1) try renderExtraNewlineToken(r, i);776 if (i > lbrace + 1) try renderExtraNewlineToken(r, i);
765 switch (token_tags[i]) {777 switch (token_tags[i]) {
766 .doc_comment => try renderToken(r, i, .newline),778 .doc_comment => try renderToken(r, i, .newline),
767 .identifier => try renderIdentifier(r, i, .comma, .eagerly_unquote),779 .identifier => {
780 try ais.pushSpace(.comma);
781 try renderIdentifier(r, i, .comma, .eagerly_unquote);
782 ais.popSpace();
783 },
768 .comma => {},784 .comma => {},
769 else => unreachable,785 else => unreachable,
770 }786 }
...@@ -843,7 +859,9 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {...@@ -843,7 +859,9 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
843 try renderToken(r, rparen + 1, .none); // {859 try renderToken(r, rparen + 1, .none); // {
844 } else {860 } else {
845 try renderToken(r, rparen + 1, .newline); // {861 try renderToken(r, rparen + 1, .newline); // {
862 try ais.pushSpace(.comma);
846 try renderExpressions(r, full.ast.cases, .comma);863 try renderExpressions(r, full.ast.cases, .comma);
864 ais.popSpace();
847 }865 }
848 ais.popIndent();866 ais.popIndent();
849 return renderToken(r, tree.lastToken(node), space); // }867 return renderToken(r, tree.lastToken(node), space); // }
...@@ -1625,7 +1643,9 @@ fn renderBuiltinCall(...@@ -1625,7 +1643,9 @@ fn renderBuiltinCall(
1625 try renderToken(r, builtin_token + 1, Space.newline); // (1643 try renderToken(r, builtin_token + 1, Space.newline); // (
16261644
1627 for (params) |param_node| {1645 for (params) |param_node| {
1646 try ais.pushSpace(.comma);
1628 try renderExpression(r, param_node, .comma);1647 try renderExpression(r, param_node, .comma);
1648 ais.popSpace();
1629 }1649 }
1630 ais.popIndent();1650 ais.popIndent();
16311651
...@@ -1793,7 +1813,9 @@ fn renderFnProto(r: *Render, fn_proto: Ast.full.FnProto, space: Space) Error!voi...@@ -1793,7 +1813,9 @@ fn renderFnProto(r: *Render, fn_proto: Ast.full.FnProto, space: Space) Error!voi
1793 }1813 }
1794 const param = fn_proto.ast.params[param_i];1814 const param = fn_proto.ast.params[param_i];
1795 param_i += 1;1815 param_i += 1;
1816 try ais.pushSpace(.comma);
1796 try renderExpression(r, param, .comma);1817 try renderExpression(r, param, .comma);
1818 ais.popSpace();
1797 last_param_token = tree.lastToken(param);1819 last_param_token = tree.lastToken(param);
1798 if (token_tags[last_param_token + 1] == .comma) last_param_token += 1;1820 if (token_tags[last_param_token + 1] == .comma) last_param_token += 1;
1799 }1821 }
...@@ -1856,6 +1878,7 @@ fn renderSwitchCase(...@@ -1856,6 +1878,7 @@ fn renderSwitchCase(
1856 switch_case: Ast.full.SwitchCase,1878 switch_case: Ast.full.SwitchCase,
1857 space: Space,1879 space: Space,
1858) Error!void {1880) Error!void {
1881 const ais = r.ais;
1859 const tree = r.tree;1882 const tree = r.tree;
1860 const node_tags = tree.nodes.items(.tag);1883 const node_tags = tree.nodes.items(.tag);
1861 const token_tags = tree.tokens.items(.tag);1884 const token_tags = tree.tokens.items(.tag);
...@@ -1875,7 +1898,9 @@ fn renderSwitchCase(...@@ -1875,7 +1898,9 @@ fn renderSwitchCase(
1875 try renderToken(r, switch_case.ast.arrow_token - 1, .space); // else keyword1898 try renderToken(r, switch_case.ast.arrow_token - 1, .space); // else keyword
1876 } else if (trailing_comma or has_comment_before_arrow) {1899 } else if (trailing_comma or has_comment_before_arrow) {
1877 // Render each value on a new line1900 // Render each value on a new line
1901 try ais.pushSpace(.comma);
1878 try renderExpressions(r, switch_case.ast.values, .comma);1902 try renderExpressions(r, switch_case.ast.values, .comma);
1903 ais.popSpace();
1879 } else {1904 } else {
1880 // Render on one line1905 // Render on one line
1881 for (switch_case.ast.values) |value_expr| {1906 for (switch_case.ast.values) |value_expr| {
...@@ -1951,6 +1976,7 @@ fn finishRenderBlock(...@@ -1951,6 +1976,7 @@ fn finishRenderBlock(
1951 for (statements, 0..) |stmt, i| {1976 for (statements, 0..) |stmt, i| {
1952 if (i != 0) try renderExtraNewline(r, stmt);1977 if (i != 0) try renderExtraNewline(r, stmt);
1953 if (r.fixups.omit_nodes.contains(stmt)) continue;1978 if (r.fixups.omit_nodes.contains(stmt)) continue;
1979 try ais.pushSpace(.semicolon);
1954 switch (node_tags[stmt]) {1980 switch (node_tags[stmt]) {
1955 .global_var_decl,1981 .global_var_decl,
1956 .local_var_decl,1982 .local_var_decl,
...@@ -1960,6 +1986,7 @@ fn finishRenderBlock(...@@ -1960,6 +1986,7 @@ fn finishRenderBlock(
19601986
1961 else => try renderExpression(r, stmt, .semicolon),1987 else => try renderExpression(r, stmt, .semicolon),
1962 }1988 }
1989 ais.popSpace();
1963 }1990 }
1964 ais.popIndent();1991 ais.popIndent();
19651992
...@@ -2003,7 +2030,10 @@ fn renderStructInit(...@@ -2003,7 +2030,10 @@ fn renderStructInit(
2003 const expr = nodes[field_node];2030 const expr = nodes[field_node];
2004 var space_after_equal: Space = if (expr == .multiline_string_literal) .none else .space;2031 var space_after_equal: Space = if (expr == .multiline_string_literal) .none else .space;
2005 try renderToken(r, struct_init.ast.lbrace + 3, space_after_equal); // =2032 try renderToken(r, struct_init.ast.lbrace + 3, space_after_equal); // =
2033
2034 try ais.pushSpace(.comma);
2006 try renderExpressionFixup(r, field_node, .comma);2035 try renderExpressionFixup(r, field_node, .comma);
2036 ais.popSpace();
20072037
2008 for (struct_init.ast.fields[1..]) |field_init| {2038 for (struct_init.ast.fields[1..]) |field_init| {
2009 const init_token = tree.firstToken(field_init);2039 const init_token = tree.firstToken(field_init);
...@@ -2012,7 +2042,10 @@ fn renderStructInit(...@@ -2012,7 +2042,10 @@ fn renderStructInit(
2012 try renderIdentifier(r, init_token - 2, .space, .eagerly_unquote); // name2042 try renderIdentifier(r, init_token - 2, .space, .eagerly_unquote); // name
2013 space_after_equal = if (nodes[field_init] == .multiline_string_literal) .none else .space;2043 space_after_equal = if (nodes[field_init] == .multiline_string_literal) .none else .space;
2014 try renderToken(r, init_token - 1, space_after_equal); // =2044 try renderToken(r, init_token - 1, space_after_equal); // =
2045
2046 try ais.pushSpace(.comma);
2015 try renderExpressionFixup(r, field_init, .comma);2047 try renderExpressionFixup(r, field_init, .comma);
2048 ais.popSpace();
2016 }2049 }
20172050
2018 ais.popIndent();2051 ais.popIndent();
...@@ -2182,7 +2215,10 @@ fn renderArrayInit(...@@ -2182,7 +2215,10 @@ fn renderArrayInit(
2182 column_counter = 0;2215 column_counter = 0;
2183 }2216 }
2184 } else {2217 } else {
2218 try ais.pushSpace(.comma);
2185 try renderExpression(&sub_render, expr, .comma);2219 try renderExpression(&sub_render, expr, .comma);
2220 ais.popSpace();
2221
2186 const width = sub_expr_buffer.items.len - start - 2;2222 const width = sub_expr_buffer.items.len - start - 2;
2187 const this_contains_newline = mem.indexOfScalar(u8, sub_expr_buffer.items[start .. sub_expr_buffer.items.len - 1], '\n') != null;2223 const this_contains_newline = mem.indexOfScalar(u8, sub_expr_buffer.items[start .. sub_expr_buffer.items.len - 1], '\n') != null;
2188 contains_newline = contains_newline or this_contains_newline;2224 contains_newline = contains_newline or this_contains_newline;
...@@ -2362,7 +2398,11 @@ fn renderContainerDecl(...@@ -2362,7 +2398,11 @@ fn renderContainerDecl(
2362 .container_field_init,2398 .container_field_init,
2363 .container_field_align,2399 .container_field_align,
2364 .container_field,2400 .container_field,
2365 => try renderMember(r, container, member, .comma),2401 => {
2402 try ais.pushSpace(.comma);
2403 try renderMember(r, container, member, .comma);
2404 ais.popSpace();
2405 },
23662406
2367 else => try renderMember(r, container, member, .newline),2407 else => try renderMember(r, container, member, .newline),
2368 }2408 }
...@@ -2450,13 +2490,17 @@ fn renderAsm(...@@ -2450,13 +2490,17 @@ fn renderAsm(
2450 try renderToken(r, comma, .newline); // ,2490 try renderToken(r, comma, .newline); // ,
2451 try renderExtraNewlineToken(r, tree.firstToken(next_asm_output));2491 try renderExtraNewlineToken(r, tree.firstToken(next_asm_output));
2452 } else if (asm_node.inputs.len == 0 and asm_node.first_clobber == null) {2492 } else if (asm_node.inputs.len == 0 and asm_node.first_clobber == null) {
2493 try ais.pushSpace(.comma);
2453 try renderAsmOutput(r, asm_output, .comma);2494 try renderAsmOutput(r, asm_output, .comma);
2495 ais.popSpace();
2454 ais.popIndent();2496 ais.popIndent();
2455 ais.setIndentDelta(indent_delta);2497 ais.setIndentDelta(indent_delta);
2456 ais.popIndent();2498 ais.popIndent();
2457 return renderToken(r, asm_node.ast.rparen, space); // rparen2499 return renderToken(r, asm_node.ast.rparen, space); // rparen
2458 } else {2500 } else {
2501 try ais.pushSpace(.comma);
2459 try renderAsmOutput(r, asm_output, .comma);2502 try renderAsmOutput(r, asm_output, .comma);
2503 ais.popSpace();
2460 const comma_or_colon = tree.lastToken(asm_output) + 1;2504 const comma_or_colon = tree.lastToken(asm_output) + 1;
2461 ais.popIndent();2505 ais.popIndent();
2462 break :colon2 switch (token_tags[comma_or_colon]) {2506 break :colon2 switch (token_tags[comma_or_colon]) {
...@@ -2482,13 +2526,17 @@ fn renderAsm(...@@ -2482,13 +2526,17 @@ fn renderAsm(
2482 try renderToken(r, first_token - 1, .newline); // ,2526 try renderToken(r, first_token - 1, .newline); // ,
2483 try renderExtraNewlineToken(r, first_token);2527 try renderExtraNewlineToken(r, first_token);
2484 } else if (asm_node.first_clobber == null) {2528 } else if (asm_node.first_clobber == null) {
2529 try ais.pushSpace(.comma);
2485 try renderAsmInput(r, asm_input, .comma);2530 try renderAsmInput(r, asm_input, .comma);
2531 ais.popSpace();
2486 ais.popIndent();2532 ais.popIndent();
2487 ais.setIndentDelta(indent_delta);2533 ais.setIndentDelta(indent_delta);
2488 ais.popIndent();2534 ais.popIndent();
2489 return renderToken(r, asm_node.ast.rparen, space); // rparen2535 return renderToken(r, asm_node.ast.rparen, space); // rparen
2490 } else {2536 } else {
2537 try ais.pushSpace(.comma);
2491 try renderAsmInput(r, asm_input, .comma);2538 try renderAsmInput(r, asm_input, .comma);
2539 ais.popSpace();
2492 const comma_or_colon = tree.lastToken(asm_input) + 1;2540 const comma_or_colon = tree.lastToken(asm_input) + 1;
2493 ais.popIndent();2541 ais.popIndent();
2494 break :colon3 switch (token_tags[comma_or_colon]) {2542 break :colon3 switch (token_tags[comma_or_colon]) {
...@@ -2574,7 +2622,9 @@ fn renderParamList(...@@ -2574,7 +2622,9 @@ fn renderParamList(
25742622
2575 try renderExtraNewline(r, params[i + 1]);2623 try renderExtraNewline(r, params[i + 1]);
2576 } else {2624 } else {
2625 try ais.pushSpace(.comma);
2577 try renderExpression(r, param_node, .comma);2626 try renderExpression(r, param_node, .comma);
2627 ais.popSpace();
2578 }2628 }
2579 }2629 }
2580 ais.popIndent();2630 ais.popIndent();
...@@ -2691,7 +2741,8 @@ fn renderSpace(r: *Render, token_index: Ast.TokenIndex, lexeme_len: usize, space...@@ -2691,7 +2741,8 @@ fn renderSpace(r: *Render, token_index: Ast.TokenIndex, lexeme_len: usize, space
2691 if (space == .comma and token_tags[token_index + 1] != .comma) {2741 if (space == .comma and token_tags[token_index + 1] != .comma) {
2692 try ais.writer().writeByte(',');2742 try ais.writer().writeByte(',');
2693 }2743 }
26942744 if (space == .semicolon or space == .comma) ais.enableSpaceMode(space);
2745 defer ais.disableSpaceMode();
2695 const comment = try renderComments(r, token_start + lexeme_len, token_starts[token_index + 1]);2746 const comment = try renderComments(r, token_start + lexeme_len, token_starts[token_index + 1]);
2696 switch (space) {2747 switch (space) {
2697 .none => {},2748 .none => {},
...@@ -3254,6 +3305,10 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {...@@ -3254,6 +3305,10 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
3254 indent_type: IndentType,3305 indent_type: IndentType,
3255 realized: bool,3306 realized: bool,
3256 };3307 };
3308 const SpaceElem = struct {
3309 space: Space,
3310 indent_count: usize,
3311 };
32573312
3258 underlying_writer: UnderlyingWriter,3313 underlying_writer: UnderlyingWriter,
32593314
...@@ -3268,6 +3323,8 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {...@@ -3268,6 +3323,8 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
3268 indent_count: usize = 0,3323 indent_count: usize = 0,
3269 indent_delta: usize,3324 indent_delta: usize,
3270 indent_stack: std.ArrayList(StackElem),3325 indent_stack: std.ArrayList(StackElem),
3326 space_stack: std.ArrayList(SpaceElem),
3327 space_mode: ?usize = null,
3271 disable_indent_committing: usize = 0,3328 disable_indent_committing: usize = 0,
3272 current_line_empty: bool = true,3329 current_line_empty: bool = true,
3273 /// the most recently applied indent3330 /// the most recently applied indent
...@@ -3278,11 +3335,13 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {...@@ -3278,11 +3335,13 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
3278 .underlying_writer = buffer.writer(),3335 .underlying_writer = buffer.writer(),
3279 .indent_delta = indent_delta_,3336 .indent_delta = indent_delta_,
3280 .indent_stack = std.ArrayList(StackElem).init(buffer.allocator),3337 .indent_stack = std.ArrayList(StackElem).init(buffer.allocator),
3338 .space_stack = std.ArrayList(SpaceElem).init(buffer.allocator),
3281 };3339 };
3282 }3340 }
32833341
3284 pub fn deinit(self: *Self) void {3342 pub fn deinit(self: *Self) void {
3285 self.indent_stack.deinit();3343 self.indent_stack.deinit();
3344 self.space_stack.deinit();
3286 }3345 }
32873346
3288 pub fn writer(self: *Self) Writer {3347 pub fn writer(self: *Self) Writer {
...@@ -3347,6 +3406,28 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {...@@ -3347,6 +3406,28 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
3347 self.disable_indent_committing -= 1;3406 self.disable_indent_committing -= 1;
3348 }3407 }
33493408
3409 pub fn pushSpace(self: *Self, space: Space) !void {
3410 try self.space_stack.append(.{ .space = space, .indent_count = self.indent_count });
3411 }
3412
3413 pub fn popSpace(self: *Self) void {
3414 _ = self.space_stack.pop();
3415 }
3416
3417 pub fn enableSpaceMode(self: *Self, space: Space) void {
3418 if (self.space_stack.items.len == 0) return;
3419 const curr = self.space_stack.getLast();
3420 if (curr.space != space) {
3421 return;
3422 }
3423 assert(curr.space == space);
3424 self.space_mode = curr.indent_count;
3425 }
3426
3427 pub fn disableSpaceMode(self: *Self) void {
3428 self.space_mode = null;
3429 }
3430
3350 /// Insert a newline unless the current line is blank3431 /// Insert a newline unless the current line is blank
3351 pub fn maybeInsertNewline(self: *Self) WriteError!void {3432 pub fn maybeInsertNewline(self: *Self) WriteError!void {
3352 if (!self.current_line_empty)3433 if (!self.current_line_empty)
...@@ -3390,7 +3471,8 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {...@@ -3390,7 +3471,8 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
3390 }3471 }
33913472
3392 fn currentIndent(self: *Self) usize {3473 fn currentIndent(self: *Self) usize {
3393 return self.indent_count * self.indent_delta;3474 const indent_count = self.space_mode orelse self.indent_count;
3475 return indent_count * self.indent_delta;
3394 }3476 }
3395 };3477 };
3396}3478}