Improve command line style

Parse the command line following the code from the Zig compiler cli.

Use the args iterator instead of slice, and use while instead of for
loop.

Use the new std.mem.cutPrefix instead of the custom function prefix.

Move Context struct to the top.
This commit is contained in:
Manlio Perillo
2026-06-06 17:39:42 +02:00
parent 6aaf048935
commit 72a441a6bd

View File

@@ -21,6 +21,7 @@ const builtin = @import("builtin");
const Process = std.process; const Process = std.process;
const print = std.debug.print; const print = std.debug.print;
const cutPrefix = std.mem.cutPrefix;
const progress_filename = ".progress.txt"; const progress_filename = ".progress.txt";
@@ -102,6 +103,16 @@ pub const Exercise = struct {
} }
}; };
// Shared, read-only run context threaded through the helpers.
const Context = struct {
io: std.Io,
arena: std.mem.Allocator,
zig_exe: []const u8,
work_path: []const u8,
};
const Error = error{Failed};
// Ansi colors. // Ansi colors.
var use_color_escapes = false; var use_color_escapes = false;
var red_text: []const u8 = ""; var red_text: []const u8 = "";
@@ -138,7 +149,8 @@ pub fn main(init: std.process.Init) !void {
const io = init.io; const io = init.io;
const arena = init.arena.allocator(); const arena = init.arena.allocator();
const args = try init.minimal.args.toSlice(arena); var args_it = try init.minimal.args.iterateAllocator(arena);
if (!args_it.skip()) @panic("expected self arg");
setupColors(io); setupColors(io);
@@ -150,22 +162,21 @@ pub fn main(init: std.process.Init) !void {
var only_n: ?usize = null; var only_n: ?usize = null;
var start_n: ?usize = null; var start_n: ?usize = null;
for (1..args.len) |n| { while (args_it.next()) |arg| {
const arg = args[n];
if (std.mem.eql(u8, arg, "--logo")) { if (std.mem.eql(u8, arg, "--logo")) {
print("{s}{s}{s}", .{ yellow_text, logo, reset_text }); print("{s}{s}{s}", .{ yellow_text, logo, reset_text });
return; return;
} else if (prefix(arg, "--zig=")) |v| { } else if (cutPrefix(u8, arg, "--zig=")) |v| {
zig_exe = v; zig_exe = v;
} else if (prefix(arg, "--work-path=")) |v| { } else if (cutPrefix(u8, arg, "--work-path=")) |v| {
work_path = v; work_path = v;
} else if (prefix(arg, "--only=")) |v| { } else if (cutPrefix(u8, arg, "--only=")) |v| {
only_n = std.fmt.parseInt(usize, v, 10) catch { only_n = std.fmt.parseInt(usize, v, 10) catch {
print("invalid --only value: {s}\n", .{v}); print("invalid --only value: {s}\n", .{v});
std.process.exit(1); std.process.exit(1);
}; };
mode = .named; mode = .named;
} else if (prefix(arg, "--start=")) |v| { } else if (cutPrefix(u8, arg, "--start=")) |v| {
start_n = std.fmt.parseInt(usize, v, 10) catch { start_n = std.fmt.parseInt(usize, v, 10) catch {
print("invalid --start value: {s}\n", .{v}); print("invalid --start value: {s}\n", .{v});
std.process.exit(1); std.process.exit(1);
@@ -181,7 +192,12 @@ pub fn main(init: std.process.Init) !void {
print("{s}", .{logo}); print("{s}", .{logo});
const ctx: Context = .{ .io = io, .arena = arena, .zig_exe = zig_exe, .work_path = work_path }; const ctx: Context = .{
.io = io,
.arena = arena,
.zig_exe = zig_exe,
.work_path = work_path,
};
switch (mode) { switch (mode) {
.named => { .named => {
@@ -230,21 +246,6 @@ pub fn main(init: std.process.Init) !void {
} }
} }
fn prefix(arg: []const u8, pre: []const u8) ?[]const u8 {
if (std.mem.startsWith(u8, arg, pre)) return arg[pre.len..];
return null;
}
// Shared, read-only run context threaded through the helpers.
const Context = struct {
io: std.Io,
arena: std.mem.Allocator,
zig_exe: []const u8,
work_path: []const u8,
};
const Error = error{Failed};
// Iterates exercises from `start_index` to the end, stopping at the first failure. // Iterates exercises from `start_index` to the end, stopping at the first failure.
// Progress is written after each passed exercise. // Progress is written after each passed exercise.
fn iterateFrom(ctx: Context, start_index: usize) Error!void { fn iterateFrom(ctx: Context, start_index: usize) Error!void {