| ... | @@ -82,6 +82,7 @@ const Render = struct { | ... | @@ -82,6 +82,7 @@ const Render = struct { |
| 82 | pub fn renderTree(buffer: *std.ArrayList(u8), tree: Ast, fixups: Fixups) Error!void { | 82 | pub fn renderTree(buffer: *std.ArrayList(u8), tree: Ast, fixups: Fixups) Error!void { |
| 83 | assert(tree.errors.len == 0); // Cannot render an invalid tree. | 83 | assert(tree.errors.len == 0); // Cannot render an invalid tree. |
| 84 | var auto_indenting_stream = Ais.init(buffer, indent_delta); | 84 | var auto_indenting_stream = Ais.init(buffer, indent_delta); |
| | 85 | defer auto_indenting_stream.deinit(); |
| 85 | var r: Render = .{ | 86 | var r: Render = .{ |
| 86 | .gpa = buffer.allocator, | 87 | .gpa = buffer.allocator, |
| 87 | .ais = &auto_indenting_stream, | 88 | .ais = &auto_indenting_stream, |
| ... | @@ -195,7 +196,7 @@ fn renderMember( | ... | @@ -195,7 +196,7 @@ fn renderMember( |
| 195 | try renderExpression(r, fn_proto, .space); | 196 | try renderExpression(r, fn_proto, .space); |
| 196 | const body_node = datas[decl].rhs; | 197 | const body_node = datas[decl].rhs; |
| 197 | if (r.fixups.gut_functions.contains(decl)) { | 198 | if (r.fixups.gut_functions.contains(decl)) { |
| 198 | ais.pushIndent(); | 199 | try ais.pushIndent(.normal); |
| 199 | const lbrace = tree.nodes.items(.main_token)[body_node]; | 200 | const lbrace = tree.nodes.items(.main_token)[body_node]; |
| 200 | try renderToken(r, lbrace, .newline); | 201 | try renderToken(r, lbrace, .newline); |
| 201 | try discardAllParams(r, fn_proto); | 202 | try discardAllParams(r, fn_proto); |
| ... | @@ -204,7 +205,7 @@ fn renderMember( | ... | @@ -204,7 +205,7 @@ fn renderMember( |
| 204 | try ais.insertNewline(); | 205 | try ais.insertNewline(); |
| 205 | try renderToken(r, tree.lastToken(body_node), space); // rbrace | 206 | try renderToken(r, tree.lastToken(body_node), space); // rbrace |
| 206 | } else if (r.fixups.unused_var_decls.count() != 0) { | 207 | } else if (r.fixups.unused_var_decls.count() != 0) { |
| 207 | ais.pushIndentNextLine(); | 208 | try ais.pushIndent(.normal); |
| 208 | const lbrace = tree.nodes.items(.main_token)[body_node]; | 209 | const lbrace = tree.nodes.items(.main_token)[body_node]; |
| 209 | try renderToken(r, lbrace, .newline); | 210 | try renderToken(r, lbrace, .newline); |
| 210 | | 211 | |
| ... | @@ -358,13 +359,16 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { | ... | @@ -358,13 +359,16 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 358 | => return renderToken(r, main_tokens[node], space), | 359 | => return renderToken(r, main_tokens[node], space), |
| 359 | | 360 | |
| 360 | .multiline_string_literal => { | 361 | .multiline_string_literal => { |
| 361 | var locked_indents = ais.lockOneShotIndent(); | | |
| 362 | try ais.maybeInsertNewline(); | 362 | try ais.maybeInsertNewline(); |
| 363 | | 363 | |
| 364 | var i = datas[node].lhs; | 364 | var i = datas[node].lhs; |
| 365 | while (i <= datas[node].rhs) : (i += 1) try renderToken(r, i, .newline); | 365 | while (i <= datas[node].rhs) : (i += 1) try renderToken(r, i, .newline); |
| 366 | | 366 | |
| 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 | } |
| 368 | | 372 | |
| 369 | switch (space) { | 373 | switch (space) { |
| 370 | .none, .space, .newline, .skip => {}, | 374 | .none, .space, .newline, .skip => {}, |
| ... | @@ -442,6 +446,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { | ... | @@ -442,6 +446,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 442 | | 446 | |
| 443 | try renderExpression(r, datas[node].lhs, .space); // target | 447 | try renderExpression(r, datas[node].lhs, .space); // target |
| 444 | | 448 | |
| | 449 | try ais.pushIndent(.normal); |
| 445 | if (token_tags[fallback_first - 1] == .pipe) { | 450 | if (token_tags[fallback_first - 1] == .pipe) { |
| 446 | try renderToken(r, main_token, .space); // catch keyword | 451 | try renderToken(r, main_token, .space); // catch keyword |
| 447 | try renderToken(r, main_token + 1, .none); // pipe | 452 | try renderToken(r, main_token + 1, .none); // pipe |
| ... | @@ -451,38 +456,27 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { | ... | @@ -451,38 +456,27 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 451 | assert(token_tags[fallback_first - 1] == .keyword_catch); | 456 | assert(token_tags[fallback_first - 1] == .keyword_catch); |
| 452 | try renderToken(r, main_token, after_op_space); // catch keyword | 457 | try renderToken(r, main_token, after_op_space); // catch keyword |
| 453 | } | 458 | } |
| 454 | | | |
| 455 | ais.pushIndentOneShot(); | | |
| 456 | try renderExpression(r, datas[node].rhs, space); // fallback | 459 | try renderExpression(r, datas[node].rhs, space); // fallback |
| | 460 | ais.popIndent(); |
| 457 | }, | 461 | }, |
| 458 | | 462 | |
| 459 | .field_access => { | 463 | .field_access => { |
| 460 | const main_token = main_tokens[node]; | 464 | const main_token = main_tokens[node]; |
| 461 | const field_access = datas[node]; | 465 | const field_access = datas[node]; |
| 462 | | 466 | |
| | 467 | try ais.pushIndent(.normal); |
| 463 | try renderExpression(r, field_access.lhs, .none); | 468 | try renderExpression(r, field_access.lhs, .none); |
| 464 | | 469 | |
| 465 | // Allow a line break between the lhs and the dot if the lhs and rhs | 470 | // Allow a line break between the lhs and the dot if the lhs and rhs |
| 466 | // are on different lines. | 471 | // are on different lines. |
| 467 | const lhs_last_token = tree.lastToken(field_access.lhs); | 472 | const lhs_last_token = tree.lastToken(field_access.lhs); |
| 468 | const same_line = tree.tokensOnSameLine(lhs_last_token, main_token + 1); | 473 | const same_line = tree.tokensOnSameLine(lhs_last_token, main_token + 1); |
| 469 | if (!same_line) { | 474 | if (!same_line and !hasComment(tree, lhs_last_token, main_token)) try ais.insertNewline(); |
| 470 | if (!hasComment(tree, lhs_last_token, main_token)) try ais.insertNewline(); | | |
| 471 | ais.pushIndentOneShot(); | | |
| 472 | } | | |
| 473 | | 475 | |
| 474 | try renderToken(r, main_token, .none); // . | 476 | try renderToken(r, main_token, .none); // . |
| 475 | | 477 | |
| 476 | // This check ensures that zag() is indented in the following example: | 478 | try renderIdentifier(r, field_access.rhs, space, .eagerly_unquote); // field |
| 477 | // const x = foo | 479 | ais.popIndent(); |
| 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 | | |
| 486 | }, | 480 | }, |
| 487 | | 481 | |
| 488 | .error_union, | 482 | .error_union, |
| ... | @@ -555,15 +549,14 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { | ... | @@ -555,15 +549,14 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 555 | const infix = datas[node]; | 549 | const infix = datas[node]; |
| 556 | try renderExpression(r, infix.lhs, .space); | 550 | try renderExpression(r, infix.lhs, .space); |
| 557 | const op_token = main_tokens[node]; | 551 | const op_token = main_tokens[node]; |
| | 552 | try ais.pushIndent(.normal); |
| 558 | if (tree.tokensOnSameLine(op_token, op_token + 1)) { | 553 | if (tree.tokensOnSameLine(op_token, op_token + 1)) { |
| 559 | try renderToken(r, op_token, .space); | 554 | try renderToken(r, op_token, .space); |
| 560 | } else { | 555 | } else { |
| 561 | ais.pushIndent(); | | |
| 562 | try renderToken(r, op_token, .newline); | 556 | try renderToken(r, op_token, .newline); |
| 563 | ais.popIndent(); | | |
| 564 | } | 557 | } |
| 565 | ais.pushIndentOneShot(); | 558 | try renderExpression(r, infix.rhs, space); |
| 566 | return renderExpression(r, infix.rhs, space); | 559 | ais.popIndent(); |
| 567 | }, | 560 | }, |
| 568 | | 561 | |
| 569 | .assign_destructure => { | 562 | .assign_destructure => { |
| ... | @@ -585,15 +578,14 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { | ... | @@ -585,15 +578,14 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 585 | else => try renderExpression(r, variable_node, variable_space), | 578 | else => try renderExpression(r, variable_node, variable_space), |
| 586 | } | 579 | } |
| 587 | } | 580 | } |
| | 581 | try ais.pushIndent(.normal); |
| 588 | if (tree.tokensOnSameLine(full.ast.equal_token, full.ast.equal_token + 1)) { | 582 | if (tree.tokensOnSameLine(full.ast.equal_token, full.ast.equal_token + 1)) { |
| 589 | try renderToken(r, full.ast.equal_token, .space); | 583 | try renderToken(r, full.ast.equal_token, .space); |
| 590 | } else { | 584 | } else { |
| 591 | ais.pushIndent(); | | |
| 592 | try renderToken(r, full.ast.equal_token, .newline); | 585 | try renderToken(r, full.ast.equal_token, .newline); |
| 593 | ais.popIndent(); | | |
| 594 | } | 586 | } |
| 595 | ais.pushIndentOneShot(); | 587 | try renderExpression(r, full.ast.value_expr, space); |
| 596 | return renderExpression(r, full.ast.value_expr, space); | 588 | ais.popIndent(); |
| 597 | }, | 589 | }, |
| 598 | | 590 | |
| 599 | .bit_not, | 591 | .bit_not, |
| ... | @@ -671,7 +663,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { | ... | @@ -671,7 +663,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 671 | const one_line = tree.tokensOnSameLine(lbracket, rbracket); | 663 | const one_line = tree.tokensOnSameLine(lbracket, rbracket); |
| 672 | const inner_space = if (one_line) Space.none else Space.newline; | 664 | const inner_space = if (one_line) Space.none else Space.newline; |
| 673 | try renderExpression(r, suffix.lhs, .none); | 665 | try renderExpression(r, suffix.lhs, .none); |
| 674 | ais.pushIndentNextLine(); | 666 | try ais.pushIndent(.normal); |
| 675 | try renderToken(r, lbracket, inner_space); // [ | 667 | try renderToken(r, lbracket, inner_space); // [ |
| 676 | try renderExpression(r, suffix.rhs, inner_space); | 668 | try renderExpression(r, suffix.rhs, inner_space); |
| 677 | ais.popIndent(); | 669 | ais.popIndent(); |
| ... | @@ -723,8 +715,9 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { | ... | @@ -723,8 +715,9 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 723 | | 715 | |
| 724 | .grouped_expression => { | 716 | .grouped_expression => { |
| 725 | try renderToken(r, main_tokens[node], .none); // lparen | 717 | try renderToken(r, main_tokens[node], .none); // lparen |
| 726 | ais.pushIndentOneShot(); | 718 | try ais.pushIndent(.normal); |
| 727 | try renderExpression(r, datas[node].lhs, .none); | 719 | try renderExpression(r, datas[node].lhs, .none); |
| | 720 | ais.popIndent(); |
| 728 | return renderToken(r, datas[node].rhs, space); // rparen | 721 | return renderToken(r, datas[node].rhs, space); // rparen |
| 729 | }, | 722 | }, |
| 730 | | 723 | |
| ... | @@ -764,7 +757,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { | ... | @@ -764,7 +757,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 764 | return renderToken(r, rbrace, space); | 757 | return renderToken(r, rbrace, space); |
| 765 | } else if (token_tags[rbrace - 1] == .comma) { | 758 | } else if (token_tags[rbrace - 1] == .comma) { |
| 766 | // There is a trailing comma so render each member on a new line. | 759 | // There is a trailing comma so render each member on a new line. |
| 767 | ais.pushIndentNextLine(); | 760 | try ais.pushIndent(.normal); |
| 768 | try renderToken(r, lbrace, .newline); | 761 | try renderToken(r, lbrace, .newline); |
| 769 | var i = lbrace + 1; | 762 | var i = lbrace + 1; |
| 770 | while (i < rbrace) : (i += 1) { | 763 | while (i < rbrace) : (i += 1) { |
| ... | @@ -845,7 +838,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { | ... | @@ -845,7 +838,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 845 | try renderExpression(r, full.ast.condition, .none); // condition expression | 838 | try renderExpression(r, full.ast.condition, .none); // condition expression |
| 846 | try renderToken(r, rparen, .space); // ) | 839 | try renderToken(r, rparen, .space); // ) |
| 847 | | 840 | |
| 848 | ais.pushIndentNextLine(); | 841 | try ais.pushIndent(.normal); |
| 849 | if (full.ast.cases.len == 0) { | 842 | if (full.ast.cases.len == 0) { |
| 850 | try renderToken(r, rparen + 1, .none); // { | 843 | try renderToken(r, rparen + 1, .none); // { |
| 851 | } else { | 844 | } else { |
| ... | @@ -920,7 +913,7 @@ fn renderArrayType( | ... | @@ -920,7 +913,7 @@ fn renderArrayType( |
| 920 | const rbracket = tree.firstToken(array_type.ast.elem_type) - 1; | 913 | const rbracket = tree.firstToken(array_type.ast.elem_type) - 1; |
| 921 | const one_line = tree.tokensOnSameLine(array_type.ast.lbracket, rbracket); | 914 | const one_line = tree.tokensOnSameLine(array_type.ast.lbracket, rbracket); |
| 922 | const inner_space = if (one_line) Space.none else Space.newline; | 915 | const inner_space = if (one_line) Space.none else Space.newline; |
| 923 | ais.pushIndentNextLine(); | 916 | try ais.pushIndent(.normal); |
| 924 | try renderToken(r, array_type.ast.lbracket, inner_space); // lbracket | 917 | try renderToken(r, array_type.ast.lbracket, inner_space); // lbracket |
| 925 | try renderExpression(r, array_type.ast.elem_count, inner_space); | 918 | try renderExpression(r, array_type.ast.elem_count, inner_space); |
| 926 | if (array_type.ast.sentinel != 0) { | 919 | if (array_type.ast.sentinel != 0) { |
| ... | @@ -1236,13 +1229,10 @@ fn renderVarDeclWithoutFixups( | ... | @@ -1236,13 +1229,10 @@ fn renderVarDeclWithoutFixups( |
| 1236 | | 1229 | |
| 1237 | const eq_token = tree.firstToken(var_decl.ast.init_node) - 1; | 1230 | const eq_token = tree.firstToken(var_decl.ast.init_node) - 1; |
| 1238 | const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline; | 1231 | const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline; |
| 1239 | { | 1232 | try ais.pushIndent(.normal); |
| 1240 | ais.pushIndent(); | 1233 | try renderToken(r, eq_token, eq_space); // = |
| 1241 | try renderToken(r, eq_token, eq_space); // = | 1234 | try renderExpression(r, var_decl.ast.init_node, space); // ; |
| 1242 | ais.popIndent(); | 1235 | ais.popIndent(); |
| 1243 | } | | |
| 1244 | ais.pushIndentOneShot(); | | |
| 1245 | return renderExpression(r, var_decl.ast.init_node, space); // ; | | |
| 1246 | } | 1236 | } |
| 1247 | | 1237 | |
| 1248 | fn renderIf(r: *Render, if_node: Ast.full.If, space: Space) Error!void { | 1238 | fn renderIf(r: *Render, if_node: Ast.full.If, space: Space) Error!void { |
| ... | @@ -1342,23 +1332,28 @@ fn renderThenElse( | ... | @@ -1342,23 +1332,28 @@ fn renderThenElse( |
| 1342 | const then_expr_is_block = nodeIsBlock(node_tags[then_expr]); | 1332 | const then_expr_is_block = nodeIsBlock(node_tags[then_expr]); |
| 1343 | const indent_then_expr = !then_expr_is_block and | 1333 | const indent_then_expr = !then_expr_is_block and |
| 1344 | !tree.tokensOnSameLine(last_prefix_token, tree.firstToken(then_expr)); | 1334 | !tree.tokensOnSameLine(last_prefix_token, tree.firstToken(then_expr)); |
| 1345 | if (indent_then_expr or (then_expr_is_block and ais.isLineOverIndented())) { | 1335 | |
| 1346 | ais.pushIndentNextLine(); | 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) { |
| 1347 | try renderToken(r, last_prefix_token, .newline); | 1343 | try renderToken(r, last_prefix_token, .newline); |
| 1348 | ais.popIndent(); | | |
| 1349 | } else { | 1344 | } else { |
| 1350 | try renderToken(r, last_prefix_token, .space); | 1345 | try renderToken(r, last_prefix_token, .space); |
| 1351 | } | 1346 | } |
| 1352 | | 1347 | |
| 1353 | if (else_expr != 0) { | 1348 | if (else_expr != 0) { |
| 1354 | if (indent_then_expr) { | 1349 | if (indent_then_expr) { |
| 1355 | ais.pushIndent(); | | |
| 1356 | try renderExpression(r, then_expr, .newline); | 1350 | try renderExpression(r, then_expr, .newline); |
| 1357 | ais.popIndent(); | | |
| 1358 | } else { | 1351 | } else { |
| 1359 | try renderExpression(r, then_expr, .space); | 1352 | try renderExpression(r, then_expr, .space); |
| 1360 | } | 1353 | } |
| 1361 | | 1354 | |
| | 1355 | if (indent_then_expr) ais.popIndent(); |
| | 1356 | |
| 1362 | var last_else_token = else_token; | 1357 | var last_else_token = else_token; |
| 1363 | | 1358 | |
| 1364 | if (maybe_error_token) |error_token| { | 1359 | if (maybe_error_token) |error_token| { |
| ... | @@ -1372,20 +1367,17 @@ fn renderThenElse( | ... | @@ -1372,20 +1367,17 @@ fn renderThenElse( |
| 1372 | !nodeIsBlock(node_tags[else_expr]) and | 1367 | !nodeIsBlock(node_tags[else_expr]) and |
| 1373 | !nodeIsIfForWhileSwitch(node_tags[else_expr]); | 1368 | !nodeIsIfForWhileSwitch(node_tags[else_expr]); |
| 1374 | if (indent_else_expr) { | 1369 | if (indent_else_expr) { |
| 1375 | ais.pushIndentNextLine(); | 1370 | try ais.pushIndent(.normal); |
| 1376 | try renderToken(r, last_else_token, .newline); | 1371 | try renderToken(r, last_else_token, .newline); |
| | 1372 | try renderExpression(r, else_expr, space); |
| 1377 | ais.popIndent(); | 1373 | ais.popIndent(); |
| 1378 | try renderExpressionIndented(r, else_expr, space); | | |
| 1379 | } else { | 1374 | } else { |
| 1380 | try renderToken(r, last_else_token, .space); | 1375 | try renderToken(r, last_else_token, .space); |
| 1381 | try renderExpression(r, else_expr, space); | 1376 | try renderExpression(r, else_expr, space); |
| 1382 | } | 1377 | } |
| 1383 | } else { | 1378 | } else { |
| 1384 | if (indent_then_expr) { | 1379 | try renderExpression(r, then_expr, space); |
| 1385 | try renderExpressionIndented(r, then_expr, space); | 1380 | if (indent_then_expr) ais.popIndent(); |
| 1386 | } else { | | |
| 1387 | try renderExpression(r, then_expr, space); | | |
| 1388 | } | | |
| 1389 | } | 1381 | } |
| 1390 | } | 1382 | } |
| 1391 | | 1383 | |
| ... | @@ -1411,7 +1403,7 @@ fn renderFor(r: *Render, for_node: Ast.full.For, space: Space) Error!void { | ... | @@ -1411,7 +1403,7 @@ fn renderFor(r: *Render, for_node: Ast.full.For, space: Space) Error!void { |
| 1411 | var cur = for_node.payload_token; | 1403 | var cur = for_node.payload_token; |
| 1412 | const pipe = std.mem.indexOfScalarPos(std.zig.Token.Tag, token_tags, cur, .pipe).?; | 1404 | const pipe = std.mem.indexOfScalarPos(std.zig.Token.Tag, token_tags, cur, .pipe).?; |
| 1413 | if (token_tags[pipe - 1] == .comma) { | 1405 | if (token_tags[pipe - 1] == .comma) { |
| 1414 | ais.pushIndentNextLine(); | 1406 | try ais.pushIndent(.normal); |
| 1415 | try renderToken(r, cur - 1, .newline); // | | 1407 | try renderToken(r, cur - 1, .newline); // | |
| 1416 | while (true) { | 1408 | while (true) { |
| 1417 | if (token_tags[cur] == .asterisk) { | 1409 | if (token_tags[cur] == .asterisk) { |
| ... | @@ -1540,7 +1532,7 @@ fn renderContainerField( | ... | @@ -1540,7 +1532,7 @@ fn renderContainerField( |
| 1540 | const eq_token = tree.firstToken(field.ast.value_expr) - 1; | 1532 | const eq_token = tree.firstToken(field.ast.value_expr) - 1; |
| 1541 | const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline; | 1533 | const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline; |
| 1542 | { | 1534 | { |
| 1543 | ais.pushIndent(); | 1535 | try ais.pushIndent(.normal); |
| 1544 | try renderToken(r, eq_token, eq_space); // = | 1536 | try renderToken(r, eq_token, eq_space); // = |
| 1545 | ais.popIndent(); | 1537 | ais.popIndent(); |
| 1546 | } | 1538 | } |
| ... | @@ -1552,12 +1544,12 @@ fn renderContainerField( | ... | @@ -1552,12 +1544,12 @@ fn renderContainerField( |
| 1552 | const maybe_comma = tree.lastToken(field.ast.value_expr) + 1; | 1544 | const maybe_comma = tree.lastToken(field.ast.value_expr) + 1; |
| 1553 | | 1545 | |
| 1554 | if (token_tags[maybe_comma] == .comma) { | 1546 | if (token_tags[maybe_comma] == .comma) { |
| 1555 | ais.pushIndent(); | 1547 | try ais.pushIndent(.normal); |
| 1556 | try renderExpression(r, field.ast.value_expr, .none); // value | 1548 | try renderExpression(r, field.ast.value_expr, .none); // value |
| 1557 | ais.popIndent(); | 1549 | ais.popIndent(); |
| 1558 | try renderToken(r, maybe_comma, .newline); | 1550 | try renderToken(r, maybe_comma, .newline); |
| 1559 | } else { | 1551 | } else { |
| 1560 | ais.pushIndent(); | 1552 | try ais.pushIndent(.normal); |
| 1561 | try renderExpression(r, field.ast.value_expr, space); // value | 1553 | try renderExpression(r, field.ast.value_expr, space); // value |
| 1562 | ais.popIndent(); | 1554 | ais.popIndent(); |
| 1563 | } | 1555 | } |
| ... | @@ -1614,9 +1606,12 @@ fn renderBuiltinCall( | ... | @@ -1614,9 +1606,12 @@ fn renderBuiltinCall( |
| 1614 | if (token_tags[first_param_token] == .multiline_string_literal_line or | 1606 | if (token_tags[first_param_token] == .multiline_string_literal_line or |
| 1615 | hasSameLineComment(tree, first_param_token - 1)) | 1607 | hasSameLineComment(tree, first_param_token - 1)) |
| 1616 | { | 1608 | { |
| 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); |
| 1618 | } | 1614 | } |
| 1619 | try renderExpression(r, param_node, .none); | | |
| 1620 | | 1615 | |
| 1621 | if (i + 1 < params.len) { | 1616 | if (i + 1 < params.len) { |
| 1622 | const comma_token = tree.lastToken(param_node) + 1; | 1617 | const comma_token = tree.lastToken(param_node) + 1; |
| ... | @@ -1626,7 +1621,7 @@ fn renderBuiltinCall( | ... | @@ -1626,7 +1621,7 @@ fn renderBuiltinCall( |
| 1626 | return renderToken(r, after_last_param_token, space); // ) | 1621 | return renderToken(r, after_last_param_token, space); // ) |
| 1627 | } else { | 1622 | } else { |
| 1628 | // Render one param per line. | 1623 | // Render one param per line. |
| 1629 | ais.pushIndent(); | 1624 | try ais.pushIndent(.normal); |
| 1630 | try renderToken(r, builtin_token + 1, Space.newline); // ( | 1625 | try renderToken(r, builtin_token + 1, Space.newline); // ( |
| 1631 | | 1626 | |
| 1632 | for (params) |param_node| { | 1627 | for (params) |param_node| { |
| ... | @@ -1752,7 +1747,7 @@ fn renderFnProto(r: *Render, fn_proto: Ast.full.FnProto, space: Space) Error!voi | ... | @@ -1752,7 +1747,7 @@ fn renderFnProto(r: *Render, fn_proto: Ast.full.FnProto, space: Space) Error!voi |
| 1752 | } | 1747 | } |
| 1753 | } else { | 1748 | } else { |
| 1754 | // One param per line. | 1749 | // One param per line. |
| 1755 | ais.pushIndent(); | 1750 | try ais.pushIndent(.normal); |
| 1756 | try renderToken(r, lparen, .newline); // ( | 1751 | try renderToken(r, lparen, .newline); // ( |
| 1757 | | 1752 | |
| 1758 | var param_i: usize = 0; | 1753 | var param_i: usize = 0; |
| ... | @@ -1933,7 +1928,7 @@ fn renderBlock( | ... | @@ -1933,7 +1928,7 @@ fn renderBlock( |
| 1933 | try renderIdentifier(r, lbrace - 2, .none, .eagerly_unquote); // identifier | 1928 | try renderIdentifier(r, lbrace - 2, .none, .eagerly_unquote); // identifier |
| 1934 | try renderToken(r, lbrace - 1, .space); // : | 1929 | try renderToken(r, lbrace - 1, .space); // : |
| 1935 | } | 1930 | } |
| 1936 | ais.pushIndentNextLine(); | 1931 | try ais.pushIndent(.normal); |
| 1937 | if (statements.len == 0) { | 1932 | if (statements.len == 0) { |
| 1938 | try renderToken(r, lbrace, .none); | 1933 | try renderToken(r, lbrace, .none); |
| 1939 | ais.popIndent(); | 1934 | ais.popIndent(); |
| ... | @@ -1986,7 +1981,7 @@ fn renderStructInit( | ... | @@ -1986,7 +1981,7 @@ fn renderStructInit( |
| 1986 | try renderExpression(r, struct_init.ast.type_expr, .none); // T | 1981 | try renderExpression(r, struct_init.ast.type_expr, .none); // T |
| 1987 | } | 1982 | } |
| 1988 | if (struct_init.ast.fields.len == 0) { | 1983 | if (struct_init.ast.fields.len == 0) { |
| 1989 | ais.pushIndentNextLine(); | 1984 | try ais.pushIndent(.normal); |
| 1990 | try renderToken(r, struct_init.ast.lbrace, .none); // lbrace | 1985 | try renderToken(r, struct_init.ast.lbrace, .none); // lbrace |
| 1991 | ais.popIndent(); | 1986 | ais.popIndent(); |
| 1992 | return renderToken(r, struct_init.ast.lbrace + 1, space); // rbrace | 1987 | return renderToken(r, struct_init.ast.lbrace + 1, space); // rbrace |
| ... | @@ -1996,7 +1991,7 @@ fn renderStructInit( | ... | @@ -1996,7 +1991,7 @@ fn renderStructInit( |
| 1996 | const trailing_comma = token_tags[rbrace - 1] == .comma; | 1991 | const trailing_comma = token_tags[rbrace - 1] == .comma; |
| 1997 | if (trailing_comma or hasComment(tree, struct_init.ast.lbrace, rbrace)) { | 1992 | if (trailing_comma or hasComment(tree, struct_init.ast.lbrace, rbrace)) { |
| 1998 | // Render one field init per line. | 1993 | // Render one field init per line. |
| 1999 | ais.pushIndentNextLine(); | 1994 | try ais.pushIndent(.normal); |
| 2000 | try renderToken(r, struct_init.ast.lbrace, .newline); | 1995 | try renderToken(r, struct_init.ast.lbrace, .newline); |
| 2001 | | 1996 | |
| 2002 | try renderToken(r, struct_init.ast.lbrace + 1, .none); // . | 1997 | try renderToken(r, struct_init.ast.lbrace + 1, .none); // . |
| ... | @@ -2054,7 +2049,7 @@ fn renderArrayInit( | ... | @@ -2054,7 +2049,7 @@ fn renderArrayInit( |
| 2054 | } | 2049 | } |
| 2055 | | 2050 | |
| 2056 | if (array_init.ast.elements.len == 0) { | 2051 | if (array_init.ast.elements.len == 0) { |
| 2057 | ais.pushIndentNextLine(); | 2052 | try ais.pushIndent(.normal); |
| 2058 | try renderToken(r, array_init.ast.lbrace, .none); // lbrace | 2053 | try renderToken(r, array_init.ast.lbrace, .none); // lbrace |
| 2059 | ais.popIndent(); | 2054 | ais.popIndent(); |
| 2060 | return renderToken(r, array_init.ast.lbrace + 1, space); // rbrace | 2055 | return renderToken(r, array_init.ast.lbrace + 1, space); // rbrace |
| ... | @@ -2096,7 +2091,7 @@ fn renderArrayInit( | ... | @@ -2096,7 +2091,7 @@ fn renderArrayInit( |
| 2096 | return renderToken(r, last_elem_token + 1, space); // rbrace | 2091 | return renderToken(r, last_elem_token + 1, space); // rbrace |
| 2097 | } | 2092 | } |
| 2098 | | 2093 | |
| 2099 | ais.pushIndentNextLine(); | 2094 | try ais.pushIndent(.normal); |
| 2100 | try renderToken(r, array_init.ast.lbrace, .newline); | 2095 | try renderToken(r, array_init.ast.lbrace, .newline); |
| 2101 | | 2096 | |
| 2102 | var expr_index: usize = 0; | 2097 | var expr_index: usize = 0; |
| ... | @@ -2149,7 +2144,8 @@ fn renderArrayInit( | ... | @@ -2149,7 +2144,8 @@ fn renderArrayInit( |
| 2149 | const sub_expr_buffer_starts = try gpa.alloc(usize, section_exprs.len + 1); | 2144 | const sub_expr_buffer_starts = try gpa.alloc(usize, section_exprs.len + 1); |
| 2150 | defer gpa.free(sub_expr_buffer_starts); | 2145 | defer gpa.free(sub_expr_buffer_starts); |
| 2151 | | 2146 | |
| 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(); |
| 2153 | var sub_render: Render = .{ | 2149 | var sub_render: Render = .{ |
| 2154 | .gpa = r.gpa, | 2150 | .gpa = r.gpa, |
| 2155 | .ais = &auto_indenting_stream, | 2151 | .ais = &auto_indenting_stream, |
| ... | @@ -2312,7 +2308,7 @@ fn renderContainerDecl( | ... | @@ -2312,7 +2308,7 @@ fn renderContainerDecl( |
| 2312 | | 2308 | |
| 2313 | const rbrace = tree.lastToken(container_decl_node); | 2309 | const rbrace = tree.lastToken(container_decl_node); |
| 2314 | if (container_decl.ast.members.len == 0) { | 2310 | if (container_decl.ast.members.len == 0) { |
| 2315 | ais.pushIndentNextLine(); | 2311 | try ais.pushIndent(.normal); |
| 2316 | if (token_tags[lbrace + 1] == .container_doc_comment) { | 2312 | if (token_tags[lbrace + 1] == .container_doc_comment) { |
| 2317 | try renderToken(r, lbrace, .newline); // lbrace | 2313 | try renderToken(r, lbrace, .newline); // lbrace |
| 2318 | try renderContainerDocComments(r, lbrace + 1); | 2314 | try renderContainerDocComments(r, lbrace + 1); |
| ... | @@ -2354,7 +2350,7 @@ fn renderContainerDecl( | ... | @@ -2354,7 +2350,7 @@ fn renderContainerDecl( |
| 2354 | } | 2350 | } |
| 2355 | | 2351 | |
| 2356 | // One member per line. | 2352 | // One member per line. |
| 2357 | ais.pushIndentNextLine(); | 2353 | try ais.pushIndent(.normal); |
| 2358 | try renderToken(r, lbrace, .newline); // lbrace | 2354 | try renderToken(r, lbrace, .newline); // lbrace |
| 2359 | if (token_tags[lbrace + 1] == .container_doc_comment) { | 2355 | if (token_tags[lbrace + 1] == .container_doc_comment) { |
| 2360 | try renderContainerDocComments(r, lbrace + 1); | 2356 | try renderContainerDocComments(r, lbrace + 1); |
| ... | @@ -2395,7 +2391,7 @@ fn renderAsm( | ... | @@ -2395,7 +2391,7 @@ fn renderAsm( |
| 2395 | } | 2391 | } |
| 2396 | | 2392 | |
| 2397 | if (asm_node.ast.items.len == 0) { | 2393 | if (asm_node.ast.items.len == 0) { |
| 2398 | ais.pushIndent(); | 2394 | try ais.pushIndent(.normal); |
| 2399 | if (asm_node.first_clobber) |first_clobber| { | 2395 | if (asm_node.first_clobber) |first_clobber| { |
| 2400 | // asm ("foo" ::: "a", "b") | 2396 | // asm ("foo" ::: "a", "b") |
| 2401 | // asm ("foo" ::: "a", "b",) | 2397 | // asm ("foo" ::: "a", "b",) |
| ... | @@ -2433,7 +2429,7 @@ fn renderAsm( | ... | @@ -2433,7 +2429,7 @@ fn renderAsm( |
| 2433 | } | 2429 | } |
| 2434 | } | 2430 | } |
| 2435 | | 2431 | |
| 2436 | ais.pushIndent(); | 2432 | try ais.pushIndent(.normal); |
| 2437 | try renderExpression(r, asm_node.ast.template, .newline); | 2433 | try renderExpression(r, asm_node.ast.template, .newline); |
| 2438 | ais.setIndentDelta(asm_indent_delta); | 2434 | ais.setIndentDelta(asm_indent_delta); |
| 2439 | const colon1 = tree.lastToken(asm_node.ast.template) + 1; | 2435 | const colon1 = tree.lastToken(asm_node.ast.template) + 1; |
| ... | @@ -2444,7 +2440,7 @@ fn renderAsm( | ... | @@ -2444,7 +2440,7 @@ fn renderAsm( |
| 2444 | } else colon2: { | 2440 | } else colon2: { |
| 2445 | try renderToken(r, colon1, .space); // : | 2441 | try renderToken(r, colon1, .space); // : |
| 2446 | | 2442 | |
| 2447 | ais.pushIndent(); | 2443 | try ais.pushIndent(.normal); |
| 2448 | for (asm_node.outputs, 0..) |asm_output, i| { | 2444 | for (asm_node.outputs, 0..) |asm_output, i| { |
| 2449 | if (i + 1 < asm_node.outputs.len) { | 2445 | if (i + 1 < asm_node.outputs.len) { |
| 2450 | const next_asm_output = asm_node.outputs[i + 1]; | 2446 | const next_asm_output = asm_node.outputs[i + 1]; |
| ... | @@ -2476,7 +2472,7 @@ fn renderAsm( | ... | @@ -2476,7 +2472,7 @@ fn renderAsm( |
| 2476 | break :colon3 colon2 + 1; | 2472 | break :colon3 colon2 + 1; |
| 2477 | } else colon3: { | 2473 | } else colon3: { |
| 2478 | try renderToken(r, colon2, .space); // : | 2474 | try renderToken(r, colon2, .space); // : |
| 2479 | ais.pushIndent(); | 2475 | try ais.pushIndent(.normal); |
| 2480 | for (asm_node.inputs, 0..) |asm_input, i| { | 2476 | for (asm_node.inputs, 0..) |asm_input, i| { |
| 2481 | if (i + 1 < asm_node.inputs.len) { | 2477 | if (i + 1 < asm_node.inputs.len) { |
| 2482 | const next_asm_input = asm_node.inputs[i + 1]; | 2478 | const next_asm_input = asm_node.inputs[i + 1]; |
| ... | @@ -2558,7 +2554,7 @@ fn renderParamList( | ... | @@ -2558,7 +2554,7 @@ fn renderParamList( |
| 2558 | const token_tags = tree.tokens.items(.tag); | 2554 | const token_tags = tree.tokens.items(.tag); |
| 2559 | | 2555 | |
| 2560 | if (params.len == 0) { | 2556 | if (params.len == 0) { |
| 2561 | ais.pushIndentNextLine(); | 2557 | try ais.pushIndent(.normal); |
| 2562 | try renderToken(r, lparen, .none); | 2558 | try renderToken(r, lparen, .none); |
| 2563 | ais.popIndent(); | 2559 | ais.popIndent(); |
| 2564 | return renderToken(r, lparen + 1, space); // ) | 2560 | return renderToken(r, lparen + 1, space); // ) |
| ... | @@ -2567,22 +2563,15 @@ fn renderParamList( | ... | @@ -2567,22 +2563,15 @@ fn renderParamList( |
| 2567 | const last_param = params[params.len - 1]; | 2563 | const last_param = params[params.len - 1]; |
| 2568 | const after_last_param_tok = tree.lastToken(last_param) + 1; | 2564 | const after_last_param_tok = tree.lastToken(last_param) + 1; |
| 2569 | if (token_tags[after_last_param_tok] == .comma) { | 2565 | if (token_tags[after_last_param_tok] == .comma) { |
| 2570 | ais.pushIndentNextLine(); | 2566 | try ais.pushIndent(.normal); |
| 2571 | try renderToken(r, lparen, .newline); // ( | 2567 | try renderToken(r, lparen, .newline); // ( |
| 2572 | for (params, 0..) |param_node, i| { | 2568 | for (params, 0..) |param_node, i| { |
| 2573 | if (i + 1 < params.len) { | 2569 | if (i + 1 < params.len) { |
| 2574 | try renderExpression(r, param_node, .none); | 2570 | try renderExpression(r, param_node, .none); |
| 2575 | | 2571 | |
| 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 | | | |
| 2581 | const comma = tree.lastToken(param_node) + 1; | 2572 | const comma = tree.lastToken(param_node) + 1; |
| 2582 | try renderToken(r, comma, .newline); // , | 2573 | try renderToken(r, comma, .newline); // , |
| 2583 | | 2574 | |
| 2584 | if (is_multiline_string) ais.pushIndent(); | | |
| 2585 | | | |
| 2586 | try renderExtraNewline(r, params[i + 1]); | 2575 | try renderExtraNewline(r, params[i + 1]); |
| 2587 | } else { | 2576 | } else { |
| 2588 | try renderExpression(r, param_node, .comma); | 2577 | try renderExpression(r, param_node, .comma); |
| ... | @@ -2599,9 +2588,12 @@ fn renderParamList( | ... | @@ -2599,9 +2588,12 @@ fn renderParamList( |
| 2599 | if (token_tags[first_param_token] == .multiline_string_literal_line or | 2588 | if (token_tags[first_param_token] == .multiline_string_literal_line or |
| 2600 | hasSameLineComment(tree, first_param_token - 1)) | 2589 | hasSameLineComment(tree, first_param_token - 1)) |
| 2601 | { | 2590 | { |
| 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); |
| 2603 | } | 2596 | } |
| 2604 | try renderExpression(r, param_node, .none); | | |
| 2605 | | 2597 | |
| 2606 | if (i + 1 < params.len) { | 2598 | if (i + 1 < params.len) { |
| 2607 | const comma = tree.lastToken(param_node) + 1; | 2599 | const comma = tree.lastToken(param_node) + 1; |
| ... | @@ -2615,66 +2607,6 @@ fn renderParamList( | ... | @@ -2615,66 +2607,6 @@ fn renderParamList( |
| 2615 | return renderToken(r, after_last_param_tok, space); // ) | 2607 | return renderToken(r, after_last_param_tok, space); // ) |
| 2616 | } | 2608 | } |
| 2617 | | 2609 | |
| 2618 | /// Renders the given expression indented, popping the indent before rendering | | |
| 2619 | /// any following line comments | | |
| 2620 | fn 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 | | | |
| 2678 | /// Render an expression, and the comma that follows it, if it is present in the source. | 2610 | /// Render an expression, and the comma that follows it, if it is present in the source. |
| 2679 | /// If a comma is present, and `space` is `Space.comma`, render only a single comma. | 2611 | /// If a comma is present, and `space` is `Space.comma`, render only a single comma. |
| 2680 | fn renderExpressionComma(r: *Render, node: Ast.Node.Index, space: Space) Error!void { | 2612 | fn renderExpressionComma(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| ... | @@ -3315,6 +3247,14 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { | ... | @@ -3315,6 +3247,14 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { |
| 3315 | pub const WriteError = UnderlyingWriter.Error; | 3247 | pub const WriteError = UnderlyingWriter.Error; |
| 3316 | pub const Writer = std.io.Writer(*Self, WriteError, write); | 3248 | pub const Writer = std.io.Writer(*Self, WriteError, write); |
| 3317 | | 3249 | |
| | 3250 | pub const IndentType = enum { |
| | 3251 | normal, |
| | 3252 | }; |
| | 3253 | const StackElem = struct { |
| | 3254 | indent_type: IndentType, |
| | 3255 | realized: bool, |
| | 3256 | }; |
| | 3257 | |
| 3318 | underlying_writer: UnderlyingWriter, | 3258 | underlying_writer: UnderlyingWriter, |
| 3319 | | 3259 | |
| 3320 | /// Offset into the source at which formatting has been disabled with | 3260 | /// Offset into the source at which formatting has been disabled with |
| ... | @@ -3327,21 +3267,24 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { | ... | @@ -3327,21 +3267,24 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { |
| 3327 | | 3267 | |
| 3328 | indent_count: usize = 0, | 3268 | indent_count: usize = 0, |
| 3329 | indent_delta: usize, | 3269 | indent_delta: usize, |
| | 3270 | indent_stack: std.ArrayList(StackElem), |
| | 3271 | disable_indent_committing: usize = 0, |
| 3330 | current_line_empty: bool = true, | 3272 | current_line_empty: bool = true, |
| 3331 | /// automatically popped when applied | | |
| 3332 | indent_one_shot_count: usize = 0, | | |
| 3333 | /// the most recently applied indent | 3273 | /// the most recently applied indent |
| 3334 | applied_indent: usize = 0, | 3274 | applied_indent: usize = 0, |
| 3335 | /// not used until the next line | | |
| 3336 | indent_next_line: usize = 0, | | |
| 3337 | | 3275 | |
| 3338 | pub fn init(buffer: *std.ArrayList(u8), indent_delta: usize) Self { | 3276 | pub fn init(buffer: *std.ArrayList(u8), indent_delta_: usize) Self { |
| 3339 | return .{ | 3277 | return .{ |
| 3340 | .underlying_writer = buffer.writer(), | 3278 | .underlying_writer = buffer.writer(), |
| 3341 | .indent_delta = indent_delta, | 3279 | .indent_delta = indent_delta_, |
| | 3280 | .indent_stack = std.ArrayList(StackElem).init(buffer.allocator), |
| 3342 | }; | 3281 | }; |
| 3343 | } | 3282 | } |
| 3344 | | 3283 | |
| | 3284 | pub fn deinit(self: *Self) void { |
| | 3285 | self.indent_stack.deinit(); |
| | 3286 | } |
| | 3287 | |
| 3345 | pub fn writer(self: *Self) Writer { | 3288 | pub fn writer(self: *Self) Writer { |
| 3346 | return .{ .context = self }; | 3289 | return .{ .context = self }; |
| 3347 | } | 3290 | } |
| ... | @@ -3385,7 +3328,23 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { | ... | @@ -3385,7 +3328,23 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { |
| 3385 | | 3328 | |
| 3386 | fn resetLine(self: *Self) void { | 3329 | fn resetLine(self: *Self) void { |
| 3387 | self.current_line_empty = true; | 3330 | 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; |
| 3389 | } | 3348 | } |
| 3390 | | 3349 | |
| 3391 | /// Insert a newline unless the current line is blank | 3350 | /// Insert a newline unless the current line is blank |
| ... | @@ -3397,36 +3356,19 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { | ... | @@ -3397,36 +3356,19 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { |
| 3397 | /// Push default indentation | 3356 | /// Push default indentation |
| 3398 | /// Doesn't actually write any indentation. | 3357 | /// Doesn't actually write any indentation. |
| 3399 | /// Just primes the stream to be able to write the correct indentation if it needs to. | 3358 | /// Just primes the stream to be able to write the correct indentation if it needs to. |
| 3400 | pub fn pushIndent(self: *Self) void { | 3359 | pub fn pushIndent(self: *Self, indent_type: IndentType) !void { |
| 3401 | self.indent_count += 1; | 3360 | try self.indent_stack.append(.{ .indent_type = indent_type, .realized = false }); |
| 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(); | | |
| 3422 | } | 3361 | } |
| 3423 | | 3362 | |
| 3424 | pub fn popIndent(self: *Self) void { | 3363 | pub fn popIndent(self: *Self) void { |
| 3425 | assert(self.indent_count != 0); | 3364 | if (self.indent_stack.pop().realized) { |
| 3426 | self.indent_count -= 1; | 3365 | assert(self.indent_count > 0); |
| | 3366 | self.indent_count -= 1; |
| | 3367 | } |
| | 3368 | } |
| 3427 | | 3369 | |
| 3428 | if (self.indent_next_line > 0) | 3370 | pub fn indentStackEmpty(self: *Self) bool { |
| 3429 | self.indent_next_line -= 1; | 3371 | return self.indent_stack.items.len == 0; |
| 3430 | } | 3372 | } |
| 3431 | | 3373 | |
| 3432 | /// Writes ' ' bytes if the current line is empty | 3374 | /// Writes ' ' bytes if the current line is empty |
| ... | @@ -3438,9 +3380,6 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { | ... | @@ -3438,9 +3380,6 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { |
| 3438 | } | 3380 | } |
| 3439 | self.applied_indent = current_indent; | 3381 | self.applied_indent = current_indent; |
| 3440 | } | 3382 | } |
| 3441 | | | |
| 3442 | self.indent_count -= self.indent_one_shot_count; | | |
| 3443 | self.indent_one_shot_count = 0; | | |
| 3444 | self.current_line_empty = false; | 3383 | self.current_line_empty = false; |
| 3445 | } | 3384 | } |
| 3446 | | 3385 | |
| ... | @@ -3451,12 +3390,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { | ... | @@ -3451,12 +3390,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { |
| 3451 | } | 3390 | } |
| 3452 | | 3391 | |
| 3453 | fn currentIndent(self: *Self) usize { | 3392 | fn currentIndent(self: *Self) usize { |
| 3454 | var indent_current: usize = 0; | 3393 | return self.indent_count * self.indent_delta; |
| 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; | | |
| 3460 | } | 3394 | } |
| 3461 | }; | 3395 | }; |
| 3462 | } | 3396 | } |