hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit d89bd967d0f7bce35282251d4e6de12a4e89209b
parent 46e3da37b31120d66cba2cdd1b450903c2469878
Author: Autumn! <autumnull@posteo.net>
Date:   Thu, 20 Apr 2023 20:31:35 +0000

getopt: document implicit -h in help text

Signed-off-by: Autumn! <autumnull@posteo.net>

Diffstat:
Mgetopt/getopts.ha | 90+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
1 file changed, 51 insertions(+), 39 deletions(-)

diff --git a/getopt/getopts.ha b/getopt/getopts.ha @@ -10,19 +10,11 @@ use io; use os; use strings; -// A flag which does not take a parameter, e.g. "-a". -export type flag = rune; - -// An option with an included parameter, e.g. "-a foo". -export type parameter = str; - -// A command line option. -export type option = (flag, parameter); - // The result of parsing the set of command line arguments, including any -// options specified and the list of non-option arguments. +// options specified and the list of non-option arguments. If a subcommand +// is present in the help passed to [[parse]], then there will be no args. export type command = struct { - opts: []option, + opts: [](rune, str), subcmd: (void | (str, *command)), args: []str, help: []help, @@ -33,11 +25,11 @@ export type command = struct { export type cmd_help = str; // Help text for a flag, formatted as "-a: help text". -export type flag_help = (flag, str); +export type flag_help = (rune, str); // Help text for a parameter, formatted as "-a param: help text" where "param" // is the first string and "help text" is the second string. -export type parameter_help = (flag, str, str); +export type parameter_help = (rune, str, str); // Definition of a named subcommand. export type subcmd_help = (str, []help); @@ -84,6 +76,7 @@ export fn parse(args: []str, help: help...) command = { case let s: unknown_subcmd => fmt::errorfln("{}: unrecognized subcommand: {}", cmd, s: str)!; printsubcmds(os::stderr, help)!; + fmt::errorln()!; }; printusage(os::stderr, args[0], help)!; os::exit(1); @@ -93,7 +86,7 @@ export fn parse(args: []str, help: help...) command = { // if an error occurs. The argument list must include the command name as // the first item; [[os::args]] fulfills this criteria. export fn tryparse(args: []str, help: help...) (command | ...error) = { - let opts: []option = []; + let opts: [](rune, str) = []; let i = 1z; for (i < len(args); i += 1) :arg { const arg = args[i]; @@ -186,22 +179,39 @@ export fn finish(cmd: *command) void = { }; }; +// Prints command usage to the provided stream. +export fn printusage( + out: io::handle, + name: str, + help: []help +) (void | io::error) = { + let h = contains_h(help); + let z = _printusage(io::empty, name, false, h, help)?; + _printusage(out, name, if (z > 72) true else false, h, help)?; +}; + fn _printusage( out: io::handle, name: str, indent: bool, + contains_h: bool, help: []help, ) (size | io::error) = { let z = fmt::fprint(out, "Usage:", name)?; let started_flags = false; - for (let i = 0z; i < len(help); i += 1) if (help[i] is flag_help) { + if (!contains_h) { + z += fmt::fprint(out, " [-h")?; + started_flags = true; + }; + for (let i = 0z; i < len(help); i += 1) match (help [i]) { + case let h: flag_help => if (!started_flags) { z += fmt::fprint(out, " [-")?; started_flags = true; }; - const help = help[i] as flag_help; - z += fmt::fprint(out, help.0: rune)?; + z += fmt::fprint(out, h.0)?; + case => void; }; if (started_flags) { z += fmt::fprint(out, "]")?; @@ -212,7 +222,7 @@ fn _printusage( if (indent) { z += fmt::fprintf(out, "\n\t")?; }; - z += fmt::fprintf(out, " [-{} <{}>]", help.0: rune, help.1)?; + z += fmt::fprintf(out, " [-{} <{}>]", help.0, help.1)?; }; let first_arg = true; for (let i = 1z; i < len(help); i += 1) if (help[i] is cmd_help) { @@ -228,14 +238,18 @@ fn _printusage( return z + fmt::fprint(out, "\n")?; }; -// Prints command usage to the provided stream. -export fn printusage( - out: io::handle, - name: str, - help: []help -) (void | io::error) = { - let z = _printusage(io::empty, name, false, help)?; - _printusage(out, name, if (z > 72) true else false, help)?; +fn contains_h(help: []help) bool = { + for (let i = 0z; i < len(help); i += 1) { + const r = match (help[i]) { + case let h: flag_help => yield h.0; + case let h: parameter_help => yield h.0; + case => continue; + }; + if (r == 'h') { + return true; + }; + }; + return false; }; // Prints command help to the provided stream. @@ -252,21 +266,19 @@ export fn printhelp( fmt::fprintfln(out, "{}: {}\n", name, help[0] as cmd_help: str)?; }; - printusage(out, name, help)?; + let contains_h = contains_h(help); + let z = _printusage(io::empty, name, false, contains_h, help)?; + _printusage(out, name, if (z > 72) true else false, contains_h, help)?; - for (let i = 0z; i < len(help); i += 1) match (help[i]) { - case (flag_help | parameter_help) => - // Only print this if there are flags to show - fmt::fprint(out, "\n")?; - break; - case => void; + fmt::fprint(out, "\n")?; + if (!contains_h) { + fmt::fprintln(out, "-h: print this help text")?; }; - for (let i = 0z; i < len(help); i += 1) match (help[i]) { case let f: flag_help => - fmt::fprintfln(out, "-{}: {}", f.0: rune, f.1)?; + fmt::fprintfln(out, "-{}: {}", f.0, f.1)?; case let p: parameter_help => - fmt::fprintfln(out, "-{} <{}>: {}", p.0: rune, p.1, p.2)?; + fmt::fprintfln(out, "-{} <{}>: {}", p.0, p.1, p.2)?; case => void; }; @@ -274,13 +286,13 @@ export fn printhelp( }; fn printsubcmds(out: io::handle, help: []help) (void | io::error) = { - let first_subcmd = true; + let first = true; for (let i = 0z; i < len(help); i += 1) match (help[i]) { case let s: subcmd_help => // Only print this if there are subcommands to show - if (first_subcmd) { + if (first) { fmt::fprintln(out, "\nSubcommands:")?; - first_subcmd = false; + first = false; }; if (len(s.1) == 0 || !(s.1[0] is cmd_help)) { fmt::fprintfln(out, " {}", s.0)?;