@@ -11,17 +11,19 @@ const command = @import("command.zig");
1111const help = @import ("./help.zig" );
1212
1313pub const AppRunner = struct {
14- // This arena and its allocator is intended to be used only for the value references
15- // that must be freed after the parsing is finished .
16- // For everything else the original allocator .
14+ // Arena allocator for temporary data during parsing (ValueRefs, argument slices, etc.)
15+ // that is freed immediately after parsing completes .
16+ // The original allocator is used for data that outlives the parsing phase .
1717 arena : ArenaAllocator ,
1818 orig_allocator : Allocator ,
19+ io : std.Io ,
1920
2021 const Self = @This ();
21- pub fn init (alloc : Allocator ) ! Self {
22+ pub fn init (io : std.Io , alloc : Allocator ) ! Self {
2223 return .{
2324 .arena = ArenaAllocator .init (alloc ),
2425 .orig_allocator = alloc ,
26+ .io = io ,
2527 };
2628 }
2729
@@ -57,19 +59,22 @@ pub const AppRunner = struct {
5759 const iter = try std .process .argsWithAllocator (self .arena .allocator ());
5860
5961 // Here we pass the child allocator because any values allocated on the client behalf may not be freed.
60- var cr = try Parser (std .process .ArgIterator ).init (app , iter , self .orig_allocator );
62+ var cr = try Parser (std .process .ArgIterator ).init (app , iter , self .io , self . orig_allocator );
6163 defer cr .deinit ();
6264
6365 if (cr .parse ()) | action | {
6466 self .deinit ();
6567 return action ;
6668 } else | err | {
67- processError (err , cr .error_data orelse unreachable , app );
69+ var buffer : [4096 ]u8 = undefined ;
70+ var w = std .Io .File .stderr ().writer (self .io , & buffer );
71+ var printer = Printer .init (& w );
72+ processError (& printer , err , cr .error_data orelse unreachable , app );
6873 if (app .help_config .print_help_on_error ) {
69- _ = std . fs . File . stdout (). write ( " \n " ) catch unreachable ;
70- try help .print_command_help (app , try cr .command_path .toOwnedSlice (self .orig_allocator ), cr .global_options );
74+ printer . printNewLine () ;
75+ try help .print_command_help (& printer , app , try cr .command_path .toOwnedSlice (self .orig_allocator ), cr .global_options );
7176 }
72- std .posix .exit (1 );
77+ std .process .exit (1 );
7378 }
7479 }
7580
@@ -83,21 +88,22 @@ pub const AppRunner = struct {
8388 }
8489};
8590
86- fn processError (err : parser.ParseError , err_data : parser.ErrorData , app : * const App ) void {
91+ fn processError (p : * Printer , err : parser.ParseError , err_data : parser.ErrorData , app : * const App ) void {
8792 switch (err ) {
88- error .UnknownOption = > printError (app , "unknown option '--{s}'" , .{err_data .provided_string }),
89- error .UnknownOptionAlias = > printError (app , "unknown option alias '-{c}'" , .{err_data .option_alias }),
90- error .UnknownSubcommand = > printError (app , "unknown subcommand '{s}'" , .{err_data .provided_string }),
91- error .MissingRequiredOption = > printError (app , "missing required option '--{s}'" , .{err_data .entity_name }),
92- error .MissingRequiredPositionalArgument = > printError (app , "missing required positional argument '{s}'" , .{err_data .entity_name }),
93- error .MissingSubcommand = > printError (app , "command '{s}' requires subcommand" , .{err_data .entity_name }),
94- error .MissingOptionValue = > printError (app , "option ('--{s}') requires value" , .{err_data .entity_name }),
95- error .UnexpectedPositionalArgument = > printError (app , "unexpected positional argument '{s}'" , .{err_data .provided_string }),
96- error .CommandDoesNotHavePositionalArguments = > printError (app , "command '{s}' does not have positional arguments" , .{err_data .entity_name }),
93+ error .UnknownOption = > printError (p , app , "unknown option '--{s}'" , .{err_data .provided_string }),
94+ error .UnknownOptionAlias = > printError (p , app , "unknown option alias '-{c}'" , .{err_data .option_alias }),
95+ error .UnknownSubcommand = > printError (p , app , "unknown subcommand '{s}'" , .{err_data .provided_string }),
96+ error .MissingRequiredOption = > printError (p , app , "missing required option '--{s}'" , .{err_data .entity_name }),
97+ error .MissingRequiredPositionalArgument = > printError (p , app , "missing required positional argument '{s}'" , .{err_data .entity_name }),
98+ error .MissingSubcommand = > printError (p , app , "command '{s}' requires subcommand" , .{err_data .entity_name }),
99+ error .MissingOptionValue = > printError (p , app , "option ('--{s}') requires value" , .{err_data .entity_name }),
100+ error .UnexpectedPositionalArgument = > printError (p , app , "unexpected positional argument '{s}'" , .{err_data .provided_string }),
101+ error .CommandDoesNotHavePositionalArguments = > printError (p , app , "command '{s}' does not have positional arguments" , .{err_data .entity_name }),
97102 error .InvalidValue = > {
98103 const iv = err_data .invalid_value ;
99104 if (iv .envvar ) | ev | {
100105 printError (
106+ p ,
101107 app ,
102108 "failed to parse '{s}' (read from envvar {s}) as the value for option '--{s}' which is of type {s}" ,
103109 .{ iv .provided_string , ev , iv .entity_name , iv .value_type },
@@ -106,27 +112,18 @@ fn processError(err: parser.ParseError, err_data: parser.ErrorData, app: *const
106112 const et = if (iv .entity_type == .option ) "option" else "positional argument" ;
107113 const px = if (iv .entity_type == .option ) "--" else "" ;
108114 printError (
115+ p ,
109116 app ,
110117 "failed to parse '{s}' as the value for {s} '{s}{s}' which is of type {s}" ,
111118 .{ iv .provided_string , et , px , iv .entity_name , iv .value_type },
112119 );
113120 }
114121 },
115- error .OutOfMemory = > printError (app , "out of memory" , .{}),
122+ error .OutOfMemory = > printError (p , app , "out of memory" , .{}),
116123 }
117124}
118125
119- pub fn printError (app : * const App , comptime fmt : []const u8 , args : anytype ) void {
120- var buf : [4096 ]u8 = undefined ;
121- var stderr = std .fs .File .stderr ();
122- var w = stderr .writer (& buf );
123- const use_color = switch (app .help_config .color_usage ) {
124- .always = > true ,
125- .never = > false ,
126- .auto = > std .posix .isatty (stderr .handle ),
127- };
128- var p = Printer .init (& w .interface , use_color );
129-
126+ pub fn printError (p : * Printer , app : * const App , comptime fmt : []const u8 , args : anytype ) void {
130127 p .printInColor (app .help_config .color_error , "ERROR" );
131128 p .format (": " , .{});
132129 p .format (fmt , args );
0 commit comments