-
Notifications
You must be signed in to change notification settings - Fork 1
Command line option parser
Module: FSharp.CommandLine.Options
Source: src/FSharp.CommandLine/options.fs
FSharp.CommandLine.Options provides a declarative and highly reusable command line option parser.
Capable of inputs like -f a.txt, --file=a.txt, -Wall, --flag+, and /dosstyle. Also treats -- ("bare double dash") correctly.
Can be either used
-
with
CommandOption.parse: CommandOption<'a> -> string list -> ('a option * string list)function. -
with
| OptionParse <option> <result_deconstructor>active pattern.
You should not create your own
--helpoption; this library handles it by itself.
-
type CommandOption<'a>... represents command options. -
module CommandOption-
val getRemainingOptions: (argv:string list) -> (found_options:string list)... finds occurrences of options. val parse: (opt: CommandOption<'a>) -> (argv: string list) -> (result:'a option * remaining_args:string list)-
val parseMany: (opt: CommandOption<'a>) -> (argv: string list) -> (results:option list * remaining_args:string list)... parses all the occurrences of specified option.
-
-
the rest will be explained later.
commandOption can be used to define an option which takes an argument.
commandOption {
names ["t"; "txt"] // no hyphens or slashes, please!
description "Speficy text file."
takes (format("%s").withNames["file"])
suggests (fun _ -> [ CommandSuggestion.Files (Some "*.txt") ])
}commandFlag can also be used to define a flag.
commandFlag {
names ["f"; "force"]
description "Use the --force, Luke!"
style SingleHyphenStyle.SingleLong
}Here are a few notes about several operators.
Specifies the value to use when the option is given without argument (e.g. used as a flag).
Can only be used inside commandOption {}.
Example:
let backupOption =
commandOption {
names ["b"]
description "Copy the original file to <file>."
takes (format("%s").map(fun file _ -> file))
defaultValue (fun s -> sprintf "%s.bak" s)
}takes (<parser>[<modifier>])Source: src/FSharp.CommandLine/optionValues.fs
Specifies how to handle the argument. Can only be used inside commandOption {}.
Consists of two parts: the parser and the modifier.
Specify how to parse the argument - the input string.
-
formatparser
Uses type-safe scanf format.
The types of captured variables will be inferred from the format string.
-
regexparser
Uses .NET regex. Very similar to the famous regex active pattern.
Captures variables as string list; no type inference here.
Constructs another type of object from the captured variables, and/or name the captures for --help.
-
.map(fun .. -> ..)modifier
An obvious function to create higher constructs.
The names of arguments are important here and will be respected when shown in --help; you don't have to use the .withNames modifier alongside this.
-
.withNames[..]/|> withNames[..]modifier
A function to specify the names of the captures, used especially when .map is not needed but you want to make --help look better.
Comparison:
takes (format("%s:%i"))
// -f, --file=<STRING_VALUE>:<INT_VALUE>
takes (format("%s:%i").withNames ["filename"; "index"])
// -f, --file=<filename>:<index>-
.asConst(..)/|> asConst ..modifier
When there are no captures, you can use this to avoid writing .map(fun _ -> ..).
Examples:
let fileOption =
commandOption {
names ["f"; "file"]
description "Name of a file to use (Default index: 0)"
takes (format("%s:%i").withNames ["filename"; "index"])
takes (format("%s").map (fun filename -> (filename, 0)))
suggests (fun _ -> [CommandSuggestion.Files None])
}
type Verbosity = Quiet | Normal | Full | Custom of int
let verbosityOption =
commandOption {
names ["v"; "verbosity"]
description "Display this amount of information in the log."
takes (regex @"q(uiet)?$" |> asConst Quiet)
takes (format "n" |> asConst Quiet)
takes (format "normal" |> asConst Quiet)
takes (regex @"f(ull)?$" |> asConst Full)
takes (format("custom:%i").map (fun level -> Custom level))
takes (format("c:%i").map (fun level -> Custom level))
}Specifies the shell suggestions it generates. Can only be used inside commandOption {}.
See Suggestion Generation System.
Specifies how to handle inputs like -abcd.
-
SingleHyphenStyle.SingleLong... treat-abcdas--abcd. -
SingleHyphenStyle.SingleShort... treat-abcdas-a bcd. -
SingleHyphenStyle.MergedShort... treat-abcdas-a -b -c -d.
When not specified, MergedShort will be used (it's the UNIX tradition).
If you want to be like gcc (-Wall), SingleShort is what you want.
You can also use these methods to define new options/flags with fewer keystrokes:
-
Command.option(_names, _format, ?_descr, ?defVal, ?_style) -
Command.flag(_names, ?_descr, ?_style)
When you use command options within command {} computation expression, you may want to
- restrict the number of occurrences to be only one
- allow multiple occurrences and treat the result as a
'a list, not'a option - assign a default value to the bound variable, if missing
All of the above can be achieved by option augmentation.
When bound with opt .. in .. operator it assigns a value of type 'a.
Note that CommandOption<'b> implements ICommandOption<'a option>, since it assigns an optional value when bound with that operator.
Represents the 'augmented' command options that preserve specs of the original option but modify the parser's behaviour.
When bound with opt .. in .. operator it assigns a value of type 'b, because it implements ICommandOption<'b>.
-
val map: (f: 'a -> 'b) -> (c: ICommandOption<'a>) -> AugmentedCommandOption<'a, 'b>... map the parsed result. -
val zeroOrMore (co: ICommandOption<'a option>) -> AugmentedCommandOption<'a option, 'a list>... apply parser until no matches found, and return the result as a list. -
val zeroOrExactlyOne (co: ICommandOption<'a option>) -> AugmentedCommandOption<'a list, 'a option>... apply parser once and immediately fail if there are one or more occurrences left. -
val whenMissingUse: (v: 'a) -> (co: ICommandOption<'a option>) -> AugmentedCommandOption<'a option, 'a>... return a specified default value if there are no occurrences.
let forceOption descr =
commandFlag {
names ["f"; "force"]
description descr
}
// val forceOption: ICommandOption<bool option>
let mainCommand =
command {
opt force1 in forceOption // val force1: bool option
opt force2 in forceOption |> CommandOption.zeroOrExactlyOne
|> CommandOption.whenMissingUse false
// val force2: bool
if force2 then
..
else
..
}
let forceOption2 descr =
commandFlag {
names ["f"; "force"]
description descr
} |> CommandOption.zeroOrExactlyOne
|> CommandOption.whenMissingUse false
// val forceOption: ICommandOption<bool>