@@ -278,10 +278,10 @@ gb_internal void usage(String argv0, String argv1 = {}) {
278
278
print_usage_line (1 , " One must contain the program's entry point, all must be in the same package." );
279
279
print_usage_line (1 , " run Same as 'build', but also then runs the newly compiled executable." );
280
280
print_usage_line (1 , " bundle Bundles a directory in a specific layout for that platform." );
281
- print_usage_line (1 , " check Parses, and type checks a directory of .odin files." );
281
+ print_usage_line (1 , " check Parses and type checks a directory of .odin files." );
282
282
print_usage_line (1 , " strip-semicolon Parses, type checks, and removes unneeded semicolons from the entire program." );
283
283
print_usage_line (1 , " test Builds and runs procedures with the attribute @(test) in the initial package." );
284
- print_usage_line (1 , " doc Generates documentation on a directory of .odin files." );
284
+ print_usage_line (1 , " doc Generates documentation from a directory of .odin files." );
285
285
print_usage_line (1 , " version Prints version." );
286
286
print_usage_line (1 , " report Prints information useful to reporting a bug." );
287
287
print_usage_line (1 , " root Prints the root path where Odin looks for the builtin collections." );
@@ -2221,20 +2221,30 @@ gb_internal void remove_temp_files(lbGenerator *gen) {
2221
2221
}
2222
2222
2223
2223
2224
- gb_internal void print_show_help (String const arg0, String command, String optional_flag = {}) {
2224
+ gb_internal int print_show_help (String const arg0, String command, String optional_flag = {}) {
2225
+ bool help_resolved = false ;
2226
+ bool printed_usage_header = false ;
2227
+ bool printed_flags_header = false ;
2228
+
2225
2229
if (command == " help" && optional_flag.len != 0 && optional_flag[0 ] != ' -' ) {
2226
2230
command = optional_flag;
2227
2231
optional_flag = {};
2228
2232
}
2229
2233
2230
- print_usage_line (0 , " %.*s is a tool for managing Odin source code." , LIT (arg0));
2231
- print_usage_line (0 , " Usage:" );
2232
- print_usage_line (1 , " %.*s %.*s [arguments]" , LIT (arg0), LIT (command));
2233
- print_usage_line (0 , " " );
2234
- defer (print_usage_line (0 , " " ));
2235
-
2234
+ auto const print_usage_header_once = [&help_resolved, &printed_usage_header, arg0, command]() {
2235
+ if (printed_usage_header) {
2236
+ return ;
2237
+ }
2238
+ print_usage_line (0 , " %.*s is a tool for managing Odin source code." , LIT (arg0));
2239
+ print_usage_line (0 , " Usage:" );
2240
+ print_usage_line (1 , " %.*s %.*s [arguments]" , LIT (arg0), LIT (command));
2241
+ print_usage_line (0 , " " );
2242
+ help_resolved = true ;
2243
+ printed_usage_header = true ;
2244
+ };
2236
2245
2237
2246
if (command == " build" ) {
2247
+ print_usage_header_once ();
2238
2248
print_usage_line (1 , " build Compiles directory of .odin files as an executable." );
2239
2249
print_usage_line (2 , " One must contain the program's entry point, all must be in the same package." );
2240
2250
print_usage_line (2 , " Use `-file` to build a single file instead." );
@@ -2243,35 +2253,48 @@ gb_internal void print_show_help(String const arg0, String command, String optio
2243
2253
print_usage_line (3 , " odin build <dir> Builds package in <dir>." );
2244
2254
print_usage_line (3 , " odin build filename.odin -file Builds single-file package, must contain entry point." );
2245
2255
} else if (command == " run" ) {
2256
+ print_usage_header_once ();
2246
2257
print_usage_line (1 , " run Same as 'build', but also then runs the newly compiled executable." );
2247
2258
print_usage_line (2 , " Append an empty flag and then the args, '-- <args>', to specify args for the output." );
2248
2259
print_usage_line (2 , " Examples:" );
2249
2260
print_usage_line (3 , " odin run . Builds and runs package in current directory." );
2250
2261
print_usage_line (3 , " odin run <dir> Builds and runs package in <dir>." );
2251
2262
print_usage_line (3 , " odin run filename.odin -file Builds and runs single-file package, must contain entry point." );
2252
2263
} else if (command == " check" ) {
2264
+ print_usage_header_once ();
2253
2265
print_usage_line (1 , " check Parses and type checks directory of .odin files." );
2254
2266
print_usage_line (2 , " Examples:" );
2255
2267
print_usage_line (3 , " odin check . Type checks package in current directory." );
2256
2268
print_usage_line (3 , " odin check <dir> Type checks package in <dir>." );
2257
2269
print_usage_line (3 , " odin check filename.odin -file Type checks single-file package, must contain entry point." );
2258
2270
} else if (command == " test" ) {
2271
+ print_usage_header_once ();
2259
2272
print_usage_line (1 , " test Builds and runs procedures with the attribute @(test) in the initial package." );
2260
2273
} else if (command == " doc" ) {
2274
+ print_usage_header_once ();
2261
2275
print_usage_line (1 , " doc Generates documentation from a directory of .odin files." );
2262
2276
print_usage_line (2 , " Examples:" );
2263
2277
print_usage_line (3 , " odin doc . Generates documentation on package in current directory." );
2264
2278
print_usage_line (3 , " odin doc <dir> Generates documentation on package in <dir>." );
2265
2279
print_usage_line (3 , " odin doc filename.odin -file Generates documentation on single-file package." );
2266
2280
} else if (command == " version" ) {
2281
+ print_usage_header_once ();
2267
2282
print_usage_line (1 , " version Prints version." );
2268
2283
} else if (command == " strip-semicolon" ) {
2284
+ print_usage_header_once ();
2269
2285
print_usage_line (1 , " strip-semicolon" );
2270
2286
print_usage_line (2 , " Parses and type checks .odin file(s) and then removes unneeded semicolons from the entire project." );
2271
2287
} else if (command == " bundle" ) {
2288
+ print_usage_header_once ();
2272
2289
print_usage_line (1 , " bundle <platform> Bundles a directory in a specific layout for that platform" );
2273
2290
print_usage_line (2 , " Supported platforms:" );
2274
2291
print_usage_line (3 , " android" );
2292
+ } else if (command == " report" ) {
2293
+ print_usage_header_once ();
2294
+ print_usage_line (1 , " report Prints information useful to reporting a bug." );
2295
+ } else if (command == " root" ) {
2296
+ print_usage_header_once ();
2297
+ print_usage_line (1 , " root Prints the root path where Odin looks for the builtin collections." );
2275
2298
}
2276
2299
2277
2300
bool doc = command == " doc" ;
@@ -2293,13 +2316,10 @@ gb_internal void print_show_help(String const arg0, String command, String optio
2293
2316
check = true ;
2294
2317
}
2295
2318
2296
- print_usage_line (0 , " " );
2297
- print_usage_line (1 , " Flags" );
2298
- print_usage_line (0 , " " );
2299
2319
2300
2320
2301
2321
2302
- auto const print_flag = [&optional_flag](char const *flag) -> bool {
2322
+ auto const print_flag = [&optional_flag, &help_resolved, &printed_flags_header, print_usage_header_once ](char const *flag) -> bool {
2303
2323
if (optional_flag.len != 0 ) {
2304
2324
String f = make_string_c (flag);
2305
2325
isize i = string_index_byte (f, ' :' );
@@ -2310,6 +2330,14 @@ gb_internal void print_show_help(String const arg0, String command, String optio
2310
2330
return false ;
2311
2331
}
2312
2332
}
2333
+ print_usage_header_once ();
2334
+ if (!printed_flags_header) {
2335
+ print_usage_line (0 , " " );
2336
+ print_usage_line (1 , " Flags" );
2337
+ print_usage_line (0 , " " );
2338
+ printed_flags_header = true ;
2339
+ }
2340
+ help_resolved = true ;
2313
2341
print_usage_line (0 , " " );
2314
2342
print_usage_line (1 , flag);
2315
2343
return true ;
@@ -2867,6 +2895,21 @@ gb_internal void print_show_help(String const arg0, String command, String optio
2867
2895
print_usage_line (2 , " If this is omitted, the terminal will prompt you to provide it." );
2868
2896
}
2869
2897
}
2898
+
2899
+ if (!help_resolved) {
2900
+ usage (arg0);
2901
+ print_usage_line (0 , " " );
2902
+ if (command == " help" ) {
2903
+ print_usage_line (0 , " '%.*s' is not a recognized flag." , LIT (optional_flag));
2904
+ } else {
2905
+ print_usage_line (0 , " '%.*s' is not a recognized command." , LIT (command));
2906
+ }
2907
+ return 1 ;
2908
+ }
2909
+
2910
+ print_usage_line (0 , " " );
2911
+
2912
+ return 0 ;
2870
2913
}
2871
2914
2872
2915
gb_internal void print_show_unused (Checker *c) {
@@ -3239,6 +3282,16 @@ int main(int arg_count, char const **arg_ptr) {
3239
3282
String run_args_string = {};
3240
3283
isize last_non_run_arg = args.count ;
3241
3284
3285
+ for_array (i, args) {
3286
+ if (args[i] == " --" ) {
3287
+ break ;
3288
+ }
3289
+ if (args[i] == " -help" || args[i] == " --help" ) {
3290
+ build_context.show_help = true ;
3291
+ return print_show_help (args[0 ], command);
3292
+ }
3293
+ }
3294
+
3242
3295
bool run_output = false ;
3243
3296
if (command == " run" || command == " test" ) {
3244
3297
if (args.count < 3 ) {
@@ -3332,6 +3385,10 @@ int main(int arg_count, char const **arg_ptr) {
3332
3385
return 1;
3333
3386
#endif
3334
3387
} else if (command == " version" ) {
3388
+ if (args.count != 2 ) {
3389
+ usage (args[0 ]);
3390
+ return 1 ;
3391
+ }
3335
3392
build_context.command_kind = Command_version;
3336
3393
gb_printf (" %.*s version %.*s" , LIT (args[0 ]), LIT (ODIN_VERSION));
3337
3394
@@ -3346,6 +3403,10 @@ int main(int arg_count, char const **arg_ptr) {
3346
3403
gb_printf (" \n " );
3347
3404
return 0 ;
3348
3405
} else if (command == " report" ) {
3406
+ if (args.count != 2 ) {
3407
+ usage (args[0 ]);
3408
+ return 1 ;
3409
+ }
3349
3410
build_context.command_kind = Command_bug_report;
3350
3411
print_bug_report_help ();
3351
3412
return 0 ;
@@ -3354,8 +3415,7 @@ int main(int arg_count, char const **arg_ptr) {
3354
3415
usage (args[0 ]);
3355
3416
return 1 ;
3356
3417
} else {
3357
- print_show_help (args[0 ], args[1 ], args[2 ]);
3358
- return 0 ;
3418
+ return print_show_help (args[0 ], args[1 ], args[2 ]);
3359
3419
}
3360
3420
} else if (command == " bundle" ) {
3361
3421
if (args.count < 4 ) {
@@ -3371,6 +3431,10 @@ int main(int arg_count, char const **arg_ptr) {
3371
3431
}
3372
3432
init_filename = args[3 ];
3373
3433
} else if (command == " root" ) {
3434
+ if (args.count != 2 ) {
3435
+ usage (args[0 ]);
3436
+ return 1 ;
3437
+ }
3374
3438
gb_printf (" %.*s" , LIT (odin_root_dir ()));
3375
3439
return 0 ;
3376
3440
} else if (command == " clear-cache" ) {
@@ -3386,11 +3450,6 @@ int main(int arg_count, char const **arg_ptr) {
3386
3450
3387
3451
init_filename = copy_string (permanent_allocator (), init_filename);
3388
3452
3389
- if (init_filename == " -help" ||
3390
- init_filename == " --help" ) {
3391
- build_context.show_help = true ;
3392
- }
3393
-
3394
3453
if (init_filename.len > 0 && !build_context.show_help ) {
3395
3454
// The command must be build, run, test, check, or another that takes a directory or filename.
3396
3455
if (!path_is_directory (init_filename)) {
@@ -3441,8 +3500,7 @@ int main(int arg_count, char const **arg_ptr) {
3441
3500
}
3442
3501
3443
3502
if (build_context.show_help ) {
3444
- print_show_help (args[0 ], command);
3445
- return 0 ;
3503
+ return print_show_help (args[0 ], command);
3446
3504
}
3447
3505
3448
3506
if (command == " bundle" ) {
0 commit comments