authorgravatar for 178735591+87flowers@users.noreply.github.com87flowers <178735591+87flowers@users.noreply.github.com> 2024-10-16 19:15:19+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-22 17:09:20-08:00
logec3e4cc14b004496d8d2ab0d15d03c0c22c3d95c
tree940863ed7c18f4a33771f1eb50be574937bb18cd
parent1b0584fd02a907d096265778044985d4c23fc05f

std/zig/render: Initial implementation of indentation


1 files changed, 119 insertions(+), 185 deletions(-)

lib/std/zig/render.zig+119-185
......@@ -82,6 +82,7 @@ const Render = struct {
8282pub fn renderTree(buffer: *std.ArrayList(u8), tree: Ast, fixups: Fixups) Error!void {
8383 assert(tree.errors.len == 0); // Cannot render an invalid tree.
8484 var auto_indenting_stream = Ais.init(buffer, indent_delta);
85 defer auto_indenting_stream.deinit();
8586 var r: Render = .{
8687 .gpa = buffer.allocator,
8788 .ais = &auto_indenting_stream,
......@@ -195,7 +196,7 @@ fn renderMember(
195196 try renderExpression(r, fn_proto, .space);
196197 const body_node = datas[decl].rhs;
197198 if (r.fixups.gut_functions.contains(decl)) {
198 ais.pushIndent();
199 try ais.pushIndent(.normal);
199200 const lbrace = tree.nodes.items(.main_token)[body_node];
200201 try renderToken(r, lbrace, .newline);
201202 try discardAllParams(r, fn_proto);
......@@ -204,7 +205,7 @@ fn renderMember(
204205 try ais.insertNewline();
205206 try renderToken(r, tree.lastToken(body_node), space); // rbrace
206207 } else if (r.fixups.unused_var_decls.count() != 0) {
207 ais.pushIndentNextLine();
208 try ais.pushIndent(.normal);
208209 const lbrace = tree.nodes.items(.main_token)[body_node];
209210 try renderToken(r, lbrace, .newline);
210211
......@@ -358,13 +359,16 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
358359 => return renderToken(r, main_tokens[node], space),
359360
360361 .multiline_string_literal => {
361 var locked_indents = ais.lockOneShotIndent();
362362 try ais.maybeInsertNewline();
363363
364364 var i = datas[node].lhs;
365365 while (i <= datas[node].rhs) : (i += 1) try renderToken(r, i, .newline);
366366
367 while (locked_indents > 0) : (locked_indents -= 1) ais.popIndent();
367 // dedent the next thing that comes after a multiline string literal
368 if (!ais.indentStackEmpty()) {
369 ais.popIndent();
370 try ais.pushIndent(.normal);
371 }
368372
369373 switch (space) {
370374 .none, .space, .newline, .skip => {},
......@@ -442,6 +446,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
442446
443447 try renderExpression(r, datas[node].lhs, .space); // target
444448
449 try ais.pushIndent(.normal);
445450 if (token_tags[fallback_first - 1] == .pipe) {
446451 try renderToken(r, main_token, .space); // catch keyword
447452 try renderToken(r, main_token + 1, .none); // pipe
......@@ -451,38 +456,27 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
451456 assert(token_tags[fallback_first - 1] == .keyword_catch);
452457 try renderToken(r, main_token, after_op_space); // catch keyword
453458 }
454
455 ais.pushIndentOneShot();
456459 try renderExpression(r, datas[node].rhs, space); // fallback
460 ais.popIndent();
457461 },
458462
459463 .field_access => {
460464 const main_token = main_tokens[node];
461465 const field_access = datas[node];
462466
467 try ais.pushIndent(.normal);
463468 try renderExpression(r, field_access.lhs, .none);
464469
465470 // Allow a line break between the lhs and the dot if the lhs and rhs
466471 // are on different lines.
467472 const lhs_last_token = tree.lastToken(field_access.lhs);
468473 const same_line = tree.tokensOnSameLine(lhs_last_token, main_token + 1);
469 if (!same_line) {
470 if (!hasComment(tree, lhs_last_token, main_token)) try ais.insertNewline();
471 ais.pushIndentOneShot();
472 }
474 if (!same_line and !hasComment(tree, lhs_last_token, main_token)) try ais.insertNewline();
473475
474476 try renderToken(r, main_token, .none); // .
475477
476 // This check ensures that zag() is indented in the following example:
477 // const x = foo
478 // .bar()
479 // . // comment
480 // zag();
481 if (!same_line and hasComment(tree, main_token, main_token + 1)) {
482 ais.pushIndentOneShot();
483 }
484
485 return renderIdentifier(r, field_access.rhs, space, .eagerly_unquote); // field
478 try renderIdentifier(r, field_access.rhs, space, .eagerly_unquote); // field
479 ais.popIndent();
486480 },
487481
488482 .error_union,
......@@ -555,15 +549,14 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
555549 const infix = datas[node];
556550 try renderExpression(r, infix.lhs, .space);
557551 const op_token = main_tokens[node];
552 try ais.pushIndent(.normal);
558553 if (tree.tokensOnSameLine(op_token, op_token + 1)) {
559554 try renderToken(r, op_token, .space);
560555 } else {
561 ais.pushIndent();
562556 try renderToken(r, op_token, .newline);
563 ais.popIndent();
564557 }
565 ais.pushIndentOneShot();
566 return renderExpression(r, infix.rhs, space);
558 try renderExpression(r, infix.rhs, space);
559 ais.popIndent();
567560 },
568561
569562 .assign_destructure => {
......@@ -585,15 +578,14 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
585578 else => try renderExpression(r, variable_node, variable_space),
586579 }
587580 }
581 try ais.pushIndent(.normal);
588582 if (tree.tokensOnSameLine(full.ast.equal_token, full.ast.equal_token + 1)) {
589583 try renderToken(r, full.ast.equal_token, .space);
590584 } else {
591 ais.pushIndent();
592585 try renderToken(r, full.ast.equal_token, .newline);
593 ais.popIndent();
594586 }
595 ais.pushIndentOneShot();
596 return renderExpression(r, full.ast.value_expr, space);
587 try renderExpression(r, full.ast.value_expr, space);
588 ais.popIndent();
597589 },
598590
599591 .bit_not,
......@@ -671,7 +663,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
671663 const one_line = tree.tokensOnSameLine(lbracket, rbracket);
672664 const inner_space = if (one_line) Space.none else Space.newline;
673665 try renderExpression(r, suffix.lhs, .none);
674 ais.pushIndentNextLine();
666 try ais.pushIndent(.normal);
675667 try renderToken(r, lbracket, inner_space); // [
676668 try renderExpression(r, suffix.rhs, inner_space);
677669 ais.popIndent();
......@@ -723,8 +715,9 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
723715
724716 .grouped_expression => {
725717 try renderToken(r, main_tokens[node], .none); // lparen
726 ais.pushIndentOneShot();
718 try ais.pushIndent(.normal);
727719 try renderExpression(r, datas[node].lhs, .none);
720 ais.popIndent();
728721 return renderToken(r, datas[node].rhs, space); // rparen
729722 },
730723
......@@ -764,7 +757,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
764757 return renderToken(r, rbrace, space);
765758 } else if (token_tags[rbrace - 1] == .comma) {
766759 // There is a trailing comma so render each member on a new line.
767 ais.pushIndentNextLine();
760 try ais.pushIndent(.normal);
768761 try renderToken(r, lbrace, .newline);
769762 var i = lbrace + 1;
770763 while (i < rbrace) : (i += 1) {
......@@ -845,7 +838,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
845838 try renderExpression(r, full.ast.condition, .none); // condition expression
846839 try renderToken(r, rparen, .space); // )
847840
848 ais.pushIndentNextLine();
841 try ais.pushIndent(.normal);
849842 if (full.ast.cases.len == 0) {
850843 try renderToken(r, rparen + 1, .none); // {
851844 } else {
......@@ -920,7 +913,7 @@ fn renderArrayType(
920913 const rbracket = tree.firstToken(array_type.ast.elem_type) - 1;
921914 const one_line = tree.tokensOnSameLine(array_type.ast.lbracket, rbracket);
922915 const inner_space = if (one_line) Space.none else Space.newline;
923 ais.pushIndentNextLine();
916 try ais.pushIndent(.normal);
924917 try renderToken(r, array_type.ast.lbracket, inner_space); // lbracket
925918 try renderExpression(r, array_type.ast.elem_count, inner_space);
926919 if (array_type.ast.sentinel != 0) {
......@@ -1236,13 +1229,10 @@ fn renderVarDeclWithoutFixups(
12361229
12371230 const eq_token = tree.firstToken(var_decl.ast.init_node) - 1;
12381231 const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline;
1239 {
1240 ais.pushIndent();
1241 try renderToken(r, eq_token, eq_space); // =
1242 ais.popIndent();
1243 }
1244 ais.pushIndentOneShot();
1245 return renderExpression(r, var_decl.ast.init_node, space); // ;
1232 try ais.pushIndent(.normal);
1233 try renderToken(r, eq_token, eq_space); // =
1234 try renderExpression(r, var_decl.ast.init_node, space); // ;
1235 ais.popIndent();
12461236}
12471237
12481238fn renderIf(r: *Render, if_node: Ast.full.If, space: Space) Error!void {
......@@ -1342,23 +1332,28 @@ fn renderThenElse(
13421332 const then_expr_is_block = nodeIsBlock(node_tags[then_expr]);
13431333 const indent_then_expr = !then_expr_is_block and
13441334 !tree.tokensOnSameLine(last_prefix_token, tree.firstToken(then_expr));
1345 if (indent_then_expr or (then_expr_is_block and ais.isLineOverIndented())) {
1346 ais.pushIndentNextLine();
1335
1336 if (indent_then_expr) try ais.pushIndent(.normal);
1337
1338 if (then_expr_is_block and ais.isLineOverIndented()) {
1339 ais.disableIndentCommitting();
1340 try renderToken(r, last_prefix_token, .newline);
1341 ais.enableIndentCommitting();
1342 } else if (indent_then_expr) {
13471343 try renderToken(r, last_prefix_token, .newline);
1348 ais.popIndent();
13491344 } else {
13501345 try renderToken(r, last_prefix_token, .space);
13511346 }
13521347
13531348 if (else_expr != 0) {
13541349 if (indent_then_expr) {
1355 ais.pushIndent();
13561350 try renderExpression(r, then_expr, .newline);
1357 ais.popIndent();
13581351 } else {
13591352 try renderExpression(r, then_expr, .space);
13601353 }
13611354
1355 if (indent_then_expr) ais.popIndent();
1356
13621357 var last_else_token = else_token;
13631358
13641359 if (maybe_error_token) |error_token| {
......@@ -1372,20 +1367,17 @@ fn renderThenElse(
13721367 !nodeIsBlock(node_tags[else_expr]) and
13731368 !nodeIsIfForWhileSwitch(node_tags[else_expr]);
13741369 if (indent_else_expr) {
1375 ais.pushIndentNextLine();
1370 try ais.pushIndent(.normal);
13761371 try renderToken(r, last_else_token, .newline);
1372 try renderExpression(r, else_expr, space);
13771373 ais.popIndent();
1378 try renderExpressionIndented(r, else_expr, space);
13791374 } else {
13801375 try renderToken(r, last_else_token, .space);
13811376 try renderExpression(r, else_expr, space);
13821377 }
13831378 } else {
1384 if (indent_then_expr) {
1385 try renderExpressionIndented(r, then_expr, space);
1386 } else {
1387 try renderExpression(r, then_expr, space);
1388 }
1379 try renderExpression(r, then_expr, space);
1380 if (indent_then_expr) ais.popIndent();
13891381 }
13901382}
13911383
......@@ -1411,7 +1403,7 @@ fn renderFor(r: *Render, for_node: Ast.full.For, space: Space) Error!void {
14111403 var cur = for_node.payload_token;
14121404 const pipe = std.mem.indexOfScalarPos(std.zig.Token.Tag, token_tags, cur, .pipe).?;
14131405 if (token_tags[pipe - 1] == .comma) {
1414 ais.pushIndentNextLine();
1406 try ais.pushIndent(.normal);
14151407 try renderToken(r, cur - 1, .newline); // |
14161408 while (true) {
14171409 if (token_tags[cur] == .asterisk) {
......@@ -1540,7 +1532,7 @@ fn renderContainerField(
15401532 const eq_token = tree.firstToken(field.ast.value_expr) - 1;
15411533 const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline;
15421534 {
1543 ais.pushIndent();
1535 try ais.pushIndent(.normal);
15441536 try renderToken(r, eq_token, eq_space); // =
15451537 ais.popIndent();
15461538 }
......@@ -1552,12 +1544,12 @@ fn renderContainerField(
15521544 const maybe_comma = tree.lastToken(field.ast.value_expr) + 1;
15531545
15541546 if (token_tags[maybe_comma] == .comma) {
1555 ais.pushIndent();
1547 try ais.pushIndent(.normal);
15561548 try renderExpression(r, field.ast.value_expr, .none); // value
15571549 ais.popIndent();
15581550 try renderToken(r, maybe_comma, .newline);
15591551 } else {
1560 ais.pushIndent();
1552 try ais.pushIndent(.normal);
15611553 try renderExpression(r, field.ast.value_expr, space); // value
15621554 ais.popIndent();
15631555 }
......@@ -1614,9 +1606,12 @@ fn renderBuiltinCall(
16141606 if (token_tags[first_param_token] == .multiline_string_literal_line or
16151607 hasSameLineComment(tree, first_param_token - 1))
16161608 {
1617 ais.pushIndentOneShot();
1609 try ais.pushIndent(.normal);
1610 try renderExpression(r, param_node, .none);
1611 ais.popIndent();
1612 } else {
1613 try renderExpression(r, param_node, .none);
16181614 }
1619 try renderExpression(r, param_node, .none);
16201615
16211616 if (i + 1 < params.len) {
16221617 const comma_token = tree.lastToken(param_node) + 1;
......@@ -1626,7 +1621,7 @@ fn renderBuiltinCall(
16261621 return renderToken(r, after_last_param_token, space); // )
16271622 } else {
16281623 // Render one param per line.
1629 ais.pushIndent();
1624 try ais.pushIndent(.normal);
16301625 try renderToken(r, builtin_token + 1, Space.newline); // (
16311626
16321627 for (params) |param_node| {
......@@ -1752,7 +1747,7 @@ fn renderFnProto(r: *Render, fn_proto: Ast.full.FnProto, space: Space) Error!voi
17521747 }
17531748 } else {
17541749 // One param per line.
1755 ais.pushIndent();
1750 try ais.pushIndent(.normal);
17561751 try renderToken(r, lparen, .newline); // (
17571752
17581753 var param_i: usize = 0;
......@@ -1933,7 +1928,7 @@ fn renderBlock(
19331928 try renderIdentifier(r, lbrace - 2, .none, .eagerly_unquote); // identifier
19341929 try renderToken(r, lbrace - 1, .space); // :
19351930 }
1936 ais.pushIndentNextLine();
1931 try ais.pushIndent(.normal);
19371932 if (statements.len == 0) {
19381933 try renderToken(r, lbrace, .none);
19391934 ais.popIndent();
......@@ -1986,7 +1981,7 @@ fn renderStructInit(
19861981 try renderExpression(r, struct_init.ast.type_expr, .none); // T
19871982 }
19881983 if (struct_init.ast.fields.len == 0) {
1989 ais.pushIndentNextLine();
1984 try ais.pushIndent(.normal);
19901985 try renderToken(r, struct_init.ast.lbrace, .none); // lbrace
19911986 ais.popIndent();
19921987 return renderToken(r, struct_init.ast.lbrace + 1, space); // rbrace
......@@ -1996,7 +1991,7 @@ fn renderStructInit(
19961991 const trailing_comma = token_tags[rbrace - 1] == .comma;
19971992 if (trailing_comma or hasComment(tree, struct_init.ast.lbrace, rbrace)) {
19981993 // Render one field init per line.
1999 ais.pushIndentNextLine();
1994 try ais.pushIndent(.normal);
20001995 try renderToken(r, struct_init.ast.lbrace, .newline);
20011996
20021997 try renderToken(r, struct_init.ast.lbrace + 1, .none); // .
......@@ -2054,7 +2049,7 @@ fn renderArrayInit(
20542049 }
20552050
20562051 if (array_init.ast.elements.len == 0) {
2057 ais.pushIndentNextLine();
2052 try ais.pushIndent(.normal);
20582053 try renderToken(r, array_init.ast.lbrace, .none); // lbrace
20592054 ais.popIndent();
20602055 return renderToken(r, array_init.ast.lbrace + 1, space); // rbrace
......@@ -2096,7 +2091,7 @@ fn renderArrayInit(
20962091 return renderToken(r, last_elem_token + 1, space); // rbrace
20972092 }
20982093
2099 ais.pushIndentNextLine();
2094 try ais.pushIndent(.normal);
21002095 try renderToken(r, array_init.ast.lbrace, .newline);
21012096
21022097 var expr_index: usize = 0;
......@@ -2149,7 +2144,8 @@ fn renderArrayInit(
21492144 const sub_expr_buffer_starts = try gpa.alloc(usize, section_exprs.len + 1);
21502145 defer gpa.free(sub_expr_buffer_starts);
21512146
2152 var auto_indenting_stream = Ais.init(sub_expr_buffer, indent_delta);
2147 var auto_indenting_stream = Ais.init(&sub_expr_buffer, indent_delta);
2148 defer auto_indenting_stream.deinit();
21532149 var sub_render: Render = .{
21542150 .gpa = r.gpa,
21552151 .ais = &auto_indenting_stream,
......@@ -2312,7 +2308,7 @@ fn renderContainerDecl(
23122308
23132309 const rbrace = tree.lastToken(container_decl_node);
23142310 if (container_decl.ast.members.len == 0) {
2315 ais.pushIndentNextLine();
2311 try ais.pushIndent(.normal);
23162312 if (token_tags[lbrace + 1] == .container_doc_comment) {
23172313 try renderToken(r, lbrace, .newline); // lbrace
23182314 try renderContainerDocComments(r, lbrace + 1);
......@@ -2354,7 +2350,7 @@ fn renderContainerDecl(
23542350 }
23552351
23562352 // One member per line.
2357 ais.pushIndentNextLine();
2353 try ais.pushIndent(.normal);
23582354 try renderToken(r, lbrace, .newline); // lbrace
23592355 if (token_tags[lbrace + 1] == .container_doc_comment) {
23602356 try renderContainerDocComments(r, lbrace + 1);
......@@ -2395,7 +2391,7 @@ fn renderAsm(
23952391 }
23962392
23972393 if (asm_node.ast.items.len == 0) {
2398 ais.pushIndent();
2394 try ais.pushIndent(.normal);
23992395 if (asm_node.first_clobber) |first_clobber| {
24002396 // asm ("foo" ::: "a", "b")
24012397 // asm ("foo" ::: "a", "b",)
......@@ -2433,7 +2429,7 @@ fn renderAsm(
24332429 }
24342430 }
24352431
2436 ais.pushIndent();
2432 try ais.pushIndent(.normal);
24372433 try renderExpression(r, asm_node.ast.template, .newline);
24382434 ais.setIndentDelta(asm_indent_delta);
24392435 const colon1 = tree.lastToken(asm_node.ast.template) + 1;
......@@ -2444,7 +2440,7 @@ fn renderAsm(
24442440 } else colon2: {
24452441 try renderToken(r, colon1, .space); // :
24462442
2447 ais.pushIndent();
2443 try ais.pushIndent(.normal);
24482444 for (asm_node.outputs, 0..) |asm_output, i| {
24492445 if (i + 1 < asm_node.outputs.len) {
24502446 const next_asm_output = asm_node.outputs[i + 1];
......@@ -2476,7 +2472,7 @@ fn renderAsm(
24762472 break :colon3 colon2 + 1;
24772473 } else colon3: {
24782474 try renderToken(r, colon2, .space); // :
2479 ais.pushIndent();
2475 try ais.pushIndent(.normal);
24802476 for (asm_node.inputs, 0..) |asm_input, i| {
24812477 if (i + 1 < asm_node.inputs.len) {
24822478 const next_asm_input = asm_node.inputs[i + 1];
......@@ -2558,7 +2554,7 @@ fn renderParamList(
25582554 const token_tags = tree.tokens.items(.tag);
25592555
25602556 if (params.len == 0) {
2561 ais.pushIndentNextLine();
2557 try ais.pushIndent(.normal);
25622558 try renderToken(r, lparen, .none);
25632559 ais.popIndent();
25642560 return renderToken(r, lparen + 1, space); // )
......@@ -2567,22 +2563,15 @@ fn renderParamList(
25672563 const last_param = params[params.len - 1];
25682564 const after_last_param_tok = tree.lastToken(last_param) + 1;
25692565 if (token_tags[after_last_param_tok] == .comma) {
2570 ais.pushIndentNextLine();
2566 try ais.pushIndent(.normal);
25712567 try renderToken(r, lparen, .newline); // (
25722568 for (params, 0..) |param_node, i| {
25732569 if (i + 1 < params.len) {
25742570 try renderExpression(r, param_node, .none);
25752571
2576 // Unindent the comma for multiline string literals.
2577 const is_multiline_string =
2578 token_tags[tree.firstToken(param_node)] == .multiline_string_literal_line;
2579 if (is_multiline_string) ais.popIndent();
2580
25812572 const comma = tree.lastToken(param_node) + 1;
25822573 try renderToken(r, comma, .newline); // ,
25832574
2584 if (is_multiline_string) ais.pushIndent();
2585
25862575 try renderExtraNewline(r, params[i + 1]);
25872576 } else {
25882577 try renderExpression(r, param_node, .comma);
......@@ -2599,9 +2588,12 @@ fn renderParamList(
25992588 if (token_tags[first_param_token] == .multiline_string_literal_line or
26002589 hasSameLineComment(tree, first_param_token - 1))
26012590 {
2602 ais.pushIndentOneShot();
2591 try ais.pushIndent(.normal);
2592 try renderExpression(r, param_node, .none);
2593 ais.popIndent();
2594 } else {
2595 try renderExpression(r, param_node, .none);
26032596 }
2604 try renderExpression(r, param_node, .none);
26052597
26062598 if (i + 1 < params.len) {
26072599 const comma = tree.lastToken(param_node) + 1;
......@@ -2615,66 +2607,6 @@ fn renderParamList(
26152607 return renderToken(r, after_last_param_tok, space); // )
26162608}
26172609
2618/// Renders the given expression indented, popping the indent before rendering
2619/// any following line comments
2620fn renderExpressionIndented(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
2621 const tree = r.tree;
2622 const ais = r.ais;
2623 const token_starts = tree.tokens.items(.start);
2624 const token_tags = tree.tokens.items(.tag);
2625
2626 ais.pushIndent();
2627
2628 var last_token = tree.lastToken(node);
2629 const punctuation = switch (space) {
2630 .none, .space, .newline, .skip => false,
2631 .comma => true,
2632 .comma_space => token_tags[last_token + 1] == .comma,
2633 .semicolon => token_tags[last_token + 1] == .semicolon,
2634 };
2635
2636 try renderExpression(r, node, if (punctuation) .none else .skip);
2637
2638 switch (space) {
2639 .none, .space, .newline, .skip => {},
2640 .comma => {
2641 if (token_tags[last_token + 1] == .comma) {
2642 try renderToken(r, last_token + 1, .skip);
2643 last_token += 1;
2644 } else {
2645 try ais.writer().writeByte(',');
2646 }
2647 },
2648 .comma_space => if (token_tags[last_token + 1] == .comma) {
2649 try renderToken(r, last_token + 1, .skip);
2650 last_token += 1;
2651 },
2652 .semicolon => if (token_tags[last_token + 1] == .semicolon) {
2653 try renderToken(r, last_token + 1, .skip);
2654 last_token += 1;
2655 },
2656 }
2657
2658 ais.popIndent();
2659
2660 if (space == .skip) return;
2661
2662 const comment_start = token_starts[last_token] + tokenSliceForRender(tree, last_token).len;
2663 const comment = try renderComments(r, comment_start, token_starts[last_token + 1]);
2664
2665 if (!comment) switch (space) {
2666 .none => {},
2667 .space,
2668 .comma_space,
2669 => try ais.writer().writeByte(' '),
2670 .newline,
2671 .comma,
2672 .semicolon,
2673 => try ais.insertNewline(),
2674 .skip => unreachable,
2675 };
2676}
2677
26782610/// Render an expression, and the comma that follows it, if it is present in the source.
26792611/// If a comma is present, and `space` is `Space.comma`, render only a single comma.
26802612fn renderExpressionComma(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
......@@ -3315,6 +3247,14 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
33153247 pub const WriteError = UnderlyingWriter.Error;
33163248 pub const Writer = std.io.Writer(*Self, WriteError, write);
33173249
3250 pub const IndentType = enum {
3251 normal,
3252 };
3253 const StackElem = struct {
3254 indent_type: IndentType,
3255 realized: bool,
3256 };
3257
33183258 underlying_writer: UnderlyingWriter,
33193259
33203260 /// Offset into the source at which formatting has been disabled with
......@@ -3327,21 +3267,24 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
33273267
33283268 indent_count: usize = 0,
33293269 indent_delta: usize,
3270 indent_stack: std.ArrayList(StackElem),
3271 disable_indent_committing: usize = 0,
33303272 current_line_empty: bool = true,
3331 /// automatically popped when applied
3332 indent_one_shot_count: usize = 0,
33333273 /// the most recently applied indent
33343274 applied_indent: usize = 0,
3335 /// not used until the next line
3336 indent_next_line: usize = 0,
33373275
3338 pub fn init(buffer: *std.ArrayList(u8), indent_delta: usize) Self {
3276 pub fn init(buffer: *std.ArrayList(u8), indent_delta_: usize) Self {
33393277 return .{
33403278 .underlying_writer = buffer.writer(),
3341 .indent_delta = indent_delta,
3279 .indent_delta = indent_delta_,
3280 .indent_stack = std.ArrayList(StackElem).init(buffer.allocator),
33423281 };
33433282 }
33443283
3284 pub fn deinit(self: *Self) void {
3285 self.indent_stack.deinit();
3286 }
3287
33453288 pub fn writer(self: *Self) Writer {
33463289 return .{ .context = self };
33473290 }
......@@ -3385,7 +3328,23 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
33853328
33863329 fn resetLine(self: *Self) void {
33873330 self.current_line_empty = true;
3388 self.indent_next_line = 0;
3331 if (self.disable_indent_committing > 0) return;
3332 if (self.indent_stack.items.len > 0) {
3333 // Only realize last pushed indent
3334 if (!self.indent_stack.items[self.indent_stack.items.len - 1].realized) {
3335 self.indent_stack.items[self.indent_stack.items.len - 1].realized = true;
3336 self.indent_count += 1;
3337 }
3338 }
3339 }
3340
3341 pub fn disableIndentCommitting(self: *Self) void {
3342 self.disable_indent_committing += 1;
3343 }
3344
3345 pub fn enableIndentCommitting(self: *Self) void {
3346 assert(self.disable_indent_committing > 0);
3347 self.disable_indent_committing -= 1;
33893348 }
33903349
33913350 /// Insert a newline unless the current line is blank
......@@ -3397,36 +3356,19 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
33973356 /// Push default indentation
33983357 /// Doesn't actually write any indentation.
33993358 /// Just primes the stream to be able to write the correct indentation if it needs to.
3400 pub fn pushIndent(self: *Self) void {
3401 self.indent_count += 1;
3402 }
3403
3404 /// Push an indent that is automatically popped after being applied
3405 pub fn pushIndentOneShot(self: *Self) void {
3406 self.indent_one_shot_count += 1;
3407 self.pushIndent();
3408 }
3409
3410 /// Turns all one-shot indents into regular indents
3411 /// Returns number of indents that must now be manually popped
3412 pub fn lockOneShotIndent(self: *Self) usize {
3413 const locked_count = self.indent_one_shot_count;
3414 self.indent_one_shot_count = 0;
3415 return locked_count;
3416 }
3417
3418 /// Push an indent that should not take effect until the next line
3419 pub fn pushIndentNextLine(self: *Self) void {
3420 self.indent_next_line += 1;
3421 self.pushIndent();
3359 pub fn pushIndent(self: *Self, indent_type: IndentType) !void {
3360 try self.indent_stack.append(.{ .indent_type = indent_type, .realized = false });
34223361 }
34233362
34243363 pub fn popIndent(self: *Self) void {
3425 assert(self.indent_count != 0);
3426 self.indent_count -= 1;
3364 if (self.indent_stack.pop().realized) {
3365 assert(self.indent_count > 0);
3366 self.indent_count -= 1;
3367 }
3368 }
34273369
3428 if (self.indent_next_line > 0)
3429 self.indent_next_line -= 1;
3370 pub fn indentStackEmpty(self: *Self) bool {
3371 return self.indent_stack.items.len == 0;
34303372 }
34313373
34323374 /// Writes ' ' bytes if the current line is empty
......@@ -3438,9 +3380,6 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
34383380 }
34393381 self.applied_indent = current_indent;
34403382 }
3441
3442 self.indent_count -= self.indent_one_shot_count;
3443 self.indent_one_shot_count = 0;
34443383 self.current_line_empty = false;
34453384 }
34463385
......@@ -3451,12 +3390,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
34513390 }
34523391
34533392 fn currentIndent(self: *Self) usize {
3454 var indent_current: usize = 0;
3455 if (self.indent_count > 0) {
3456 const indent_count = self.indent_count - self.indent_next_line;
3457 indent_current = indent_count * self.indent_delta;
3458 }
3459 return indent_current;
3393 return self.indent_count * self.indent_delta;
34603394 }
34613395 };
34623396}