authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-11-12 22:53:24+00:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-11-12 21:55:46-08:00
log9ebce51e164c6d35e4f412eb747fa8d3c6ea84b3
treed96d93a907d3d1c92ca56a6ca28493ce65ea801d
parent9996f8b9b17f7e04be64ac220c9bad743b45a2b7

compiler: un-jit `zig fmt`

This command being JITed leads to a substantially worse first-time user experience, since you have to wait for upwards of 20 seconds for `fmt.zig` to build. This is especially bad when your editor is configured to run `zig fmt` on save and does so in a blocking manner. As such, it makes sense from a usability perspective to not JIT this particular command.

3 files changed, 337 insertions(+), 347 deletions(-)

lib/compiler/fmt.zig deleted-343
...@@ -1,343 +0,0 @@
1const std = @import("std");
2const mem = std.mem;
3const fs = std.fs;
4const process = std.process;
5const Allocator = std.mem.Allocator;
6const Color = std.zig.Color;
7
8const usage_fmt =
9 \\Usage: zig fmt [file]...
10 \\
11 \\ Formats the input files and modifies them in-place.
12 \\ Arguments can be files or directories, which are searched
13 \\ recursively.
14 \\
15 \\Options:
16 \\ -h, --help Print this help and exit
17 \\ --color [auto|off|on] Enable or disable colored error messages
18 \\ --stdin Format code from stdin; output to stdout
19 \\ --check List non-conforming files and exit with an error
20 \\ if the list is non-empty
21 \\ --ast-check Run zig ast-check on every file
22 \\ --exclude [file] Exclude file or directory from formatting
23 \\
24 \\
25;
26
27const Fmt = struct {
28 seen: SeenMap,
29 any_error: bool,
30 check_ast: bool,
31 color: Color,
32 gpa: Allocator,
33 arena: Allocator,
34 out_buffer: std.ArrayList(u8),
35
36 const SeenMap = std.AutoHashMap(fs.File.INode, void);
37};
38
39pub fn main() !void {
40 var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
41 defer arena_instance.deinit();
42 const arena = arena_instance.allocator();
43 const gpa = arena;
44
45 const args = try process.argsAlloc(arena);
46
47 var color: Color = .auto;
48 var stdin_flag: bool = false;
49 var check_flag: bool = false;
50 var check_ast_flag: bool = false;
51 var input_files = std.ArrayList([]const u8).init(gpa);
52 defer input_files.deinit();
53 var excluded_files = std.ArrayList([]const u8).init(gpa);
54 defer excluded_files.deinit();
55
56 {
57 var i: usize = 1;
58 while (i < args.len) : (i += 1) {
59 const arg = args[i];
60 if (mem.startsWith(u8, arg, "-")) {
61 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
62 const stdout = std.io.getStdOut().writer();
63 try stdout.writeAll(usage_fmt);
64 return process.cleanExit();
65 } else if (mem.eql(u8, arg, "--color")) {
66 if (i + 1 >= args.len) {
67 fatal("expected [auto|on|off] after --color", .{});
68 }
69 i += 1;
70 const next_arg = args[i];
71 color = std.meta.stringToEnum(Color, next_arg) orelse {
72 fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
73 };
74 } else if (mem.eql(u8, arg, "--stdin")) {
75 stdin_flag = true;
76 } else if (mem.eql(u8, arg, "--check")) {
77 check_flag = true;
78 } else if (mem.eql(u8, arg, "--ast-check")) {
79 check_ast_flag = true;
80 } else if (mem.eql(u8, arg, "--exclude")) {
81 if (i + 1 >= args.len) {
82 fatal("expected parameter after --exclude", .{});
83 }
84 i += 1;
85 const next_arg = args[i];
86 try excluded_files.append(next_arg);
87 } else {
88 fatal("unrecognized parameter: '{s}'", .{arg});
89 }
90 } else {
91 try input_files.append(arg);
92 }
93 }
94 }
95
96 if (stdin_flag) {
97 if (input_files.items.len != 0) {
98 fatal("cannot use --stdin with positional arguments", .{});
99 }
100
101 const stdin = std.io.getStdIn();
102 const source_code = std.zig.readSourceFileToEndAlloc(gpa, stdin, null) catch |err| {
103 fatal("unable to read stdin: {}", .{err});
104 };
105 defer gpa.free(source_code);
106
107 var tree = std.zig.Ast.parse(gpa, source_code, .zig) catch |err| {
108 fatal("error parsing stdin: {}", .{err});
109 };
110 defer tree.deinit(gpa);
111
112 if (check_ast_flag) {
113 var zir = try std.zig.AstGen.generate(gpa, tree);
114
115 if (zir.hasCompileErrors()) {
116 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
117 try wip_errors.init(gpa);
118 defer wip_errors.deinit();
119 try wip_errors.addZirErrorMessages(zir, tree, source_code, "<stdin>");
120 var error_bundle = try wip_errors.toOwnedBundle("");
121 defer error_bundle.deinit(gpa);
122 error_bundle.renderToStdErr(color.renderOptions());
123 process.exit(2);
124 }
125 } else if (tree.errors.len != 0) {
126 try std.zig.printAstErrorsToStderr(gpa, tree, "<stdin>", color);
127 process.exit(2);
128 }
129 const formatted = try tree.render(gpa);
130 defer gpa.free(formatted);
131
132 if (check_flag) {
133 const code: u8 = @intFromBool(mem.eql(u8, formatted, source_code));
134 process.exit(code);
135 }
136
137 return std.io.getStdOut().writeAll(formatted);
138 }
139
140 if (input_files.items.len == 0) {
141 fatal("expected at least one source file argument", .{});
142 }
143
144 var fmt = Fmt{
145 .gpa = gpa,
146 .arena = arena,
147 .seen = Fmt.SeenMap.init(gpa),
148 .any_error = false,
149 .check_ast = check_ast_flag,
150 .color = color,
151 .out_buffer = std.ArrayList(u8).init(gpa),
152 };
153 defer fmt.seen.deinit();
154 defer fmt.out_buffer.deinit();
155
156 // Mark any excluded files/directories as already seen,
157 // so that they are skipped later during actual processing
158 for (excluded_files.items) |file_path| {
159 const stat = fs.cwd().statFile(file_path) catch |err| switch (err) {
160 error.FileNotFound => continue,
161 // On Windows, statFile does not work for directories
162 error.IsDir => dir: {
163 var dir = try fs.cwd().openDir(file_path, .{});
164 defer dir.close();
165 break :dir try dir.stat();
166 },
167 else => |e| return e,
168 };
169 try fmt.seen.put(stat.inode, {});
170 }
171
172 for (input_files.items) |file_path| {
173 try fmtPath(&fmt, file_path, check_flag, fs.cwd(), file_path);
174 }
175 if (fmt.any_error) {
176 process.exit(1);
177 }
178}
179
180const FmtError = error{
181 SystemResources,
182 OperationAborted,
183 IoPending,
184 BrokenPipe,
185 Unexpected,
186 WouldBlock,
187 Canceled,
188 FileClosed,
189 DestinationAddressRequired,
190 DiskQuota,
191 FileTooBig,
192 InputOutput,
193 NoSpaceLeft,
194 AccessDenied,
195 OutOfMemory,
196 RenameAcrossMountPoints,
197 ReadOnlyFileSystem,
198 LinkQuotaExceeded,
199 FileBusy,
200 EndOfStream,
201 Unseekable,
202 NotOpenForWriting,
203 UnsupportedEncoding,
204 ConnectionResetByPeer,
205 SocketNotConnected,
206 LockViolation,
207 NetNameDeleted,
208 InvalidArgument,
209 ProcessNotFound,
210} || fs.File.OpenError;
211
212fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
213 fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
214 error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
215 else => {
216 std.log.err("unable to format '{s}': {s}", .{ file_path, @errorName(err) });
217 fmt.any_error = true;
218 return;
219 },
220 };
221}
222
223fn fmtPathDir(
224 fmt: *Fmt,
225 file_path: []const u8,
226 check_mode: bool,
227 parent_dir: fs.Dir,
228 parent_sub_path: []const u8,
229) FmtError!void {
230 var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
231 defer dir.close();
232
233 const stat = try dir.stat();
234 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
235
236 var dir_it = dir.iterate();
237 while (try dir_it.next()) |entry| {
238 const is_dir = entry.kind == .directory;
239
240 if (mem.startsWith(u8, entry.name, ".")) continue;
241
242 if (is_dir or entry.kind == .file and (mem.endsWith(u8, entry.name, ".zig") or mem.endsWith(u8, entry.name, ".zon"))) {
243 const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
244 defer fmt.gpa.free(full_path);
245
246 if (is_dir) {
247 try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);
248 } else {
249 fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {
250 std.log.err("unable to format '{s}': {s}", .{ full_path, @errorName(err) });
251 fmt.any_error = true;
252 return;
253 };
254 }
255 }
256 }
257}
258
259fn fmtPathFile(
260 fmt: *Fmt,
261 file_path: []const u8,
262 check_mode: bool,
263 dir: fs.Dir,
264 sub_path: []const u8,
265) FmtError!void {
266 const source_file = try dir.openFile(sub_path, .{});
267 var file_closed = false;
268 errdefer if (!file_closed) source_file.close();
269
270 const stat = try source_file.stat();
271
272 if (stat.kind == .directory)
273 return error.IsDir;
274
275 const gpa = fmt.gpa;
276 const source_code = try std.zig.readSourceFileToEndAlloc(
277 gpa,
278 source_file,
279 std.math.cast(usize, stat.size) orelse return error.FileTooBig,
280 );
281 defer gpa.free(source_code);
282
283 source_file.close();
284 file_closed = true;
285
286 // Add to set after no longer possible to get error.IsDir.
287 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
288
289 var tree = try std.zig.Ast.parse(gpa, source_code, .zig);
290 defer tree.deinit(gpa);
291
292 if (tree.errors.len != 0) {
293 try std.zig.printAstErrorsToStderr(gpa, tree, file_path, fmt.color);
294 fmt.any_error = true;
295 return;
296 }
297
298 if (fmt.check_ast) {
299 if (stat.size > std.zig.max_src_size)
300 return error.FileTooBig;
301
302 var zir = try std.zig.AstGen.generate(gpa, tree);
303 defer zir.deinit(gpa);
304
305 if (zir.hasCompileErrors()) {
306 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
307 try wip_errors.init(gpa);
308 defer wip_errors.deinit();
309 try wip_errors.addZirErrorMessages(zir, tree, source_code, file_path);
310 var error_bundle = try wip_errors.toOwnedBundle("");
311 defer error_bundle.deinit(gpa);
312 error_bundle.renderToStdErr(fmt.color.renderOptions());
313 fmt.any_error = true;
314 }
315 }
316
317 // As a heuristic, we make enough capacity for the same as the input source.
318 fmt.out_buffer.shrinkRetainingCapacity(0);
319 try fmt.out_buffer.ensureTotalCapacity(source_code.len);
320
321 try tree.renderToArrayList(&fmt.out_buffer, .{});
322 if (mem.eql(u8, fmt.out_buffer.items, source_code))
323 return;
324
325 if (check_mode) {
326 const stdout = std.io.getStdOut().writer();
327 try stdout.print("{s}\n", .{file_path});
328 fmt.any_error = true;
329 } else {
330 var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
331 defer af.deinit();
332
333 try af.file.writeAll(fmt.out_buffer.items);
334 try af.finish();
335 const stdout = std.io.getStdOut().writer();
336 try stdout.print("{s}\n", .{file_path});
337 }
338}
339
340fn fatal(comptime format: []const u8, args: anytype) noreturn {
341 std.log.err(format, args);
342 process.exit(1);
343}
src/fmt.zig created+336
...@@ -0,0 +1,336 @@
1const usage_fmt =
2 \\Usage: zig fmt [file]...
3 \\
4 \\ Formats the input files and modifies them in-place.
5 \\ Arguments can be files or directories, which are searched
6 \\ recursively.
7 \\
8 \\Options:
9 \\ -h, --help Print this help and exit
10 \\ --color [auto|off|on] Enable or disable colored error messages
11 \\ --stdin Format code from stdin; output to stdout
12 \\ --check List non-conforming files and exit with an error
13 \\ if the list is non-empty
14 \\ --ast-check Run zig ast-check on every file
15 \\ --exclude [file] Exclude file or directory from formatting
16 \\
17 \\
18;
19
20const Fmt = struct {
21 seen: SeenMap,
22 any_error: bool,
23 check_ast: bool,
24 color: Color,
25 gpa: Allocator,
26 arena: Allocator,
27 out_buffer: std.ArrayList(u8),
28
29 const SeenMap = std.AutoHashMap(fs.File.INode, void);
30};
31
32pub fn run(
33 gpa: Allocator,
34 arena: Allocator,
35 args: []const []const u8,
36) !void {
37 var color: Color = .auto;
38 var stdin_flag: bool = false;
39 var check_flag: bool = false;
40 var check_ast_flag: bool = false;
41 var input_files = std.ArrayList([]const u8).init(gpa);
42 defer input_files.deinit();
43 var excluded_files = std.ArrayList([]const u8).init(gpa);
44 defer excluded_files.deinit();
45
46 {
47 var i: usize = 0;
48 while (i < args.len) : (i += 1) {
49 const arg = args[i];
50 if (mem.startsWith(u8, arg, "-")) {
51 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
52 const stdout = std.io.getStdOut().writer();
53 try stdout.writeAll(usage_fmt);
54 return process.cleanExit();
55 } else if (mem.eql(u8, arg, "--color")) {
56 if (i + 1 >= args.len) {
57 fatal("expected [auto|on|off] after --color", .{});
58 }
59 i += 1;
60 const next_arg = args[i];
61 color = std.meta.stringToEnum(Color, next_arg) orelse {
62 fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
63 };
64 } else if (mem.eql(u8, arg, "--stdin")) {
65 stdin_flag = true;
66 } else if (mem.eql(u8, arg, "--check")) {
67 check_flag = true;
68 } else if (mem.eql(u8, arg, "--ast-check")) {
69 check_ast_flag = true;
70 } else if (mem.eql(u8, arg, "--exclude")) {
71 if (i + 1 >= args.len) {
72 fatal("expected parameter after --exclude", .{});
73 }
74 i += 1;
75 const next_arg = args[i];
76 try excluded_files.append(next_arg);
77 } else {
78 fatal("unrecognized parameter: '{s}'", .{arg});
79 }
80 } else {
81 try input_files.append(arg);
82 }
83 }
84 }
85
86 if (stdin_flag) {
87 if (input_files.items.len != 0) {
88 fatal("cannot use --stdin with positional arguments", .{});
89 }
90
91 const stdin = std.io.getStdIn();
92 const source_code = std.zig.readSourceFileToEndAlloc(gpa, stdin, null) catch |err| {
93 fatal("unable to read stdin: {}", .{err});
94 };
95 defer gpa.free(source_code);
96
97 var tree = std.zig.Ast.parse(gpa, source_code, .zig) catch |err| {
98 fatal("error parsing stdin: {}", .{err});
99 };
100 defer tree.deinit(gpa);
101
102 if (check_ast_flag) {
103 var zir = try std.zig.AstGen.generate(gpa, tree);
104
105 if (zir.hasCompileErrors()) {
106 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
107 try wip_errors.init(gpa);
108 defer wip_errors.deinit();
109 try wip_errors.addZirErrorMessages(zir, tree, source_code, "<stdin>");
110 var error_bundle = try wip_errors.toOwnedBundle("");
111 defer error_bundle.deinit(gpa);
112 error_bundle.renderToStdErr(color.renderOptions());
113 process.exit(2);
114 }
115 } else if (tree.errors.len != 0) {
116 try std.zig.printAstErrorsToStderr(gpa, tree, "<stdin>", color);
117 process.exit(2);
118 }
119 const formatted = try tree.render(gpa);
120 defer gpa.free(formatted);
121
122 if (check_flag) {
123 const code: u8 = @intFromBool(mem.eql(u8, formatted, source_code));
124 process.exit(code);
125 }
126
127 return std.io.getStdOut().writeAll(formatted);
128 }
129
130 if (input_files.items.len == 0) {
131 fatal("expected at least one source file argument", .{});
132 }
133
134 var fmt = Fmt{
135 .gpa = gpa,
136 .arena = arena,
137 .seen = Fmt.SeenMap.init(gpa),
138 .any_error = false,
139 .check_ast = check_ast_flag,
140 .color = color,
141 .out_buffer = std.ArrayList(u8).init(gpa),
142 };
143 defer fmt.seen.deinit();
144 defer fmt.out_buffer.deinit();
145
146 // Mark any excluded files/directories as already seen,
147 // so that they are skipped later during actual processing
148 for (excluded_files.items) |file_path| {
149 const stat = fs.cwd().statFile(file_path) catch |err| switch (err) {
150 error.FileNotFound => continue,
151 // On Windows, statFile does not work for directories
152 error.IsDir => dir: {
153 var dir = try fs.cwd().openDir(file_path, .{});
154 defer dir.close();
155 break :dir try dir.stat();
156 },
157 else => |e| return e,
158 };
159 try fmt.seen.put(stat.inode, {});
160 }
161
162 for (input_files.items) |file_path| {
163 try fmtPath(&fmt, file_path, check_flag, fs.cwd(), file_path);
164 }
165 if (fmt.any_error) {
166 process.exit(1);
167 }
168}
169
170const FmtError = error{
171 SystemResources,
172 OperationAborted,
173 IoPending,
174 BrokenPipe,
175 Unexpected,
176 WouldBlock,
177 Canceled,
178 FileClosed,
179 DestinationAddressRequired,
180 DiskQuota,
181 FileTooBig,
182 InputOutput,
183 NoSpaceLeft,
184 AccessDenied,
185 OutOfMemory,
186 RenameAcrossMountPoints,
187 ReadOnlyFileSystem,
188 LinkQuotaExceeded,
189 FileBusy,
190 EndOfStream,
191 Unseekable,
192 NotOpenForWriting,
193 UnsupportedEncoding,
194 ConnectionResetByPeer,
195 SocketNotConnected,
196 LockViolation,
197 NetNameDeleted,
198 InvalidArgument,
199 ProcessNotFound,
200} || fs.File.OpenError;
201
202fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
203 fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
204 error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
205 else => {
206 std.log.err("unable to format '{s}': {s}", .{ file_path, @errorName(err) });
207 fmt.any_error = true;
208 return;
209 },
210 };
211}
212
213fn fmtPathDir(
214 fmt: *Fmt,
215 file_path: []const u8,
216 check_mode: bool,
217 parent_dir: fs.Dir,
218 parent_sub_path: []const u8,
219) FmtError!void {
220 var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
221 defer dir.close();
222
223 const stat = try dir.stat();
224 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
225
226 var dir_it = dir.iterate();
227 while (try dir_it.next()) |entry| {
228 const is_dir = entry.kind == .directory;
229
230 if (mem.startsWith(u8, entry.name, ".")) continue;
231
232 if (is_dir or entry.kind == .file and (mem.endsWith(u8, entry.name, ".zig") or mem.endsWith(u8, entry.name, ".zon"))) {
233 const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
234 defer fmt.gpa.free(full_path);
235
236 if (is_dir) {
237 try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);
238 } else {
239 fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {
240 std.log.err("unable to format '{s}': {s}", .{ full_path, @errorName(err) });
241 fmt.any_error = true;
242 return;
243 };
244 }
245 }
246 }
247}
248
249fn fmtPathFile(
250 fmt: *Fmt,
251 file_path: []const u8,
252 check_mode: bool,
253 dir: fs.Dir,
254 sub_path: []const u8,
255) FmtError!void {
256 const source_file = try dir.openFile(sub_path, .{});
257 var file_closed = false;
258 errdefer if (!file_closed) source_file.close();
259
260 const stat = try source_file.stat();
261
262 if (stat.kind == .directory)
263 return error.IsDir;
264
265 const gpa = fmt.gpa;
266 const source_code = try std.zig.readSourceFileToEndAlloc(
267 gpa,
268 source_file,
269 std.math.cast(usize, stat.size) orelse return error.FileTooBig,
270 );
271 defer gpa.free(source_code);
272
273 source_file.close();
274 file_closed = true;
275
276 // Add to set after no longer possible to get error.IsDir.
277 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
278
279 var tree = try std.zig.Ast.parse(gpa, source_code, .zig);
280 defer tree.deinit(gpa);
281
282 if (tree.errors.len != 0) {
283 try std.zig.printAstErrorsToStderr(gpa, tree, file_path, fmt.color);
284 fmt.any_error = true;
285 return;
286 }
287
288 if (fmt.check_ast) {
289 if (stat.size > std.zig.max_src_size)
290 return error.FileTooBig;
291
292 var zir = try std.zig.AstGen.generate(gpa, tree);
293 defer zir.deinit(gpa);
294
295 if (zir.hasCompileErrors()) {
296 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
297 try wip_errors.init(gpa);
298 defer wip_errors.deinit();
299 try wip_errors.addZirErrorMessages(zir, tree, source_code, file_path);
300 var error_bundle = try wip_errors.toOwnedBundle("");
301 defer error_bundle.deinit(gpa);
302 error_bundle.renderToStdErr(fmt.color.renderOptions());
303 fmt.any_error = true;
304 }
305 }
306
307 // As a heuristic, we make enough capacity for the same as the input source.
308 fmt.out_buffer.shrinkRetainingCapacity(0);
309 try fmt.out_buffer.ensureTotalCapacity(source_code.len);
310
311 try tree.renderToArrayList(&fmt.out_buffer, .{});
312 if (mem.eql(u8, fmt.out_buffer.items, source_code))
313 return;
314
315 if (check_mode) {
316 const stdout = std.io.getStdOut().writer();
317 try stdout.print("{s}\n", .{file_path});
318 fmt.any_error = true;
319 } else {
320 var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
321 defer af.deinit();
322
323 try af.file.writeAll(fmt.out_buffer.items);
324 try af.finish();
325 const stdout = std.io.getStdOut().writer();
326 try stdout.print("{s}\n", .{file_path});
327 }
328}
329
330const std = @import("std");
331const mem = std.mem;
332const fs = std.fs;
333const process = std.process;
334const Allocator = std.mem.Allocator;
335const Color = std.zig.Color;
336const fatal = std.process.fatal;
src/main.zig+1-4
...@@ -309,10 +309,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -309,10 +309,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
309 .server = use_server,309 .server = use_server,
310 });310 });
311 } else if (mem.eql(u8, cmd, "fmt")) {311 } else if (mem.eql(u8, cmd, "fmt")) {
312 return jitCmd(gpa, arena, cmd_args, .{312 return @import("fmt.zig").run(gpa, arena, cmd_args);
313 .cmd_name = "fmt",
314 .root_src_path = "fmt.zig",
315 });
316 } else if (mem.eql(u8, cmd, "objcopy")) {313 } else if (mem.eql(u8, cmd, "objcopy")) {
317 return jitCmd(gpa, arena, cmd_args, .{314 return jitCmd(gpa, arena, cmd_args, .{
318 .cmd_name = "objcopy",315 .cmd_name = "objcopy",