authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-08 13:21:04-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-08 13:21:04-07:00
log4caea5d62f1a37cf5661afdfbd47458fe6e38b5f
treeef912eb514b2c79df93b844898003d0de1f401dc
parent8d97f05662dcae88bde353224d97a2c72b93bac5

zig fmt: change --complexity to --stats

preparing to add more stats

1 files changed, 50 insertions(+), 22 deletions(-)

src/fmt.zig+50-22
......@@ -6,6 +6,7 @@ const process = std.process;
66const Allocator = std.mem.Allocator;
77const Color = std.zig.Color;
88const fatal = std.process.fatal;
9const Serializer = std.zon.Serializer;
910
1011const usage_fmt =
1112 \\Usage: zig fmt [file]...
......@@ -23,7 +24,7 @@ const usage_fmt =
2324 \\ --ast-check Run zig ast-check on every file
2425 \\ --exclude [file] Exclude file or directory from formatting
2526 \\ --zon Treat all input files as ZON, regardless of file extension
26 \\ --complexity Print a complexity report for each file as well as total
27 \\ --stats Print aggregated statistics in ZON format to stdout
2728 \\
2829 \\
2930;
......@@ -39,10 +40,16 @@ const Fmt = struct {
3940 io: Io,
4041 out_buffer: std.Io.Writer.Allocating,
4142 stdout_writer: *Io.File.Writer,
43 serializer: Serializer,
44 root_struct: Serializer.Struct,
4245
43 complexity: bool,
46 stats: bool,
4447 total_tokens: u64,
4548 total_nodes: u64,
49 /// Count per token tag index
50 token_stats: []u64,
51 /// Count per node tag index
52 node_stats: []u64,
4653
4754 const SeenMap = std.AutoHashMap(Io.File.INode, void);
4855};
......@@ -53,7 +60,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
5360 var check_flag = false;
5461 var check_ast_flag = false;
5562 var force_zon = false;
56 var complexity = false;
63 var stats = false;
5764
5865 var input_files = std.array_list.Managed([]const u8).init(gpa);
5966 defer input_files.deinit();
......@@ -84,8 +91,8 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
8491 check_flag = true;
8592 } else if (mem.eql(u8, arg, "--ast-check")) {
8693 check_ast_flag = true;
87 } else if (mem.eql(u8, arg, "--complexity")) {
88 complexity = true;
94 } else if (mem.eql(u8, arg, "--stats")) {
95 stats = true;
8996 } else if (mem.eql(u8, arg, "--exclude")) {
9097 if (i + 1 >= args.len) {
9198 fatal("expected parameter after --exclude", .{});
......@@ -185,13 +192,23 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
185192 .color = color,
186193 .out_buffer = .init(gpa),
187194 .stdout_writer = &stdout_writer,
188 .complexity = complexity,
195 .stats = stats,
189196 .total_tokens = 0,
190197 .total_nodes = 0,
198 .serializer = .{ .writer = &stdout_writer.interface },
199 .root_struct = undefined,
200 .token_stats = undefined,
201 .node_stats = undefined,
191202 };
192203 defer fmt.seen.deinit();
193204 defer fmt.out_buffer.deinit();
194205
206 if (stats) {
207 fmt.root_struct = try fmt.serializer.beginStruct(.{});
208 fmt.token_stats = try arena.alloc(u64, @typeInfo(std.zig.Token.Tag).@"enum".field_names.len);
209 fmt.node_stats = try arena.alloc(u64, @typeInfo(std.zig.Ast.Node.Tag).@"enum".field_names.len);
210 }
211
195212 // Mark any excluded files/directories as already seen,
196213 // so that they are skipped later during actual processing
197214 for (excluded_files.items) |file_path| {
......@@ -212,8 +229,10 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
212229 try fmtPath(&fmt, file_path, check_flag, Io.Dir.cwd(), file_path);
213230 }
214231
215 if (complexity) {
216 std.log.info("total: tokens={d} nodes={d}", .{ fmt.total_tokens, fmt.total_nodes });
232 if (stats) {
233 try fmt.root_struct.field("tokens", fmt.total_tokens, .{});
234 try fmt.root_struct.field("nodes", fmt.total_nodes, .{});
235 try fmt.root_struct.end();
217236 }
218237
219238 try fmt.stdout_writer.flush();
......@@ -357,8 +376,13 @@ fn fmtPathFile(
357376 }
358377 }
359378
360 if (fmt.complexity) {
361 std.log.info("{s}: tokens={d} nodes={d}", .{ file_path, tree.tokens.len, tree.nodes.len });
379 var zon_struct: Serializer.Struct = undefined;
380
381 if (fmt.stats) {
382 zon_struct = try fmt.root_struct.beginStructField(file_path, .{});
383 try zon_struct.field("tokens", tree.tokens.len, .{});
384 try zon_struct.field("nodes", tree.nodes.len, .{});
385
362386 fmt.total_tokens += tree.tokens.len;
363387 fmt.total_nodes += tree.nodes.len;
364388 }
......@@ -370,20 +394,24 @@ fn fmtPathFile(
370394 tree.render(gpa, &fmt.out_buffer.writer, .{}) catch |err| switch (err) {
371395 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
372396 };
373 if (mem.eql(u8, fmt.out_buffer.written(), source_code))
374 return;
375
376 if (check_mode) {
377 try fmt.stdout_writer.interface.print("{s}\n", .{file_path});
378 fmt.any_error = true;
379 } else {
380 var af = try dir.createFileAtomic(io, sub_path, .{ .permissions = stat.permissions, .replace = true });
381 defer af.deinit(io);
397 if (!mem.eql(u8, fmt.out_buffer.written(), source_code)) {
398 if (check_mode) {
399 fmt.any_error = true;
400 } else {
401 var af = try dir.createFileAtomic(io, sub_path, .{ .permissions = stat.permissions, .replace = true });
402 defer af.deinit(io);
382403
383 try af.file.writeStreamingAll(io, fmt.out_buffer.written());
384 try af.replace(io);
385 try fmt.stdout_writer.interface.print("{s}\n", .{file_path});
404 try af.file.writeStreamingAll(io, fmt.out_buffer.written());
405 try af.replace(io);
406 }
407 if (fmt.stats) {
408 try zon_struct.field("dirty", true, .{});
409 } else {
410 try fmt.stdout_writer.interface.print("{s}\n", .{file_path});
411 }
386412 }
413
414 if (fmt.stats) try zon_struct.end();
387415}
388416
389417/// Provided for debugging/testing purposes; unused by the compiler.