authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-02-24 16:44:55+01:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-02-24 17:28:29+01:00
log52c45bf44d797f28594db5a75c306ed209cfb933
treef89c6a5a425cec8d8be8a1c284ce3a270a41598c
parent371b21bdfbfa8917b44e809fb8a041411ffc6b8a
signaturelock-open Commit is signed but in an unrecognized format.

zig fmt: rework single statement if/while/for indentation

This approach properly handles nesting unlike the approach in the previous commit.

2 files changed, 101 insertions(+), 64 deletions(-)

lib/std/zig/parser_test.zig+17
...@@ -1496,12 +1496,14 @@ test "zig fmt: if nested" {...@@ -1496,12 +1496,14 @@ test "zig fmt: if nested" {
1496 \\ GE_EQUAL1496 \\ GE_EQUAL
1497 \\ else1497 \\ else
1498 \\ GE_GREATER1498 \\ GE_GREATER
1499 \\ // comment
1499 \\ else if (aInt > bInt)1500 \\ else if (aInt > bInt)
1500 \\ GE_LESS1501 \\ GE_LESS
1501 \\ else if (aInt == bInt)1502 \\ else if (aInt == bInt)
1502 \\ GE_EQUAL1503 \\ GE_EQUAL
1503 \\ else1504 \\ else
1504 \\ GE_GREATER;1505 \\ GE_GREATER;
1506 \\ // comment
1505 \\}1507 \\}
1506 \\1508 \\
1507 );1509 );
...@@ -4189,6 +4191,21 @@ test "zig fmt: line comment after multiline single expr if statement with multil...@@ -4189,6 +4191,21 @@ test "zig fmt: line comment after multiline single expr if statement with multil
4189 \\4191 \\
4190 \\ // bar4192 \\ // bar
4191 \\ baz();4193 \\ baz();
4194 \\
4195 \\ if (foo)
4196 \\ x =
4197 \\ \\hello
4198 \\ \\hello
4199 \\ \\
4200 \\ else
4201 \\ y =
4202 \\ \\hello
4203 \\ \\hello
4204 \\ \\
4205 \\ ;
4206 \\
4207 \\ // bar
4208 \\ baz();
4192 \\}4209 \\}
4193 \\4210 \\
4194 );4211 );
lib/std/zig/render.zig+84-64
...@@ -44,7 +44,6 @@ pub fn renderTree(buffer: *std.ArrayList(u8), tree: ast.Tree) Error!void {...@@ -44,7 +44,6 @@ pub fn renderTree(buffer: *std.ArrayList(u8), tree: ast.Tree) Error!void {
44/// Render all members in the given slice, keeping empty lines where appropriate44/// Render all members in the given slice, keeping empty lines where appropriate
45fn renderMembers(gpa: *Allocator, ais: *Ais, tree: ast.Tree, members: []const ast.Node.Index) Error!void {45fn renderMembers(gpa: *Allocator, ais: *Ais, tree: ast.Tree, members: []const ast.Node.Index) Error!void {
46 if (members.len == 0) return;46 if (members.len == 0) return;
47 //try renderExtraNewline(ais, tree, members[0]);
48 try renderMember(gpa, ais, tree, members[0], .newline);47 try renderMember(gpa, ais, tree, members[0], .newline);
49 for (members[1..]) |member| {48 for (members[1..]) |member| {
50 try renderExtraNewline(ais, tree, member);49 try renderExtraNewline(ais, tree, member);
...@@ -202,10 +201,8 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I...@@ -202,10 +201,8 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I
202 while (locked_indents > 0) : (locked_indents -= 1) ais.popIndent();201 while (locked_indents > 0) : (locked_indents -= 1) ais.popIndent();
203202
204 switch (space) {203 switch (space) {
205 .none, .space, .newline => {},204 .none, .space, .newline, .skip => {},
206 .newline_pop => ais.popIndent(),
207 .semicolon => if (token_tags[i] == .semicolon) try renderToken(ais, tree, i, .newline),205 .semicolon => if (token_tags[i] == .semicolon) try renderToken(ais, tree, i, .newline),
208 .semicolon_pop => if (token_tags[i] == .semicolon) try renderToken(ais, tree, i, .newline_pop),
209 .comma => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .newline),206 .comma => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .newline),
210 .comma_space => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .space),207 .comma_space => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .space),
211 }208 }
...@@ -1147,15 +1144,11 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full....@@ -1147,15 +1144,11 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full.
1147 } else {1144 } else {
1148 try renderToken(ais, tree, while_node.else_token, .newline); // else1145 try renderToken(ais, tree, while_node.else_token, .newline); // else
1149 }1146 }
1150 ais.pushIndent();1147 try renderExpressionIndented(gpa, ais, tree, while_node.ast.else_expr, space);
1151 try renderExpression(gpa, ais, tree, while_node.ast.else_expr, space);
1152 ais.popIndent();
1153 return;1148 return;
1154 }1149 }
1155 } else {1150 } else {
1156 ais.pushIndent();1151 try renderExpressionIndented(gpa, ais, tree, while_node.ast.then_expr, space);
1157 assert(space == .semicolon);
1158 try renderExpression(gpa, ais, tree, while_node.ast.then_expr, .semicolon_pop);
1159 return;1152 return;
1160 }1153 }
1161 }1154 }
...@@ -2168,6 +2161,64 @@ fn renderCall(...@@ -2168,6 +2161,64 @@ fn renderCall(
2168 return renderToken(ais, tree, after_last_param_tok, space); // )2161 return renderToken(ais, tree, after_last_param_tok, space); // )
2169}2162}
21702163
2164/// Renders the given expression indented, popping the indent before rendering
2165/// any following line comments
2166fn renderExpressionIndented(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void {
2167 const token_starts = tree.tokens.items(.start);
2168 const token_tags = tree.tokens.items(.tag);
2169
2170 ais.pushIndent();
2171
2172 var last_token = tree.lastToken(node);
2173 const punctuation = switch (space) {
2174 .none, .space, .newline, .skip => false,
2175 .comma => true,
2176 .comma_space => token_tags[last_token + 1] == .comma,
2177 .semicolon => token_tags[last_token + 1] == .semicolon,
2178 };
2179
2180 try renderExpression(gpa, ais, tree, node, if (punctuation) .none else .skip);
2181
2182 switch (space) {
2183 .none, .space, .newline, .skip => {},
2184 .comma => {
2185 if (token_tags[last_token + 1] == .comma) {
2186 try renderToken(ais, tree, last_token + 1, .skip);
2187 last_token += 1;
2188 } else {
2189 try ais.writer().writeByte(',');
2190 }
2191 },
2192 .comma_space => if (token_tags[last_token + 1] == .comma) {
2193 try renderToken(ais, tree, last_token + 1, .skip);
2194 last_token += 1;
2195 },
2196 .semicolon => if (token_tags[last_token + 1] == .semicolon) {
2197 try renderToken(ais, tree, last_token + 1, .skip);
2198 last_token += 1;
2199 },
2200 }
2201
2202 ais.popIndent();
2203
2204 if (space == .skip) return;
2205
2206 const comment_start = token_starts[last_token] + tokenSliceForRender(tree, last_token).len;
2207 const comment = try renderComments(ais, tree, comment_start, token_starts[last_token + 1]);
2208
2209 if (!comment) switch (space) {
2210 .none => {},
2211 .space,
2212 .comma_space,
2213 => try ais.writer().writeByte(' '),
2214 .newline,
2215 .comma,
2216 .semicolon,
2217 => try ais.insertNewline(),
2218 .skip => unreachable,
2219 };
2220}
2221
2171/// Render an expression, and the comma that follows it, if it is present in the source.2222/// Render an expression, and the comma that follows it, if it is present in the source.
2172fn renderExpressionComma(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void {2223fn renderExpressionComma(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void {
2173 const token_tags = tree.tokens.items(.tag);2224 const token_tags = tree.tokens.items(.tag);
...@@ -2198,9 +2249,6 @@ const Space = enum {...@@ -2198,9 +2249,6 @@ const Space = enum {
2198 space,2249 space,
2199 /// Output the token lexeme followed by a newline.2250 /// Output the token lexeme followed by a newline.
2200 newline,2251 newline,
2201 /// Same as newline, but pop an indent level before rendering the
2202 /// following comments if any.
2203 newline_pop,
2204 /// If the next token is a comma, render it as well. If not, insert one.2252 /// If the next token is a comma, render it as well. If not, insert one.
2205 /// In either case, a newline will be inserted afterwards.2253 /// In either case, a newline will be inserted afterwards.
2206 comma,2254 comma,
...@@ -2210,9 +2258,9 @@ const Space = enum {...@@ -2210,9 +2258,9 @@ const Space = enum {
2210 /// Additionally consume the next token if it is a semicolon.2258 /// Additionally consume the next token if it is a semicolon.
2211 /// In either case, a newline will be inserted afterwards.2259 /// In either case, a newline will be inserted afterwards.
2212 semicolon,2260 semicolon,
2213 /// Same as semicolon, but pop an indent level before rendering the2261 /// Skip rendering whitespace and comments. If this is used, the caller
2214 /// following comments if any.2262 /// *must* handle handle whitespace and comments manually.
2215 semicolon_pop,2263 skip,
2216};2264};
22172265
2218fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Space) Error!void {2266fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Space) Error!void {
...@@ -2224,65 +2272,37 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp...@@ -2224,65 +2272,37 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp
22242272
2225 try ais.writer().writeAll(lexeme);2273 try ais.writer().writeAll(lexeme);
22262274
2227 const token_end = token_start + lexeme.len;2275 if (space == .skip) return;
2228 const next_token_start = token_starts[token_index + 1];
2229 switch (space) {
2230 .none => _ = try renderComments(ais, tree, token_end, next_token_start),
2231
2232 .space => if (!try renderComments(ais, tree, token_end, next_token_start)) {
2233 try ais.writer().writeByte(' ');
2234 },
22352276
2236 .newline => if (!try renderComments(ais, tree, token_end, next_token_start)) {2277 if (space == .comma and token_tags[token_index + 1] != .comma) {
2237 try ais.insertNewline();2278 try ais.writer().writeByte(',');
2238 },2279 }
22392280
2240 .newline_pop => {2281 const comment = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1]);
2241 ais.popIndent();2282 switch (space) {
2242 if (!try renderComments(ais, tree, token_end, next_token_start)) {2283 .none => {},
2243 try ais.insertNewline();2284 .space => if (!comment) try ais.writer().writeByte(' '),
2244 }2285 .newline => if (!comment) try ais.insertNewline(),
2245 },
22462286
2247 .comma => if (token_tags[token_index + 1] == .comma) {2287 .comma => if (token_tags[token_index + 1] == .comma) {
2248 _ = try renderComments(ais, tree, token_end, next_token_start);
2249 try renderToken(ais, tree, token_index + 1, .newline);2288 try renderToken(ais, tree, token_index + 1, .newline);
2250 } else {2289 } else if (!comment) {
2251 try ais.writer().writeByte(',');2290 try ais.insertNewline();
2252 if (!try renderComments(ais, tree, token_end, next_token_start)) {
2253 try ais.insertNewline();
2254 }
2255 },2291 },
22562292
2257 .comma_space => {2293 .comma_space => if (token_tags[token_index + 1] == .comma) {
2258 const comment = try renderComments(ais, tree, token_end, next_token_start);2294 try renderToken(ais, tree, token_index + 1, .space);
2259 if (token_tags[token_index + 1] == .comma) {2295 } else if (!comment) {
2260 try renderToken(ais, tree, token_index + 1, .space);2296 try ais.writer().writeByte(' ');
2261 } else if (!comment) {
2262 try ais.writer().writeByte(' ');
2263 }
2264 },2297 },
22652298
2266 .semicolon => {2299 .semicolon => if (token_tags[token_index + 1] == .semicolon) {
2267 const comment = try renderComments(ais, tree, token_end, next_token_start);2300 try renderToken(ais, tree, token_index + 1, .newline);
2268 if (token_tags[token_index + 1] == .semicolon) {2301 } else if (!comment) {
2269 try renderToken(ais, tree, token_index + 1, .newline);2302 try ais.insertNewline();
2270 } else if (!comment) {
2271 try ais.insertNewline();
2272 }
2273 },2303 },
22742304
2275 .semicolon_pop => {2305 .skip => unreachable,
2276 if (token_tags[token_index + 1] == .semicolon) {
2277 _ = try renderComments(ais, tree, token_end, next_token_start);
2278 try renderToken(ais, tree, token_index + 1, .newline_pop);
2279 } else {
2280 ais.popIndent();
2281 if (!try renderComments(ais, tree, token_end, next_token_start)) {
2282 try ais.insertNewline();
2283 }
2284 }
2285 },
2286 }2306 }
2287}2307}
22882308