Rename non-positional "arg"/"flag" to "option"

This commit is contained in:
Jan Van Bruggen 2022-10-08 01:37:09 -06:00
parent 3d5728d82c
commit a39fc076d3
No known key found for this signature in database
GPG Key ID: FE2A4E38E0FA6134
2 changed files with 162 additions and 162 deletions

View File

@ -10,7 +10,7 @@ main = Program.withArgs \args ->
Arg.succeed (\dividend -> \divisor -> Div (Num.toF64 dividend) (Num.toF64 divisor))
|> Arg.withParser
(
Arg.i64 {
Arg.i64Option {
long: "dividend",
short: "n",
help: "the number to divide; corresponds to a numerator",
@ -18,7 +18,7 @@ main = Program.withArgs \args ->
)
|> Arg.withParser
(
Arg.i64 {
Arg.i64Option {
long: "divisor",
short: "d",
help: "the number to divide by; corresponds to a denominator",
@ -30,7 +30,7 @@ main = Program.withArgs \args ->
Arg.succeed (\base -> \num -> Log (Num.toF64 base) (Num.toF64 num))
|> Arg.withParser
(
Arg.i64 {
Arg.i64Option {
long: "base",
short: "b",
help: "base of the logarithm",
@ -38,7 +38,7 @@ main = Program.withArgs \args ->
)
|> Arg.withParser
(
Arg.i64 {
Arg.i64Option {
long: "num",
help: "the number to take the logarithm of",
}

View File

@ -6,9 +6,9 @@ interface Arg
toHelp,
parseFormatted,
succeed,
bool,
str,
i64,
boolOption,
strOption,
i64Option,
positional,
subCommand,
choice,
@ -32,7 +32,7 @@ NamedParser a := {
## needs, consider transforming it into a [NamedParser].
Parser a := [
Succeed a,
Arg ArgConfig (MarkedArgs -> Result { newlyTaken : Taken, val : a } (ParseError [])),
Option OptionConfig (MarkedArgs -> Result { newlyTaken : Taken, val : a } (ParseError [])),
Positional PositionalConfig (MarkedArgs -> Result { newlyTaken : Taken, val : a } (ParseError [])),
# TODO: hiding the record behind an alias currently causes a panic
SubCommand
@ -59,15 +59,15 @@ MarkedArgs : { args : List Str, taken : Taken }
ParseError a : [
## The program name was not found as the first argument to be parsed.
ProgramNameNotProvided Str,
## An argument is required, but it was not found.
MissingRequiredArg Str,
## A positional argument is required, but it was not found.
MissingPositionalArg Str,
## An argument was found, but it didn't have the expected [Type].
WrongType
MissingPositional Str,
## An option argument is required, but it was not found.
MissingRequiredOption Str,
## An argument was found, but it didn't have the expected [OptionType].
WrongOptionType
{
arg : Str,
expected : Type,
expected : OptionType,
},
## A subcommand is required, but it was not found.
SubCommandNotFound
@ -82,9 +82,9 @@ ParseError a : [
},
]a
## Expected type of an argument, in an argument list being parsed.
## Describes how a string argument should be interpreted as a certain type.
Type : [
## Expected type of an option, in an argument list being parsed.
## Describes how a string option should be interpreted as a certain type.
OptionType : [
Str,
Bool,
I64,
@ -96,11 +96,11 @@ Help : [
Config (List Config),
]
ArgConfig : {
OptionConfig : {
long : Str,
short : Str,
help : Str,
type : Type,
type : OptionType,
}
PositionalConfig : {
@ -108,7 +108,7 @@ PositionalConfig : {
help : Str,
}
Config : [Arg ArgConfig, Positional PositionalConfig]
Config : [Option OptionConfig, Positional PositionalConfig]
## Generates help metadata from a [Parser].
##
@ -133,8 +133,8 @@ toHelpHelper = \@Parser parser, configs ->
WithConfig innerParser config ->
toHelpHelper innerParser (List.append configs config)
Arg config _ ->
List.append configs (Arg config)
Option config _ ->
List.append configs (Option config)
|> Config
SubCommand commands ->
@ -194,8 +194,8 @@ andMap = \@Parser parser, @Parser mapper ->
|> andMap (@Parser mapper)
|> WithConfig config
Arg config run ->
Arg config \args ->
Option config run ->
Option config \args ->
run args
|> Result.map (\{ val, newlyTaken } -> { val: fn val, newlyTaken })
@ -211,16 +211,16 @@ andMap = \@Parser parser, @Parser mapper ->
List.map cmds mapSubParser
|> SubCommand
Arg config run ->
Option config run ->
when parser is
Succeed a ->
Arg config \args ->
Option config \args ->
when run args is
Ok { val: fn, newlyTaken } -> Ok { val: fn a, newlyTaken }
Err err -> Err err
Lazy thunk ->
Arg config \args ->
Option config \args ->
when run args is
Ok { val: fn, newlyTaken } -> Ok { val: fn (thunk {}), newlyTaken }
Err err -> Err err
@ -230,9 +230,9 @@ andMap = \@Parser parser, @Parser mapper ->
|> andMap (@Parser mapper)
|> WithConfig config2
Arg config2 run2 ->
Option config2 run2 ->
# Parse first the one and then the other.
combinedParser = Arg config2 \args ->
combinedParser = Option config2 \args ->
when run args is
Ok { val: fn, newlyTaken } ->
run2 (updateTaken args newlyTaken)
@ -242,7 +242,7 @@ andMap = \@Parser parser, @Parser mapper ->
# Store the extra config.
@Parser combinedParser
|> WithConfig (Arg config)
|> WithConfig (Option config)
Positional config2 run2 ->
combinedParser = Positional config2 \args ->
@ -255,7 +255,7 @@ andMap = \@Parser parser, @Parser mapper ->
# Store the extra config.
@Parser combinedParser
|> WithConfig (Arg config)
|> WithConfig (Option config)
SubCommand cmds ->
# For each subcommand, first run the subcommand, then
@ -285,9 +285,9 @@ andMap = \@Parser parser, @Parser mapper ->
|> andMap (@Parser mapper)
|> WithConfig config2
Arg config2 run2 ->
Option config2 run2 ->
# Parse first the one and then the other.
combinedParser = Arg config2 \args ->
combinedParser = Option config2 \args ->
when run args is
Ok { val: fn, newlyTaken } ->
run2 (updateTaken args newlyTaken)
@ -336,8 +336,8 @@ andMap = \@Parser parser, @Parser mapper ->
|> andMap (@Parser mapper)
|> WithConfig config
Arg config run ->
Arg config \args ->
Option config run ->
Option config \args ->
run args
|> Result.map (\{ val, newlyTaken } -> { val: fn val, newlyTaken })
@ -399,7 +399,7 @@ parseHelp : Parser a, MarkedArgs -> Result a (ParseError [])
parseHelp = \@Parser parser, args ->
when parser is
Succeed val -> Ok val
Arg _ run ->
Option _ run ->
run args
|> Result.map .val
@ -444,51 +444,51 @@ nextUnmarked = \marked ->
help 0
## Creates a parser for a boolean flag argument.
## Flags of value "true" and "false" will be parsed as [Bool.true] and [Bool.false], respectively.
## All other values will result in a `WrongType` error.
bool : _ -> Parser Bool # TODO: panics if parameter annotation given
bool = \{ long, short ? "", help ? "" } ->
## Creates a parser for a boolean option argument.
## Options of value "true" and "false" will be parsed as [Bool.true] and [Bool.false], respectively.
## All other values will result in a `WrongOptionType` error.
boolOption : _ -> Parser Bool # TODO: panics if parameter annotation given
boolOption = \{ long, short ? "", help ? "" } ->
fn = \args ->
when findOneArg long short args is
Err NotFound -> Err (MissingRequiredArg long)
Err NotFound -> Err (MissingRequiredOption long)
Ok { val, newlyTaken } ->
when val is
"true" -> Ok { val: Bool.true, newlyTaken }
"false" -> Ok { val: Bool.false, newlyTaken }
_ -> Err (WrongType { arg: long, expected: Bool })
_ -> Err (WrongOptionType { arg: long, expected: Bool })
@Parser (Arg { long, short, help, type: Bool } fn)
@Parser (Option { long, short, help, type: Bool } fn)
## Creates a parser for a string flag argument.
str : _ -> Parser Str # TODO: panics if parameter annotation given
str = \{ long, short ? "", help ? "" } ->
## Creates a parser for a string option argument.
strOption : _ -> Parser Str # TODO: panics if parameter annotation given
strOption = \{ long, short ? "", help ? "" } ->
fn = \args ->
when findOneArg long short args is
Err NotFound -> Err (MissingRequiredArg long)
Err NotFound -> Err (MissingRequiredOption long)
Ok { val, newlyTaken } -> Ok { val, newlyTaken }
@Parser (Arg { long, short, help, type: Str } fn)
@Parser (Option { long, short, help, type: Str } fn)
## Creates a parser for a 64-bit signed integer ([I64]).
i64 : _ -> Parser I64 # TODO: panics if parameter annotation given
i64 = \{ long, short ? "", help ? "" } ->
## Creates a parser for a 64-bit signed integer ([I64]) option argument.
i64Option : _ -> Parser I64 # TODO: panics if parameter annotation given
i64Option = \{ long, short ? "", help ? "" } ->
fn = \args ->
when findOneArg long short args is
Err NotFound -> Err (MissingRequiredArg long)
Err NotFound -> Err (MissingRequiredOption long)
Ok { val, newlyTaken } ->
Str.toI64 val
|> Result.mapErr (\_ -> WrongType { arg: long, expected: I64 })
|> Result.mapErr (\_ -> WrongOptionType { arg: long, expected: I64 })
|> Result.map (\v -> { val: v, newlyTaken })
@Parser (Arg { long, short, help, type: I64 } fn)
@Parser (Option { long, short, help, type: I64 } fn)
## Parses a single positional argument as a string.
positional : _ -> Parser Str
positional = \{ name, help ? "" } ->
fn = \args ->
nextUnmarked args
|> Result.mapErr (\OutOfBounds -> MissingPositionalArg name)
|> Result.mapErr (\OutOfBounds -> MissingPositional name)
|> Result.map (\{ val, index } -> { val, newlyTaken: Set.insert args.taken index })
@Parser (Positional { name, help } fn)
@ -573,12 +573,12 @@ formatHelpHelp = \n, cmdHelp ->
"""
Config configs ->
argConfigs =
optionConfigs =
filterMap
configs
(\config ->
when config is
Arg c -> Some c
Option c -> Some c
_ -> None)
positionalConfigs =
@ -589,13 +589,13 @@ formatHelpHelp = \n, cmdHelp ->
Positional c -> Some c
_ -> None)
fmtArgsHelp =
if List.isEmpty argConfigs then
fmtOptionsHelp =
if List.isEmpty optionConfigs then
""
else
helpStr =
argConfigs
|> List.map (\c -> formatArgConfig (n + indentLevel) c)
optionConfigs
|> List.map (\c -> formatOptionConfig (n + indentLevel) c)
|> Str.joinWith "\n"
"""
@ -619,7 +619,7 @@ formatHelpHelp = \n, cmdHelp ->
\(helpStr)
"""
Str.concat fmtArgsHelp fmtPositionalsHelp
Str.concat fmtOptionsHelp fmtPositionalsHelp
formatSubCommand = \n, { name, help } ->
indented = indent n
@ -628,14 +628,14 @@ formatSubCommand = \n, { name, help } ->
"\(indented)\(name)\(fmtHelp)"
formatArgConfig : Nat, ArgConfig -> Str
formatArgConfig = \n, { long, short, help, type } ->
formatOptionConfig : Nat, OptionConfig -> Str
formatOptionConfig = \n, { long, short, help, type } ->
indented = indent n
formattedShort =
mapNonEmptyStr short \s -> ", -\(s)"
formattedType = formatType type
formattedType = formatOptionType type
formattedHelp =
mapNonEmptyStr help \h -> " \(h)"
@ -651,8 +651,8 @@ formatPositionalConfig = \n, { name, help } ->
"\(indented)\(name)\(formattedHelp)"
formatType : Type -> Str
formatType = \type ->
formatOptionType : OptionType -> Str
formatOptionType = \type ->
when type is
Bool -> "bool"
Str -> "string"
@ -666,16 +666,16 @@ formatError = \err ->
ProgramNameNotProvided programName ->
"The program name \"\(programName)\" was not probided as a first argument!"
MissingRequiredArg arg ->
"Argument `--\(arg)` is required but was not provided!"
MissingPositional arg ->
"The positional argument `\(arg)` is required but was not provided!"
MissingPositionalArg arg ->
"A positional argument for `\(arg)` is required but was not provided!"
MissingRequiredOption arg ->
"The option `--\(arg)` is required but was not provided!"
WrongType { arg, expected } ->
formattedType = formatType expected
WrongOptionType { arg, expected } ->
formattedType = formatOptionType expected
"The argument `--\(arg)` expects a value of type \(formattedType)!"
"The option `--\(arg)` expects a value of type \(formattedType)!"
SubCommandNotFound { choices } ->
fmtChoices =
@ -708,117 +708,117 @@ formatError = \err ->
## the result of `parser` to `mapper`.
##
## This provides a way to chain the results of multiple parsers together. For
## example, to combine the results of two [str] arguments into a record, you
## could use
## example, to combine the results of two [strOption] arguments into a record,
## you could use
##
## ```
## succeed (\host -> \port -> { host, port })
## |> withParser (str { long: "host" })
## |> withParser (str { long: "port" })
## |> withParser (strOption { long: "host" })
## |> withParser (strOption { long: "port" })
## ```
withParser = \arg1, arg2 -> andMap arg2 arg1
mark = \args -> { args, taken: Set.empty }
# bool undashed long argument is missing
# bool undashed long option is missing
expect
parser = bool { long: "foo" }
parser = boolOption { long: "foo" }
parseHelp parser (mark ["foo"]) == Err (MissingRequiredArg "foo")
parseHelp parser (mark ["foo"]) == Err (MissingRequiredOption "foo")
# bool dashed long argument without value is missing
# bool dashed long option without value is missing
expect
parser = bool { long: "foo" }
parser = boolOption { long: "foo" }
parseHelp parser (mark ["--foo"]) == Err (MissingRequiredArg "foo")
parseHelp parser (mark ["--foo"]) == Err (MissingRequiredOption "foo")
# bool dashed long argument with value is determined true
# bool dashed long option with value is determined true
expect
parser = bool { long: "foo" }
parser = boolOption { long: "foo" }
parseHelp parser (mark ["--foo", "true"]) == Ok Bool.true
# bool dashed long argument with value is determined false
# bool dashed long option with value is determined false
expect
parser = bool { long: "foo" }
parser = boolOption { long: "foo" }
parseHelp parser (mark ["--foo", "false"]) == Ok Bool.false
# bool dashed long argument with value is determined wrong type
# bool dashed long option with value is determined wrong type
expect
parser = bool { long: "foo" }
parser = boolOption { long: "foo" }
parseHelp parser (mark ["--foo", "not-a-bool"]) == Err (WrongType { arg: "foo", expected: Bool })
parseHelp parser (mark ["--foo", "not-a-bool"]) == Err (WrongOptionType { arg: "foo", expected: Bool })
# bool dashed short argument with value is determined true
# bool dashed short option with value is determined true
expect
parser = bool { long: "foo", short: "F" }
parser = boolOption { long: "foo", short: "F" }
parseHelp parser (mark ["-F", "true"]) == Ok Bool.true
# bool dashed short argument with value is determined false
# bool dashed short option with value is determined false
expect
parser = bool { long: "foo", short: "F" }
parser = boolOption { long: "foo", short: "F" }
parseHelp parser (mark ["-F", "false"]) == Ok Bool.false
# bool dashed short argument with value is determined wrong type
# bool dashed short option with value is determined wrong type
expect
parser = bool { long: "foo", short: "F" }
parser = boolOption { long: "foo", short: "F" }
parseHelp parser (mark ["-F", "not-a-bool"]) == Err (WrongType { arg: "foo", expected: Bool })
parseHelp parser (mark ["-F", "not-a-bool"]) == Err (WrongOptionType { arg: "foo", expected: Bool })
# string dashed long argument without value is missing
# string dashed long option without value is missing
expect
parser = str { long: "foo" }
parser = strOption { long: "foo" }
parseHelp parser (mark ["--foo"]) == Err (MissingRequiredArg "foo")
parseHelp parser (mark ["--foo"]) == Err (MissingRequiredOption "foo")
# string dashed long argument with value is determined
# string dashed long option with value is determined
expect
parser = str { long: "foo" }
parser = strOption { long: "foo" }
parseHelp parser (mark ["--foo", "itsme"]) == Ok "itsme"
# string dashed short argument without value is missing
# string dashed short option without value is missing
expect
parser = str { long: "foo", short: "F" }
parser = strOption { long: "foo", short: "F" }
parseHelp parser (mark ["-F"]) == Err (MissingRequiredArg "foo")
parseHelp parser (mark ["-F"]) == Err (MissingRequiredOption "foo")
# string dashed short argument with value is determined
# string dashed short option with value is determined
expect
parser = str { long: "foo", short: "F" }
parser = strOption { long: "foo", short: "F" }
parseHelp parser (mark ["-F", "itsme"]) == Ok "itsme"
# i64 dashed long argument without value is missing
# i64 dashed long option without value is missing
expect
parser = i64 { long: "foo" }
parser = i64Option { long: "foo" }
parseHelp parser (mark ["--foo"]) == Err (MissingRequiredArg "foo")
parseHelp parser (mark ["--foo"]) == Err (MissingRequiredOption "foo")
# i64 dashed long argument with value is determined positive
# i64 dashed long option with value is determined positive
expect
parser = i64 { long: "foo" }
parser = i64Option { long: "foo" }
parseHelp parser (mark ["--foo", "1234"]) == Ok 1234
# i64 dashed long argument with value is determined negative
# i64 dashed long option with value is determined negative
expect
parser = i64 { long: "foo" }
parser = i64Option { long: "foo" }
parseHelp parser (mark ["--foo", "-1234"]) == Ok -1234
# i64 dashed short argument without value is missing
# i64 dashed short option without value is missing
expect
parser = i64 { long: "foo", short: "F" }
parser = i64Option { long: "foo", short: "F" }
parseHelp parser (mark ["-F"]) == Err (MissingRequiredArg "foo")
parseHelp parser (mark ["-F"]) == Err (MissingRequiredOption "foo")
# i64 dashed short argument with value is determined
# i64 dashed short option with value is determined
expect
parser = i64 { long: "foo", short: "F" }
parser = i64Option { long: "foo", short: "F" }
parseHelp parser (mark ["-F", "1234"]) == Ok 1234
@ -826,8 +826,8 @@ expect
expect
parser =
succeed (\foo -> \bar -> "foo: \(foo) bar: \(bar)")
|> withParser (str { long: "foo" })
|> withParser (str { long: "bar" })
|> withParser (strOption { long: "foo" })
|> withParser (strOption { long: "bar" })
cases = [
["--foo", "true", "--bar", "baz"],
@ -841,13 +841,13 @@ expect
expect
parser =
succeed (\foo -> \bar -> "foo: \(foo) bar: \(bar)")
|> withParser (str { long: "foo" })
|> withParser (str { long: "bar" })
|> withParser (strOption { long: "foo" })
|> withParser (strOption { long: "bar" })
List.all
[
parseHelp parser (mark ["--foo", "zaz"]) == Err (MissingRequiredArg "bar"),
parseHelp parser (mark ["--bar", "zaz"]) == Err (MissingRequiredArg "foo"),
parseHelp parser (mark ["--foo", "zaz"]) == Err (MissingRequiredOption "bar"),
parseHelp parser (mark ["--bar", "zaz"]) == Err (MissingRequiredOption "foo"),
]
(\b -> b)
@ -855,47 +855,47 @@ expect
expect
parser =
succeed (\foo -> \bar -> \_bool -> "foo: \(foo) bar: \(bar)")
|> withParser (str { long: "foo", help: "the foo flag" })
|> withParser (str { long: "bar", short: "B" })
|> withParser (bool { long: "bool" })
|> withParser (strOption { long: "foo", help: "the foo option" })
|> withParser (strOption { long: "bar", short: "B" })
|> withParser (boolOption { long: "bool" })
toHelp parser
== Config [
Arg { long: "foo", short: "", help: "the foo flag", type: Str },
Arg { long: "bar", short: "B", help: "", type: Str },
Arg { long: "bool", short: "", help: "", type: Bool },
Option { long: "foo", short: "", help: "the foo option", type: Str },
Option { long: "bar", short: "B", help: "", type: Str },
Option { long: "bool", short: "", help: "", type: Bool },
]
# format argument is missing
# format option is missing
expect
parser = bool { long: "foo" }
parser = boolOption { long: "foo" }
when parseHelp parser (mark ["foo"]) is
Ok _ -> Bool.false
Err e ->
err = formatError e
err == "Argument `--foo` is required but was not provided!"
err == "The option `--foo` is required but was not provided!"
# format argument has wrong type
# format option has wrong type
expect
parser = bool { long: "foo" }
parser = boolOption { long: "foo" }
when parseHelp parser (mark ["--foo", "12"]) is
Ok _ -> Bool.false
Err e ->
err = formatError e
err == "The argument `--foo` expects a value of type bool!"
err == "The option `--foo` expects a value of type bool!"
# format help menu with only args
# format help menu with only options
expect
parser =
succeed (\_foo -> \_bar -> \_baz -> \_bool -> "")
|> withParser (str { long: "foo", help: "the foo flag" })
|> withParser (str { long: "bar", short: "B" })
|> withParser (str { long: "baz", short: "z", help: "the baz flag" })
|> withParser (bool { long: "bool" })
|> withParser (strOption { long: "foo", help: "the foo option" })
|> withParser (strOption { long: "bar", short: "B" })
|> withParser (strOption { long: "baz", short: "z", help: "the baz option" })
|> withParser (boolOption { long: "bool" })
|> program { name: "test" }
formatHelp parser
@ -904,9 +904,9 @@ expect
test
OPTIONS:
--foo the foo flag (string)
--foo the foo option (string)
--bar, -B (string)
--baz, -z the baz flag (string)
--baz, -z the baz option (string)
--bool (bool)
"""
@ -915,12 +915,12 @@ expect
parser =
choice [
succeed (\user -> \pw -> "\(user)\(pw)")
|> withParser (str { long: "user" })
|> withParser (str { long: "pw" })
|> withParser (strOption { long: "user" })
|> withParser (strOption { long: "pw" })
|> subCommand "login",
succeed (\file -> \url -> "\(file)\(url)")
|> withParser (str { long: "file" })
|> withParser (str { long: "url" })
|> withParser (strOption { long: "file" })
|> withParser (strOption { long: "url" })
|> subCommand "publish",
]
|> program { name: "test" }
@ -963,12 +963,12 @@ expect
parser =
choice [
succeed (\user -> \pw -> "logging in \(user) with \(pw)")
|> withParser (str { long: "user" })
|> withParser (str { long: "pw" })
|> withParser (strOption { long: "user" })
|> withParser (strOption { long: "pw" })
|> subCommand "login",
succeed (\file -> \url -> "\(file)\(url)")
|> withParser (str { long: "file" })
|> withParser (str { long: "url" })
|> withParser (strOption { long: "file" })
|> withParser (strOption { long: "url" })
|> subCommand "publish",
]
|> program { name: "test" }
@ -983,8 +983,8 @@ expect
choice [
choice [
succeed (\user -> \pw -> "logging in \(user) with \(pw)")
|> withParser (str { long: "user" })
|> withParser (str { long: "pw" })
|> withParser (strOption { long: "user" })
|> withParser (strOption { long: "pw" })
|> subCommand "login",
]
|> subCommand "auth",
@ -1031,17 +1031,17 @@ expect
\t"auth", "publish"
"""
# parse positional argument
# parse positional
expect
parser = positional { name: "foo" }
parseHelp parser (mark ["myArg"]) == Ok "myArg"
# parse positional argument with argument flag
# parse positional with option
expect
parser =
succeed (\foo -> \bar -> "foo: \(foo), bar: \(bar)")
|> withParser (str { long: "foo" })
|> withParser (strOption { long: "foo" })
|> withParser (positional { name: "bar" })
cases = [
@ -1051,7 +1051,7 @@ expect
List.all cases \args -> parseHelp parser (mark args) == Ok "foo: true, bar: baz"
# parse positional argument with subcommand
# parse positional with subcommand
expect
parser = choice [
positional { name: "bar" }
@ -1060,8 +1060,8 @@ expect
parseHelp parser (mark ["hello", "foo"]) == Ok "foo"
# missing positional argument
# missing positional
expect
parser = positional { name: "bar" }
parseHelp parser (mark []) == Err (MissingPositionalArg "bar")
parseHelp parser (mark []) == Err (MissingPositional "bar")