andrey-zherikov / argparse Goto Github PK
View Code? Open in Web Editor NEWParser for command-line arguments
Home Page: https://andrey-zherikov.github.io/argparse/
License: Boost Software License 1.0
Parser for command-line arguments
Home Page: https://andrey-zherikov.github.io/argparse/
License: Boost Software License 1.0
Currently, unit tests write to both stdout and stderr. They should do neither because they are run by clients of the library.
import std;
import argparse;
@Command("c1")
struct command1
{
bool c1data;
}
@Command("c2")
struct command2
{
@NamedArgument
bool c2data;
}
struct Program {
@NamedArgument("numbers")
bool numbers;
SumType!(command1, command2) cmd;
}
void _main(Program args)
{
writeln(args);
}
mixin CLI!(Program).main!((arguments) {
_main(arguments);
});
This program does not show the subcommand when called with --help
:
Usage: argparse-test [--numbers] [-h]
Optional arguments:
--numbers
-h, --help Show this help message and exit
If I remove the @NamedArgument annotation, then its printing the expected output:
Usage: argparse-test [--numbers] [-h] <command> [<args>]
Available commands:
c1
c2
Optional arguments:
--numbers
-h, --help Show this help message and exit
Happens only with some versions of the compiler e.g dmd-2.100.0.
``
../../external/argparse/source/argparse/package.d(425,6): Error: typesafe variadic function parameter
name` of type `string[]` cannot be marked `return`
It seems, PositionalArgument(0)
actually gets the name of the executable itself, at least on Windows. I have struct defined this way:
@(Command.Description("Simple tool that generates a D source module embedding specified resources into it"))
struct Options {
@(
PositionalArgument(0)
.Description("Resource manifest to process")
)
string manifest;
@(
NamedArgument("d", "developer")
.Description("Read resources from filesystem instead of actually embedding them")
)
bool developerMode = false;
}
Argument parsing is called this way:
void main(string[] args) {
CLI!Options.parseArgs!typedMain(args);
}
And for the test I just output the parsed manifest
option:
void typedMain(Options args) {
info("Provided manifest file: " ~ args.manifest);
}
Seems to follow examples from docs, if I'm not missing something obvious... Well, results:
> embed-resources
Provided manifest file: embed-resources
> embed-resources manifest.json
Error: Unrecognized arguments: ["manifest.json"]
import argparse;
struct Args {
bool banana;
}
mixin CLI!({
Config cfg;
cfg.errorHandler = (string) { };
return cfg;
}(), Args).main!((in _) { });
argparse/config.d(90,9): Error: closures are not yet supported in CTFE
N.B. (string) { }
is not a closure; return errorHandlerFunc = (string msg) { func(msg); };
(inside the library) is.
I’m almost satisfied with the way argparse
formats the help message. Just a couple of suggestions:
-h
/--help
argument should be customizable. For example, one might want to reword its description or omit --help
from help (what’s the point of having it there, in the first place?). Disabling it altogether and processing it manually is not an option: -h
is special-cased in the parser (no errors are issued if -h
is present, and it interacts with subcommands in a complex way). I suppose the approach of ansiStylingArgument
can be used here.
This code currently produces the following output:
import argparse;
struct Args {
@(NamedArgument("b", "banana").Description("Description of the banana"))
int banana;
}
mixin CLI!Args.main!((in _) { });
Usage: myprog [-b BANANA] [-h]
Optional arguments:
-b BANANA, --banana BANANA
Description of the banana
-h, --help Show this help message and exit
I’d like it to look as follows:
Usage: myprog [-b BANANA] [-h]
Optional arguments:
-b, --banana BANANA
Description of the banana
-h, --help Show this help message and exit
I.e., output a placeholder only once per set of alternatives (one BANANA at the end). Saying that several times a line just clutters the output, in my opinion. A field in the config will fit, I think.
You may notice in the example above that columns are separated by 4 spaces. Is it a bug? (I saw a reference to 2 spaces somewhere in the source and would indeed prefer slightly more compact layout.)
If epilog
is empty (default), a blank line is emitted before it nevertheless. Therefore, the output of a program ends with \n\n
, which feels wrong.
I think it would be handy if a program, when invoked incorrectly (i.e., if parsing failed), printed its one-line usage after the error message. I’d appreciate if I could just enable that behaviour with a flag in the config; however, it would even be possible to implement it outside the library if we had access to computed usage
and if errorHandler
wasn’t broken.
Compilation flags used --mtriple=x86_64-linux-gnu -w --preview=dip1000 --preview=dtorfields --preview=fieldwise -O --release --boundscheck=off
(this is a precheck compilation phase).
Example code for argparse options (the code that produces the error):
struct ViewerOptions
{
@(MutuallyExclusive())
{
@(NamedArgument("local").Description("Choose a local connection").Optional())
bool local = true;
@(NamedArgument("remote").Description("Choose a remote connection").Optional())
string remoteAddress = null;
}
@(NamedArgument("serverPath").Description("Path the server binary").Optional())
string serverPath = null;
@(NamedArgument("p", "path").Description("Path of the dumping blobs").Optional())
string localPath = defaultPath;
@(NamedArgument("namespace").Description("Namespace to interleave").Optional())
string namespace = null;
@(NamedArgument("d", "debug").Description("Enable debugging").Optional())
bool debugging = false;
}
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(278): Error: CTFE failed because of previous errors in `getMemberArgumentUDA`
/opt/hostedtoolcache/dc/ldc2-1.30.0/x64/ldc2-1.30.0-linux-x86_64/bin/../import/std/meta.d(652): Error: template instance `argparse.internal.command.TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions).fun!"serverPath"` error instantiating
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(286): instantiated from here: `staticMap!(getArgumentUDA, "local", "remoteAddress", "serverPath", "localPath", "namespace", "debugging")`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(358): instantiated from here: `TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(603): instantiated from here: `createCommand!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(628): ... (2 instantiations, -v to show) ...
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/api/cli.d(192): instantiated from here: `CLI!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.autodetect, null), ViewerOptions)`
source/wtracer/viewer/main.d(273): instantiated from here: `CLI!(ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(278): Error: CTFE failed because of previous errors in `getMemberArgumentUDA`
/opt/hostedtoolcache/dc/ldc2-1.30.0/x64/ldc2-1.30.0-linux-x86_64/bin/../import/std/meta.d(652): Error: template instance `argparse.internal.command.TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions).fun!"localPath"` error instantiating
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/argumentudahelpers.d(77): Error: first argument is not a symbol
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/argumentudahelpers.d(80): while evaluating: `static assert(typeUDAs.length <= 1)`
/opt/hostedtoolcache/dc/ldc2-1.30.0/x64/ldc2-1.30.0-linux-x86_64/bin/../import/std/meta.d(652): Error: template instance `argparse.internal.command.TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions).fun!"local"` error instantiating
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(286): instantiated from here: `staticMap!(getArgumentUDA, "local", "remoteAddress", "serverPath", "localPath", "namespace", "debugging")`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(358): instantiated from here: `TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(603): instantiated from here: `createCommand!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(626): ... (2 instantiations, -v to show) ...
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/api/cli.d(192): instantiated from here: `CLI!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.autodetect, null), ViewerOptions)`
source/wtracer/viewer/main.d(273): instantiated from here: `CLI!(ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/argumentudahelpers.d(77): Error: first argument is not a symbol
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/argumentudahelpers.d(80): while evaluating: `static assert(typeUDAs.length <= 1)`
/opt/hostedtoolcache/dc/ldc2-1.30.0/x64/ldc2-1.30.0-linux-x86_64/bin/../import/std/meta.d(652): Error: template instance `argparse.internal.command.TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions).fun!"remoteAddress"` error instantiating
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(286): instantiated from here: `staticMap!(getArgumentUDA, "local", "remoteAddress", "serverPath", "localPath", "namespace", "debugging")`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(358): instantiated from here: `TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(603): instantiated from here: `createCommand!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(626): ... (2 instantiations, -v to show) ...
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/api/cli.d(192): instantiated from here: `CLI!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.autodetect, null), ViewerOptions)`
source/wtracer/viewer/main.d(273): instantiated from here: `CLI!(ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/argumentudahelpers.d(77): Error: first argument is not a symbol
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/argumentudahelpers.d(80): while evaluating: `static assert(typeUDAs.length <= 1)`
/opt/hostedtoolcache/dc/ldc2-1.30.0/x64/ldc2-1.30.0-linux-x86_64/bin/../import/std/meta.d(652): Error: template instance `argparse.internal.command.TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions).fun!"serverPath"` error instantiating
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(286): instantiated from here: `staticMap!(getArgumentUDA, "local", "remoteAddress", "serverPath", "localPath", "namespace", "debugging")`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(358): instantiated from here: `TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(603): instantiated from here: `createCommand!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(626): ... (2 instantiations, -v to show) ...
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/api/cli.d(192): instantiated from here: `CLI!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.autodetect, null), ViewerOptions)`
source/wtracer/viewer/main.d(273): instantiated from here: `CLI!(ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/argumentudahelpers.d(77): Error: first argument is not a symbol
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/argumentudahelpers.d(80): while evaluating: `static assert(typeUDAs.length <= 1)`
/opt/hostedtoolcache/dc/ldc2-1.30.0/x64/ldc2-1.30.0-linux-x86_64/bin/../import/std/meta.d(652): Error: template instance `argparse.internal.command.TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions).fun!"localPath"` error instantiating
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(286): instantiated from here: `staticMap!(getArgumentUDA, "local", "remoteAddress", "serverPath", "localPath", "namespace", "debugging")`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(358): instantiated from here: `TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(603): instantiated from here: `createCommand!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(626): ... (2 instantiations, -v to show) ...
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/api/cli.d(192): instantiated from here: `CLI!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.autodetect, null), ViewerOptions)`
source/wtracer/viewer/main.d(273): instantiated from here: `CLI!(ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/argumentudahelpers.d(77): Error: first argument is not a symbol
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/argumentudahelpers.d(80): while evaluating: `static assert(typeUDAs.length <= 1)`
/opt/hostedtoolcache/dc/ldc2-1.30.0/x64/ldc2-1.30.0-linux-x86_64/bin/../import/std/meta.d(652): Error: template instance `argparse.internal.command.TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions).fun!"namespace"` error instantiating
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(286): instantiated from here: `staticMap!(getArgumentUDA, "local", "remoteAddress", "serverPath", "localPath", "namespace", "debugging")`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(358): instantiated from here: `TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(603): instantiated from here: `createCommand!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(626): ... (2 instantiations, -v to show) ...
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/api/cli.d(192): instantiated from here: `CLI!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.autodetect, null), ViewerOptions)`
source/wtracer/viewer/main.d(273): instantiated from here: `CLI!(ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/argumentudahelpers.d(77): Error: first argument is not a symbol
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/argumentudahelpers.d(80): while evaluating: `static assert(typeUDAs.length <= 1)`
/opt/hostedtoolcache/dc/ldc2-1.30.0/x64/ldc2-1.30.0-linux-x86_64/bin/../import/std/meta.d(652): Error: template instance `argparse.internal.command.TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions).fun!"debugging"` error instantiating
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(286): instantiated from here: `staticMap!(getArgumentUDA, "local", "remoteAddress", "serverPath", "localPath", "namespace", "debugging")`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(358): instantiated from here: `TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(603): instantiated from here: `createCommand!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.on, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(626): ... (2 instantiations, -v to show) ...
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/api/cli.d(192): instantiated from here: `CLI!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.autodetect, null), ViewerOptions)`
source/wtracer/viewer/main.d(273): instantiated from here: `CLI!(ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(278): Error: CTFE failed because of previous errors in `getMemberArgumentUDA`
/opt/hostedtoolcache/dc/ldc2-1.30.0/x64/ldc2-1.30.0-linux-x86_64/bin/../import/std/meta.d(652): Error: template instance `argparse.internal.command.TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions).fun!"local"` error instantiating
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(286): instantiated from here: `staticMap!(getArgumentUDA, "local", "remoteAddress", "serverPath", "localPath", "namespace", "debugging")`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(358): instantiated from here: `TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(603): instantiated from here: `createCommand!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(628): ... (2 instantiations, -v to show) ...
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/api/cli.d(192): instantiated from here: `CLI!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.autodetect, null), ViewerOptions)`
source/wtracer/viewer/main.d(273): instantiated from here: `CLI!(ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(278): Error: CTFE failed because of previous errors in `getMemberArgumentUDA`
/opt/hostedtoolcache/dc/ldc2-1.30.0/x64/ldc2-1.30.0-linux-x86_64/bin/../import/std/meta.d(652): Error: template instance `argparse.internal.command.TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions).fun!"remoteAddress"` error instantiating
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(286): instantiated from here: `staticMap!(getArgumentUDA, "local", "remoteAddress", "serverPath", "localPath", "namespace", "debugging")`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(358): instantiated from here: `TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(603): instantiated from here: `createCommand!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(628): ... (2 instantiations, -v to show) ...
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/api/cli.d(192): instantiated from here: `CLI!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.autodetect, null), ViewerOptions)`
source/wtracer/viewer/main.d(273): instantiated from here: `CLI!(ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(278): Error: CTFE failed because of previous errors in `getMemberArgumentUDA`
/opt/hostedtoolcache/dc/ldc2-1.30.0/x64/ldc2-1.30.0-linux-x86_64/bin/../import/std/meta.d(652): Error: template instance `argparse.internal.command.TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions).fun!"serverPath"` error instantiating
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(286): instantiated from here: `staticMap!(getArgumentUDA, "local", "remoteAddress", "serverPath", "localPath", "namespace", "debugging")`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(358): instantiated from here: `TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(603): instantiated from here: `createCommand!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/parser.d(628): ... (2 instantiations, -v to show) ...
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/api/cli.d(192): instantiated from here: `CLI!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.autodetect, null), ViewerOptions)`
source/wtracer/viewer/main.d(273): instantiated from here: `CLI!(ViewerOptions)`
/home/runner/work/wtracer/wtracer/3rdparty/argparse/source/argparse/internal/command.d(278): Error: CTFE failed because of previous errors in `getMemberArgumentUDA`
/opt/hostedtoolcache/dc/ldc2-1.30.0/x64/ldc2-1.30.0-linux-x86_64/bin/../import/std/meta.d(652): Error: template instance `argparse.internal.command.TypeTraits!(Config('=', '\xff', '-', "--", true, false, true, Style(TextStyle("\x1b[1"), TextStyle("\x1b[1"), TextStyle("\x1b[1;4"), TextStyle("\x1b[93"), TextStyle("\x1b[3"), TextStyle("\x1b[93"), TextStyle("\x1b[31")), StylingMode.off, null), ViewerOptions).fun!"localPath"` error instantiating
e.g. for me --help does not print the subcommands if I do not Annotate their SumType with @SubCommands.
Also the first subsection reads Subcommands without UDA
which indices for me, that there is a way to do subcommands without and with uda ... but its kind of the same, just the subcommands are configured with udas ...
Would be awesome to have a flag that outputs shell completion code primarily for bash and zshell.
Python has this at https://kislyuk.github.io/argcomplete/.
If program name is not provided, then
Runtime.args[0]
(a.k.a.argv[0]
frommain
function) is used.
Here’s how we “not provide” a program name:
import argparse;
@(Command("").Description("A program's description."))
struct Args {
bool banana;
}
mixin CLI!Args.main!((in _) { });
Command()
should work as well, shouldn’t it? But it doesn’t; it throws an ArrayIndexError
.
All --
-aware programs I’ve encountered understand it the same way: it marks the end of named parameters; all arguments following it are bound to positional ones. To illustrate, these three invocations are equivalent:
cp -f -- a b
cp -f a -- b
cp -f a b
This is necessary in order to support binding an argument that starts with a dash to a positional one:
cp -- a -R # Copy the file named `a` to a file named `-R`.
cp a -- -R # Ditto.
This is important to a program user if the names aren’t known in advance:
cp -- "$from" "$to" # Will work predictably no matter what these variables contain.
If we were implementing cp
in D, we’d like to declare it as follows:
struct Args {
@PositionalArgument(0) string from;
@PositionalArgument(1) string to;
}
…and expect everything to work out of the box.
A program should never need to know if it was invoked with --
or without. If it needs to accept a variable number of arguments, it just asks for @(PositionalArgument(0).Optional) string[ ] rest
.
It is a common idiom to accept a -
parameter meaning stdin. E.g., cat -
reads its whole stdin and sends it to stdout. However, argparse currently treats it as a named parameter, even though NamedArgument("")
is not allowed—so it cannot be accessed in any way.
import argparse;
struct T {
@NamedArgument bool c;
@PositionalArgument(0) string fileName;
}
void main() {
assert(CLI!T.parseArgs!((T t) { assert(t == T(true, "-")); })(["-", "-c"]) == 0);
}
import argparse;
struct Args {
bool banana;
}
mixin CLI!({
Config cfg = { caseSensitive: false };
return cfg;
}(), Args).main!((in _) { });
$ ./prog --help
Error: Unrecognized arguments: ["--help"]
struct Param(VALUE_TYPE)
contains a const Config* config
, which disables the assignment operator for the whole struct. Perhaps you meant const(Config)* config
?
Discovered this when I was trying to deduplicate Complete.InitCmd
. A reduced example that should be easier to follow:
struct Description {
string delegate() dg;
}
auto createCompleter(string desc) {
@Description(() => desc) // Seems good so far.
struct Complete { }
return Complete.init; // Err... We haven't stored `desc` anywhere, have we?
}
void main() {
import std.stdio: writeln;
import std.traits: getUDAs;
enum completer = createCompleter("Description.");
writeln(getUDAs!(typeof(completer), Description)[0].dg()); // Here.
}
The compiler blames: delegate test.createCompleter.__lambda3
is a nested function and cannot be accessed from D main
. And it is right. Therefore, a delegate can be used with a LazyString
only if it does not escape its declaration scope.
UDAs are attached at struct-declaration time, but variables we want to close over are only available at instance-creation time. Unfortunately, I can’t think of a good solution here. One idea comes to my mind: add a third option to LazyString
, which should be a struct with no members, to signify even more runtime strings. Then a caller can test for this and invoke cmd.getDescription
. That should work in principle, but it requires patching every callsite to account for that, which I’m not happy with. Any better ideas?
This is almost probably a compiler/Phobos regression. CC @pbackus perhaps are you aware of some change on sumtype that affected this? There's no other informational error, so, I can't understand clearly where the issue resides exactly. All I have is this log, and I'm confident its from argparse
given the type names:
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Unknown))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Argument))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(SubCommand))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Unknown))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Argument))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(SubCommand))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Unknown))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Argument))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(SubCommand))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Unknown))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Argument))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(SubCommand))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Unknown))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Argument))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(SubCommand))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Unknown))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Argument))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(SubCommand))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Unknown))` does not match template declaration `DeducedParameterType(T)`
/home/luis/.local/bin/../import/std/sumtype.d(418): Error: template instance `DeducedParameterType!(inout(Argument))` does not match template declaration `DeducedParameterType(T)`
If I try something like this:
...
@(NamedArgument
.Description("Set of ponies to consider +- list of regexes")
.Parse!((string s) { return 1; })
.Action!((ref double result, int i) { result = 1.0; })
)
double set;
...
it works as described, but if I replace double
with a custom type of mine:
...
struct MyType {
double d;
}
...
@(NamedArgument
.Description("Set of ponies to consider +- list of regexes")
.Parse!((string s) { return 1; })
.Action!((ref MyType result, int i) { result = MyType(); result.d = 1.0; })
)
MyType set;
...
I get from the compiler:
../../../../../.dub/packages/argparse-master/argparse/source/argparse/internal.d(478,9): Error: static assert: "Type is not supported: MyType"
../../../../../.dub/packages/argparse-master/argparse/source/argparse/internal.d(493,58): instantiated from here: `defaultValuesCount!(MyType)`
../../../../../.dub/packages/argparse-master/argparse/source/argparse/internal.d(885,29): instantiated from here: `setDefaults!(MyType, "set")`
../../../../../.dub/packages/argparse-master/argparse/source/argparse/internal.d(852,21): instantiated from here: `addArgument!("set")`
mixin CLI!Params.main!((arguments) { });
struct Params
{
@PositionalArgument(0, "bar")
string foo;
}
shows the help as
Usage: command [-h] foo
Required arguments:
foo
while I would have expected "bar" instead of "foo" from the README.
(Especially in the case that the CLI parameter is a keyword of D.)
import argparse;
struct Args {
bool b;
string s;
}
mixin CLI!({
Config cfg = { bundling: true };
return cfg;
}(), Args).main!((in args) {
import std.stdio;
writeln(args.b, " <", args.s, '>');
});
./prog -bs=abc
Expected output: true <abc>
.
Current output: true <>
.
On the other hand, all of these work correctly:
./prog -bsabc
./prog -b -sabc
./prog -b -s=abc
./prog -b -s abc
import argparse;
static struct Basic
{
@PositionalArgument(0)
int[] array;
}
mixin CLI!Basic.main!((args)
{
return 0;
});
If I call this program without arguments, I get an error message:
Error: The following argument is required: --array
But there is no argument --array
. The help message actually provides the correct name:
Required arguments:
array ...
An example from the Readme, reduced:
import argparse;
struct T {
@(PositionalArgument(0).Description(() => "Argument description"))
string param0;
}
void main() {
CLI!T.parseArgs!((T t) { })(["-h"]); // SIGILL
}
DMD 2.105.3.
I have no idea why, but I don't see any colors in the help text in the bash terminal of Visual Studio Code.
I see colors in a separate terminal. And I see the red "Error:" text in error messages from dmd in Visual Studio Code.
Having a mere import argparse;
in a program and compiling it with -unittest
compiles and runs all of the argparse’s tests. Or at least attempts to. If I run dmd -lowmem -unittest -i test.d
on a file containing this single line, the compiler devours 2.8 GB of RAM; then I kill it, or else my system freezes. I have no idea how hungry it is in reality.
In my opinion, inspecting some UDAs shouldn’t involve so much work. I’ll have a look at the code and see if I can figure out what is going on there.
Hello,
I am making a CLI which only has subcommands, and as such I thought that is should show help when no command is given, how can I do that. I didn't find any way to show the default help outside of the help switch.
If there are default values for subcommands or parameters, those should be highlighted in the helptext.
e.g.
import std.stdio;
import argparse;
struct Cmd1 {}
struct Cmd2 {}
enum Mode {
WALK,
RUN,
}
struct Arguments {
@(NamedArgument.Description("dsc for text1"))
string text1 = "abc";
@(NamedArgument.Description("dsc for text2"))
string text2;
@(NamedArgument.Description("mode to use"))
Mode mode = Mode.WALK;
SubCommand!(Default!Cmd1, Cmd2) subcommands;
}
mixin CLI!Arguments.main!(arguments => arguments.writeln);
outputs
Usage: argparse-issue [--text1 TEXT1] [--text2 TEXT2] [--mode {WALK,RUN}] [-h] <command> [<args>]
Available commands:
Cmd1
Cmd2
Optional arguments:
--text1 TEXT1 dsc for text1
--text2 TEXT2 dsc for text2
--mode {WALK,RUN} mode to use
-h, --help Show this help message and exit
at the moment when called with --help
.
It would be great if something like
Usage: argparse-issue [--text1 TEXT1] [--text2 TEXT2] [--mode {WALK,RUN}] [-h] <command> [<args>]
Available commands:
Cmd1 (default)
Cmd2
Optional arguments:
--text1 TEXT1 dsc for text1 (defaults to abc)
--text2 TEXT2 dsc for text2
--mode {WALK,RUN} mode to use (defaults to WALK)
-h, --help Show this help message and exit
could be printed.
I have a program with a debug output option, so it can be called with --format debug
. Output options are defined as enum
:
enum OutputFormat
{
silent,
debug_,
}
Obviously, I cannot define debug
as enum
member since it is a keyword. My current workaround looks like this:
import argparse;
import std.meta;
import std.traits;
import std.conv;
import std.algorithm;
enum OutputFormat
{
silent,
debug_,
}
private enum string allowedOutputFormat(OutputFormat Member) =
Member.to!string.strip('_');
private enum string[] allowedOutputFormats = [
staticMap!(allowedOutputFormat, EnumMembers!OutputFormat)
];
private OutputFormat parseOutputFormat(string input)
{
switch (input)
{
case "debug":
return OutputFormat.debug_;
case "silent":
return OutputFormat.silent;
default:
throw new Exception("");
}
}
static struct Basic
{
@(NamedArgument
.AllowedValues!allowedOutputFormats
.PreValidation!((string x) => true)
.Parse!parseOutputFormat
.Validation!((OutputFormat x) => true)
)
OutputFormat format;
}
mixin CLI!Basic.main!((args)
{
return 0;
});
I don't mind writing some logic for such edge cases, but it would be nice if it were a bit easier. Defining PreValidation
and Validation
for this looks strange, but the parser doesn't work without it.
argparse/source/argparse/internal/valueparser.d
Lines 149 to 160 in 7bfd802
yes, y, no, and n are accepted in lower case only, but true and false are matched case-insensitively by std.conv.to
. Also, when a parsing error occurs, the message only mentions true/false as allowed values.
I would like to show some information in the epilog, that is not available as compile time constant.
I was playing with rust/clap and one feature I really liked there was, that you can use doc-comments as an alternative to annotations to document flags/commands...
Not sure that its possible to get to the doc-comments in dlang though (I found an old issue: dlang/dmd#6872 where one of the usecases was especially commandline help generation).
struct Parameters
{
@(NamedArgument.Description("1 x"))
string x;
@(NamedArgument.Description("12 ys"))
string yyyyyyyyyyyy;
}
gives a help like
Optional arguments:
-x X 1 x
--yyyyyyyyyyyy YYYYYYYYYYYY
12 ys
-h, --help Show this help message and exit
I would have hoped that the too long parameter is just ignored and the description follows briefly after -h, --help
.
( I had a parameter list with nice descriptions, but the introduction of one long parameter causes an ugly wrapping of the descriptions).
MutuallyExclusive
groups should support having e.g. both arguments required so I can have at least --foo
or --bar
but not both.
For example, either:
@MutuallyExclusive
{
@(
NamedArgument
.Required()
)
bool stdin;
@(
NamedArgument("files", "f")
.Required()
.Description("D source files to scan. You can provide a regex to match multiple files")
)
string[] files;
}
or
@(MutuallyExclusive.Required())
{
@NamedArgument
bool stdin;
@(
NamedArgument("files", "f")
.Description("D source files to scan. You can provide a regex to match multiple files")
)
string[] files;
}
Lets say I want to pass files via arguments or pass a file via stdin
, but I want at least one of the options?
If this is possible, please let me know :)
My CI detects a regression at runtime when bumping 7e08d53 to 1dc7ab5, regardless of the build type or flags.
Error:
core.exception.OutOfMemoryError@core/lifetime.d(126): Memory allocation failed
----------------
(weirdly, no stack trace)
Can't give much more context but I'll keep this up-to-date if any investigation is known.
Fix: dub test --build=unittest-cov-ctfe --verbose
.
I think, apart from being case-sensitive or case-insensitive, there is a third practically useful approach: ignore case in long options but be case-sensitive in short ones. The reason is that it’s fairly common to have one-letter options that differ only in their case. I believe they should not block the ability to match long options case-insensitively.
There is a tricky point, though: how should we process --g
? There are three strategies that are all sane on the first glance:
-g
and -G
exist), emit an error.To understand which one is better, let’s consider this scenario:
-g
flag.--G
.-G
flag.With strategy 1, the user would face an error right on the second step, thus the problem is prevented before it even appeared.
With strategy 2, when the user upgrades their installation, their script will break. The program simply added a new option, and that turned out to be a backwards-incompatible change.
With strategy 3, when the user upgrades, their script will silently begin doing something different.
I hope the point is clear now.
#!/usr/bin/env dub
/+ dub.sdl:
name "argparse_subcommand_bug"
dependency "argparse" version="0.10.0"
+/
import argparse;
import std.stdio: writeln;
struct sum
{
}
struct min
{
}
struct max
{
}
int main_(max cmd)
{
import std.algorithm: maxElement;
writeln("max = ");
return 0;
}
int main_(min cmd)
{
import std.algorithm: minElement;
writeln("min = ");
return 0;
}
int main_(sum cmd)
{
import std.algorithm: sum;
writeln("sum = ");
return 0;
}
// This mixin defines standard main function that parses command line and calls the provided function:
mixin CLI!(sum, min, max).main!main_;
running this program with sum or min as arguments always prints sum.
Currently, if a parsing error occurs, the program exits with code 1; this is hard-coded into the library. However, the program may want to use return code 1 itself and leave another code for the CLI framework. If I understood correctly, to do this, we have to invoke the lower-level parseArgs
manually, check if it returned 1, and if so, distinguish it from the program’s 1 somehow (e.g., by checking a global variable). It feels really hacky for such simple task.
A blog post explaining why having different error codes is important.
For a subcommand, you can affect the description by attributing the command with information.
But I want to just add a description for the whole program. Is that possible to do?
auto myBold = bold;
assert(is(typeof(myBold("text")) == string));
assert(!is(typeof(bold("text")): string)); // Not even convertible.
(That’s because bold()("text")
returns string
while bold("text")
returns StyledText
.)
IMHO, it shouldn’t work like this. Unfortunately, any change in this would be an API change. Is it justified for 2.0?
In case we decide to unify them, we’ll have at least 3 ways:
string
, remove StyledText
altogether.StyledText
, which will be implicitly convertible to string
.StyledText
, which will retain its explicit toString
method.Why do we consider options 2 and 3? Because StyledText
can become a lazy range – and it’ll be possible to rule out allocations of temporary strings:
// Allocates a temporary just to concatenate it; then it immediately becomes garbage.
string msg0 = "argument " ~ bold("name") ~ " is bold";
// Proposed alternative:
auto app = appender!string();
app ~= "argument ";
app ~= bold("name"); // No temporaries; writes directly into the buffer.
app ~= " is bold";
string msg1 = app[];
// The same in one line:
string msg2 = chain("argument ".byCodeUnit, bold("name"), " is bold".byCodeUnit).array();
I think StyledText
can retain its opBinary!"~"
and opBinaryRight!"~"
for convenience: they clearly look like something that allocates. So all the snippets above will be compilable.
The question is, whether or not StyledText
should implicitly convert to string
. To be honest, a lazy range that can implicitly lose its laziness scares me off. I’d prefer option 3.
Implications:
string msg = bold("text").toString()
will continue to work.app ~= config.programName("text")
will continue to work.writeln(config.programName("text"))
will continue to work: writeln
invokes toString
.string msg = config.programName("text") ~ " is bold"
will continue to work.string msg = config.programName("text")
will break with approach 3: an explicit toString
is required, just like in example 1 above.A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.