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;...@@ -6,6 +6,7 @@ const process = std.process;
6const Allocator = std.mem.Allocator;6const Allocator = std.mem.Allocator;
7const Color = std.zig.Color;7const Color = std.zig.Color;
8const fatal = std.process.fatal;8const fatal = std.process.fatal;
9const Serializer = std.zon.Serializer;
910
10const usage_fmt =11const usage_fmt =
11 \\Usage: zig fmt [file]...12 \\Usage: zig fmt [file]...
...@@ -23,7 +24,7 @@ const usage_fmt =...@@ -23,7 +24,7 @@ const usage_fmt =
23 \\ --ast-check Run zig ast-check on every file24 \\ --ast-check Run zig ast-check on every file
24 \\ --exclude [file] Exclude file or directory from formatting25 \\ --exclude [file] Exclude file or directory from formatting
25 \\ --zon Treat all input files as ZON, regardless of file extension26 \\ --zon Treat all input files as ZON, regardless of file extension
26 \\ --complexity Print a complexity report for each file as well as total27 \\ --stats Print aggregated statistics in ZON format to stdout
27 \\28 \\
28 \\29 \\
29;30;
...@@ -39,10 +40,16 @@ const Fmt = struct {...@@ -39,10 +40,16 @@ const Fmt = struct {
39 io: Io,40 io: Io,
40 out_buffer: std.Io.Writer.Allocating,41 out_buffer: std.Io.Writer.Allocating,
41 stdout_writer: *Io.File.Writer,42 stdout_writer: *Io.File.Writer,
43 serializer: Serializer,
44 root_struct: Serializer.Struct,
4245
43 complexity: bool,46 stats: bool,
44 total_tokens: u64,47 total_tokens: u64,
45 total_nodes: u64,48 total_nodes: u64,
49 /// Count per token tag index
50 token_stats: []u64,
51 /// Count per node tag index
52 node_stats: []u64,
4653
47 const SeenMap = std.AutoHashMap(Io.File.INode, void);54 const SeenMap = std.AutoHashMap(Io.File.INode, void);
48};55};
...@@ -53,7 +60,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !...@@ -53,7 +60,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
53 var check_flag = false;60 var check_flag = false;
54 var check_ast_flag = false;61 var check_ast_flag = false;
55 var force_zon = false;62 var force_zon = false;
56 var complexity = false;63 var stats = false;
5764
58 var input_files = std.array_list.Managed([]const u8).init(gpa);65 var input_files = std.array_list.Managed([]const u8).init(gpa);
59 defer input_files.deinit();66 defer input_files.deinit();
...@@ -84,8 +91,8 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !...@@ -84,8 +91,8 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
84 check_flag = true;91 check_flag = true;
85 } else if (mem.eql(u8, arg, "--ast-check")) {92 } else if (mem.eql(u8, arg, "--ast-check")) {
86 check_ast_flag = true;93 check_ast_flag = true;
87 } else if (mem.eql(u8, arg, "--complexity")) {94 } else if (mem.eql(u8, arg, "--stats")) {
88 complexity = true;95 stats = true;
89 } else if (mem.eql(u8, arg, "--exclude")) {96 } else if (mem.eql(u8, arg, "--exclude")) {
90 if (i + 1 >= args.len) {97 if (i + 1 >= args.len) {
91 fatal("expected parameter after --exclude", .{});98 fatal("expected parameter after --exclude", .{});
...@@ -185,13 +192,23 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !...@@ -185,13 +192,23 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
185 .color = color,192 .color = color,
186 .out_buffer = .init(gpa),193 .out_buffer = .init(gpa),
187 .stdout_writer = &stdout_writer,194 .stdout_writer = &stdout_writer,
188 .complexity = complexity,195 .stats = stats,
189 .total_tokens = 0,196 .total_tokens = 0,
190 .total_nodes = 0,197 .total_nodes = 0,
198 .serializer = .{ .writer = &stdout_writer.interface },
199 .root_struct = undefined,
200 .token_stats = undefined,
201 .node_stats = undefined,
191 };202 };
192 defer fmt.seen.deinit();203 defer fmt.seen.deinit();
193 defer fmt.out_buffer.deinit();204 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
195 // Mark any excluded files/directories as already seen,212 // Mark any excluded files/directories as already seen,
196 // so that they are skipped later during actual processing213 // so that they are skipped later during actual processing
197 for (excluded_files.items) |file_path| {214 for (excluded_files.items) |file_path| {
...@@ -212,8 +229,10 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !...@@ -212,8 +229,10 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
212 try fmtPath(&fmt, file_path, check_flag, Io.Dir.cwd(), file_path);229 try fmtPath(&fmt, file_path, check_flag, Io.Dir.cwd(), file_path);
213 }230 }
214231
215 if (complexity) {232 if (stats) {
216 std.log.info("total: tokens={d} nodes={d}", .{ fmt.total_tokens, fmt.total_nodes });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();
217 }236 }
218237
219 try fmt.stdout_writer.flush();238 try fmt.stdout_writer.flush();
...@@ -357,8 +376,13 @@ fn fmtPathFile(...@@ -357,8 +376,13 @@ fn fmtPathFile(
357 }376 }
358 }377 }
359378
360 if (fmt.complexity) {379 var zon_struct: Serializer.Struct = undefined;
361 std.log.info("{s}: tokens={d} nodes={d}", .{ file_path, tree.tokens.len, tree.nodes.len });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
362 fmt.total_tokens += tree.tokens.len;386 fmt.total_tokens += tree.tokens.len;
363 fmt.total_nodes += tree.nodes.len;387 fmt.total_nodes += tree.nodes.len;
364 }388 }
...@@ -370,20 +394,24 @@ fn fmtPathFile(...@@ -370,20 +394,24 @@ fn fmtPathFile(
370 tree.render(gpa, &fmt.out_buffer.writer, .{}) catch |err| switch (err) {394 tree.render(gpa, &fmt.out_buffer.writer, .{}) catch |err| switch (err) {
371 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,395 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
372 };396 };
373 if (mem.eql(u8, fmt.out_buffer.written(), source_code))397 if (!mem.eql(u8, fmt.out_buffer.written(), source_code)) {
374 return;398 if (check_mode) {
375399 fmt.any_error = true;
376 if (check_mode) {400 } else {
377 try fmt.stdout_writer.interface.print("{s}\n", .{file_path});401 var af = try dir.createFileAtomic(io, sub_path, .{ .permissions = stat.permissions, .replace = true });
378 fmt.any_error = true;402 defer af.deinit(io);
379 } else {
380 var af = try dir.createFileAtomic(io, sub_path, .{ .permissions = stat.permissions, .replace = true });
381 defer af.deinit(io);
382403
383 try af.file.writeStreamingAll(io, fmt.out_buffer.written());404 try af.file.writeStreamingAll(io, fmt.out_buffer.written());
384 try af.replace(io);405 try af.replace(io);
385 try fmt.stdout_writer.interface.print("{s}\n", .{file_path});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 }
386 }412 }
413
414 if (fmt.stats) try zon_struct.end();
387}415}
388416
389/// Provided for debugging/testing purposes; unused by the compiler.417/// Provided for debugging/testing purposes; unused by the compiler.