diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
new file mode 100644
index 0000000..1c37d3d
--- /dev/null
+++ b/.github/workflows/docs.yaml
@@ -0,0 +1,99 @@
+name: Build documentation
+
+on:
+ push:
+ branches: ["master"]
+ pull_request:
+
+# Gives the workflow permissions to clone the repo and create a page deployment
+permissions:
+ id-token: write
+ pages: write
+
+env:
+ # Name of help module and instance id separated by a slash
+ INSTANCE: docs/ad
+ # AD = the ID of the instance in capital letters
+ ARTIFACT: webHelpAD2-all.zip
+ # Writerside docker image version
+ DOCKER_VERSION: 241.15989
+ # Add the variable below to upload Algolia indexes
+ # AD = the ID of the instance in capital letters
+ ALGOLIA_ARTIFACT: algolia-indexes-AD.zip
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Build Writerside docs using Docker
+ uses: JetBrains/writerside-github-action@v4
+ with:
+ instance: ${{ env.INSTANCE }}
+ artifact: ${{ env.ARTIFACT }}
+ docker-version: ${{ env.DOCKER_VERSION }}
+
+ - name: Upload documentation
+ uses: actions/upload-artifact@v4
+ with:
+ name: docs
+ retention-days: 7
+ path: |
+ artifacts/${{ env.ARTIFACT }}
+ artifacts/report.json
+
+ # Add the step below to upload Algolia indexes
+ - name: Upload algolia-indexes
+ uses: actions/upload-artifact@v4
+ with:
+ name: algolia-indexes
+ retention-days: 7
+ path: artifacts/${{ env.ALGOLIA_ARTIFACT }}
+
+ # fail the build when documentation contains errors
+ test:
+ # Requires build job results
+ needs: build
+ runs-on: ubuntu-latest
+ steps:
+ - name: Download artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: docs
+ path: artifacts
+
+ - name: Test documentation
+ uses: JetBrains/writerside-checker-action@v1
+ with:
+ instance: ${{ env.INSTANCE }}
+
+ deploy:
+ if: ${{ github.ref_name == 'master' }}
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ # Requires the test job results
+ needs: test
+ runs-on: ubuntu-latest
+ steps:
+ - name: Download artifact
+ uses: actions/download-artifact@v4
+ with:
+ name: docs
+
+ - name: Unzip artifact
+ run: unzip -O UTF-8 -qq ${{ env.ARTIFACT }} -d dir
+
+ - name: Setup Pages
+ uses: actions/configure-pages@v4
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: dir
+
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index b9c2183..fc0bff6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,6 @@
out/
docs.json
__dummy.html
-docs/
/argparse
argparse.iml
*argparse.so
diff --git a/docs/ad.tree b/docs/ad.tree
new file mode 100644
index 0000000..d4b0130
--- /dev/null
+++ b/docs/ad.tree
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/c.list b/docs/c.list
new file mode 100644
index 0000000..c4c77a2
--- /dev/null
+++ b/docs/c.list
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/cfg/buildprofiles.xml b/docs/cfg/buildprofiles.xml
new file mode 100644
index 0000000..dac9c3c
--- /dev/null
+++ b/docs/cfg/buildprofiles.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ false
+
+
+
+
diff --git a/docs/code_snippets/allowed_values.d b/docs/code_snippets/allowed_values.d
new file mode 100644
index 0000000..24f781b
--- /dev/null
+++ b/docs/code_snippets/allowed_values.d
@@ -0,0 +1,14 @@
+import argparse;
+
+struct T
+{
+ @(NamedArgument.AllowedValues!(["apple","pear","banana"]))
+ string fruit;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["--fruit", "apple"]));
+assert(t == T("apple"));
+
+// "kiwi" is not allowed
+assert(!CLI!T.parseArgs(t, ["--fruit", "kiwi"]));
diff --git a/docs/code_snippets/ansiStylingArgument.d b/docs/code_snippets/ansiStylingArgument.d
new file mode 100644
index 0000000..0230332
--- /dev/null
+++ b/docs/code_snippets/ansiStylingArgument.d
@@ -0,0 +1,20 @@
+import argparse;
+
+struct T
+{
+ static auto color = ansiStylingArgument;
+}
+
+T t;
+CLI!T.parseArgs(t, ["-h"]);
+
+// This is a way to detect whether `--color` argument was specified in the command line
+// Note that 'autodetect' is converted to either 'on' or 'off'
+assert(CLI!T.parseArgs(t, ["--color"]));
+assert(t.color);
+
+assert(CLI!T.parseArgs(t, ["--color=always"]));
+assert(t.color);
+
+assert(CLI!T.parseArgs(t, ["--color=never"]));
+assert(!t.color);
diff --git a/docs/code_snippets/arity.d b/docs/code_snippets/arity.d
new file mode 100644
index 0000000..5a9d7cd
--- /dev/null
+++ b/docs/code_snippets/arity.d
@@ -0,0 +1,13 @@
+import argparse;
+
+struct T
+{
+ @(NamedArgument.NumberOfValues(1,3))
+ int[] a;
+ @(NamedArgument.NumberOfValues(2))
+ int[] b;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-a","1","2","3","-b","4","5"]));
+assert(t == T([1,2,3], [4,5]));
diff --git a/docs/code_snippets/arity_no_values.d b/docs/code_snippets/arity_no_values.d
new file mode 100644
index 0000000..3cb20fc
--- /dev/null
+++ b/docs/code_snippets/arity_no_values.d
@@ -0,0 +1,19 @@
+import argparse;
+
+struct T
+{
+ @(NamedArgument.AllowNoValue !10) int a;
+ @(NamedArgument.RequireNoValue!20) int b;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-a"]));
+assert(t.a == 10);
+
+assert(CLI!T.parseArgs(t, ["-b"]));
+assert(t.b == 20);
+
+assert(CLI!T.parseArgs(t, ["-a","30"]));
+assert(t.a == 30);
+
+assert(!CLI!T.parseArgs(t, ["-b","30"])); // Unrecognized arguments: ["30"]
\ No newline at end of file
diff --git a/docs/code_snippets/call_parser1.d b/docs/code_snippets/call_parser1.d
new file mode 100644
index 0000000..3f8d66e
--- /dev/null
+++ b/docs/code_snippets/call_parser1.d
@@ -0,0 +1,18 @@
+import argparse;
+
+struct T
+{
+ string a;
+ string b;
+}
+
+mixin CLI!T.main!((args)
+{
+ // 'args' has 'T' type
+ static assert(is(typeof(args) == T));
+
+ // do whatever you need
+ import std.stdio: writeln;
+ args.writeln;
+ return 0;
+});
diff --git a/docs/code_snippets/call_parser2.d b/docs/code_snippets/call_parser2.d
new file mode 100644
index 0000000..11b3488
--- /dev/null
+++ b/docs/code_snippets/call_parser2.d
@@ -0,0 +1,27 @@
+import argparse;
+
+struct cmd1
+{
+ string a;
+}
+
+struct cmd2
+{
+ string b;
+}
+
+mixin CLI!(cmd1, cmd2).main!((args, unparsed)
+{
+ // 'args' has either 'cmd1' or 'cmd2' type
+ static if(is(typeof(args) == cmd1))
+ writeln("cmd1: ", args);
+ else static if(is(typeof(args) == cmd2))
+ writeln("cmd2: ", args);
+ else
+ static assert(false); // this would never happen
+
+ // unparsed arguments has 'string[]' type
+ static assert(is(typeof(unparsed) == string[]));
+
+ return 0;
+});
diff --git a/docs/code_snippets/call_parser3.d b/docs/code_snippets/call_parser3.d
new file mode 100644
index 0000000..87d2cdd
--- /dev/null
+++ b/docs/code_snippets/call_parser3.d
@@ -0,0 +1,21 @@
+import argparse;
+
+struct COMMAND
+{
+ string a;
+ string b;
+}
+
+static int my_main(COMMAND command)
+{
+ // Do whatever is needed
+ return 0;
+}
+
+int main(string[] args)
+{
+ // Do initialization here
+ // If needed, termination code can be done as 'scope(exit) { ...code... }' here as well
+
+ return CLI!COMMAND.parseArgs!my_main(args[1..$]);
+}
diff --git a/docs/code_snippets/call_parser4.d b/docs/code_snippets/call_parser4.d
new file mode 100644
index 0000000..63cdb25
--- /dev/null
+++ b/docs/code_snippets/call_parser4.d
@@ -0,0 +1,19 @@
+import argparse;
+
+struct COMMAND
+{
+ string a;
+ string b;
+}
+
+int main(string[] argv)
+{
+ COMMAND cmd;
+
+ if(!CLI!COMMAND.parseArgs(cmd, argv[1..$]))
+ return 1; // parsing failure
+
+ // Do whatever is needed
+
+ return 0;
+}
diff --git a/docs/code_snippets/call_parser5.d b/docs/code_snippets/call_parser5.d
new file mode 100644
index 0000000..70dcb4c
--- /dev/null
+++ b/docs/code_snippets/call_parser5.d
@@ -0,0 +1,13 @@
+import argparse;
+
+struct T
+{
+ string a;
+}
+
+auto arguments = [ "-a", "A", "-c", "C" ];
+
+T result;
+assert(CLI!T.parseKnownArgs(result, arguments));
+assert(result == T("A"));
+assert(arguments == ["-c", "C"]);
diff --git a/docs/code_snippets/config_addHelp.d b/docs/code_snippets/config_addHelp.d
new file mode 100644
index 0000000..0b8a808
--- /dev/null
+++ b/docs/code_snippets/config_addHelp.d
@@ -0,0 +1,18 @@
+import argparse;
+
+struct T
+{
+ string a, b;
+}
+
+T t1;
+CLI!T.parseArgs(t1, ["-a", "A", "-h", "-b", "B"]);
+assert(t1 == T("A"));
+
+enum Config cfg = { addHelp: false };
+
+T t2;
+string[] unrecognizedArgs;
+CLI!(cfg, T).parseKnownArgs(t2, ["-a", "A", "-h", "-b", "B"], unrecognizedArgs);
+assert(t2 == T("A","B"));
+assert(unrecognizedArgs == ["-h"]);
diff --git a/docs/code_snippets/config_arraySep.d b/docs/code_snippets/config_arraySep.d
new file mode 100644
index 0000000..71e03dc
--- /dev/null
+++ b/docs/code_snippets/config_arraySep.d
@@ -0,0 +1,16 @@
+import argparse;
+
+struct T
+{
+ string[] a;
+}
+
+T t1;
+assert(CLI!T.parseArgs(t1, ["-a","1:2:3","-a","4","5"]));
+assert(t1 == T(["1:2:3","4","5"]));
+
+enum Config cfg = { arraySep: ':' };
+
+T t2;
+assert(CLI!(cfg, T).parseArgs(t2, ["-a","1:2:3","-a","4","5"]));
+assert(t2 == T(["1","2","3","4","5"]));
diff --git a/docs/code_snippets/config_assignChar.d b/docs/code_snippets/config_assignChar.d
new file mode 100644
index 0000000..7acda42
--- /dev/null
+++ b/docs/code_snippets/config_assignChar.d
@@ -0,0 +1,12 @@
+import argparse;
+
+struct T
+{
+ string[] a;
+}
+
+enum Config cfg = { assignChar: ':' };
+
+T t;
+assert(CLI!(cfg, T).parseArgs(t, ["-a:1","-a:2","-a:3"]));
+assert(t == T(["1","2","3"]));
diff --git a/docs/code_snippets/config_bundling.d b/docs/code_snippets/config_bundling.d
new file mode 100644
index 0000000..991104a
--- /dev/null
+++ b/docs/code_snippets/config_bundling.d
@@ -0,0 +1,24 @@
+import argparse;
+
+struct T
+{
+ bool a;
+ bool b;
+ string c;
+}
+
+enum Config cfg = { bundling: true };
+
+T t;
+
+assert(CLI!(cfg, T).parseArgs(t, ["-ab"]));
+assert(t == T(true, true));
+
+assert(CLI!(cfg, T).parseArgs(t, ["-abc=foo"]));
+assert(t == T(true, true, "foo"));
+
+assert(CLI!(cfg, T).parseArgs(t, ["-a","-bc=foo"]));
+assert(t == T(true, true, "foo"));
+
+assert(CLI!(cfg, T).parseArgs(t, ["-a","-bcfoo"]));
+assert(t == T(true, true, "foo"));
diff --git a/docs/code_snippets/config_caseSensitive.d b/docs/code_snippets/config_caseSensitive.d
new file mode 100644
index 0000000..9ef060c
--- /dev/null
+++ b/docs/code_snippets/config_caseSensitive.d
@@ -0,0 +1,12 @@
+import argparse;
+
+struct T
+{
+ string[] param;
+}
+
+enum Config cfg = { caseSensitive: false };
+
+T t;
+assert(CLI!(cfg, T).parseArgs(t, ["--param","1","--PARAM","2","--PaRaM","3"]));
+assert(t == T(["1","2","3"]));
diff --git a/docs/code_snippets/config_endOfNamedArgs.d b/docs/code_snippets/config_endOfNamedArgs.d
new file mode 100644
index 0000000..f6a238e
--- /dev/null
+++ b/docs/code_snippets/config_endOfNamedArgs.d
@@ -0,0 +1,14 @@
+import argparse;
+
+struct T
+{
+ @NamedArgument string a;
+ @PositionalArgument(0) string b;
+ @PositionalArgument(1) string[] c;
+}
+
+enum Config cfg = { endOfNamedArgs: "---" };
+
+T t;
+assert(CLI!(cfg, T).parseArgs(t, ["B","-a","foo","---","--","-a","boo"]));
+assert(t == T("foo","B",["--","-a","boo"]));
diff --git a/docs/code_snippets/config_errorHandler.d b/docs/code_snippets/config_errorHandler.d
new file mode 100644
index 0000000..359db9c
--- /dev/null
+++ b/docs/code_snippets/config_errorHandler.d
@@ -0,0 +1,24 @@
+import argparse;
+
+struct T
+{
+ string a;
+}
+
+enum Config cfg = {
+ errorHandler:
+ (text)
+ {
+ try {
+ import std.stdio : stderr;
+ stderr.writeln("Detected an error: ", text);
+ }
+ catch(Exception e)
+ {
+ throw new Error(e.msg);
+ }
+ }
+};
+
+T t;
+assert(!CLI!(cfg, T).parseArgs(t, ["-b"]));
diff --git a/docs/code_snippets/config_namedArgPrefix.d b/docs/code_snippets/config_namedArgPrefix.d
new file mode 100644
index 0000000..230e57d
--- /dev/null
+++ b/docs/code_snippets/config_namedArgPrefix.d
@@ -0,0 +1,13 @@
+import argparse;
+
+struct T
+{
+ string a;
+ string baz;
+}
+
+enum Config cfg = { namedArgPrefix: '+' };
+
+T t;
+assert(CLI!(cfg, T).parseArgs(t, ["+a","foo","++baz","BAZZ"]));
+assert(t == T("foo","BAZZ"));
diff --git a/docs/code_snippets/config_styling.d b/docs/code_snippets/config_styling.d
new file mode 100644
index 0000000..9379785
--- /dev/null
+++ b/docs/code_snippets/config_styling.d
@@ -0,0 +1,13 @@
+import argparse;
+import argparse.ansi;
+
+struct T
+{
+ string a, b;
+}
+
+enum Config cfg = { styling: { programName: blue, argumentName: green.italic } };
+
+T t;
+CLI!(cfg, T).parseArgs(t, ["-a", "A", "-h", "-b", "B"]);
+assert(t == T("A"));
diff --git a/docs/code_snippets/config_stylingMode.d b/docs/code_snippets/config_stylingMode.d
new file mode 100644
index 0000000..683378d
--- /dev/null
+++ b/docs/code_snippets/config_stylingMode.d
@@ -0,0 +1,12 @@
+import argparse;
+
+struct T
+{
+ string a, b;
+}
+
+enum Config cfg = { stylingMode: Config.StylingMode.off };
+
+T t;
+CLI!(cfg, T).parseArgs(t, ["-a", "A", "-h", "-b", "B"]);
+assert(t == T("A"));
diff --git a/docs/code_snippets/double_dash.d b/docs/code_snippets/double_dash.d
new file mode 100644
index 0000000..bccd477
--- /dev/null
+++ b/docs/code_snippets/double_dash.d
@@ -0,0 +1,16 @@
+import argparse;
+
+struct T
+{
+ @NamedArgument
+ string a;
+ @NamedArgument
+ string b;
+
+ @PositionalArgument(0)
+ string[] args;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-a","A","--","-b","B"]));
+assert(t == T("A","",["-b","B"]));
diff --git a/docs/code_snippets/help_argument_group.d b/docs/code_snippets/help_argument_group.d
new file mode 100644
index 0000000..506c74e
--- /dev/null
+++ b/docs/code_snippets/help_argument_group.d
@@ -0,0 +1,29 @@
+import argparse;
+
+@(Command("MYPROG")
+.Description("custom description")
+.Epilog("custom epilog")
+)
+struct T
+{
+ @(ArgumentGroup("group1").Description("group1 description"))
+ {
+ @NamedArgument
+ {
+ string a;
+ string b;
+ }
+ @PositionalArgument(0) string p;
+ }
+
+ @(ArgumentGroup("group2").Description("group2 description"))
+ @NamedArgument
+ {
+ string c;
+ string d;
+ }
+ @PositionalArgument(1) string q;
+}
+
+T t;
+CLI!T.parseArgs(t, ["-h"]);
diff --git a/docs/code_snippets/help_example.d b/docs/code_snippets/help_example.d
new file mode 100644
index 0000000..48ee652
--- /dev/null
+++ b/docs/code_snippets/help_example.d
@@ -0,0 +1,24 @@
+import argparse;
+
+@(Command("MYPROG")
+.Description("custom description")
+.Epilog("custom epilog")
+)
+struct T
+{
+ @NamedArgument string s;
+ @(NamedArgument.Placeholder("VALUE")) string p;
+
+ @(NamedArgument.HideFromHelp) string hidden;
+
+ enum Fruit { apple, pear };
+ @(NamedArgument("f","fruit").Required.Description("This is a help text for fruit. Very very very very very very very very very very very very very very very very very very very long text")) Fruit f;
+
+ @(NamedArgument.AllowedValues!([1,4,16,8])) int i;
+
+ @(PositionalArgument(0).Description("This is a help text for param0. Very very very very very very very very very very very very very very very very very very very long text")) string param0;
+ @(PositionalArgument(1).AllowedValues!(["q","a"])) string param1;
+}
+
+T t;
+CLI!T.parseArgs(t, ["-h"]);
diff --git a/docs/code_snippets/mutually_exclusive.d b/docs/code_snippets/mutually_exclusive.d
new file mode 100644
index 0000000..e5a6f8a
--- /dev/null
+++ b/docs/code_snippets/mutually_exclusive.d
@@ -0,0 +1,20 @@
+import argparse;
+
+struct T
+{
+ @MutuallyExclusive()
+ {
+ string a;
+ string b;
+ }
+}
+
+T t;
+
+// One of them or no argument is allowed
+assert(CLI!T.parseArgs(t, ["-a","a"]));
+assert(CLI!T.parseArgs(t, ["-b","b"]));
+assert(CLI!T.parseArgs(t, []));
+
+// Both arguments or no argument is not allowed
+assert(!CLI!T.parseArgs(t, ["-a","a","-b","b"]));
diff --git a/docs/code_snippets/mutually_exclusive_required.d b/docs/code_snippets/mutually_exclusive_required.d
new file mode 100644
index 0000000..cf7b6a0
--- /dev/null
+++ b/docs/code_snippets/mutually_exclusive_required.d
@@ -0,0 +1,20 @@
+import argparse;
+
+struct T
+{
+ @(MutuallyExclusive.Required)
+ {
+ string a;
+ string b;
+ }
+}
+
+T t;
+
+// Either argument is allowed
+assert(CLI!T.parseArgs(t, ["-a","a"]));
+assert(CLI!T.parseArgs(t, ["-b","b"]));
+
+// Both or no arguments are not allowed
+assert(!CLI!T.parseArgs(t, ["-a","a","-b","b"]));
+assert(!CLI!T.parseArgs(t, []));
diff --git a/docs/code_snippets/mutually_required.d b/docs/code_snippets/mutually_required.d
new file mode 100644
index 0000000..90b74a2
--- /dev/null
+++ b/docs/code_snippets/mutually_required.d
@@ -0,0 +1,20 @@
+import argparse;
+
+struct T
+{
+ @RequiredTogether()
+ {
+ string a;
+ string b;
+ }
+}
+
+T t;
+
+// Both or no argument is allowed
+assert(CLI!T.parseArgs(t, ["-a","a","-b","b"]));
+assert(CLI!T.parseArgs(t, []));
+
+// Only one argument is not allowed
+assert(!CLI!T.parseArgs(t, ["-a","a"]));
+assert(!CLI!T.parseArgs(t, ["-b","b"]));
diff --git a/docs/code_snippets/mutually_required_required.d b/docs/code_snippets/mutually_required_required.d
new file mode 100644
index 0000000..bc9ed61
--- /dev/null
+++ b/docs/code_snippets/mutually_required_required.d
@@ -0,0 +1,20 @@
+import argparse;
+
+struct T
+{
+ @(RequiredTogether.Required)
+ {
+ string a;
+ string b;
+ }
+}
+
+T t;
+
+// Both arguments are allowed
+assert(CLI!T.parseArgs(t, ["-a","a","-b","b"]));
+
+// Single argument or no argument is not allowed
+assert(!CLI!T.parseArgs(t, ["-a","a"]));
+assert(!CLI!T.parseArgs(t, ["-b","b"]));
+assert(!CLI!T.parseArgs(t, []));
diff --git a/docs/code_snippets/named_arguments.d b/docs/code_snippets/named_arguments.d
new file mode 100644
index 0000000..890efae
--- /dev/null
+++ b/docs/code_snippets/named_arguments.d
@@ -0,0 +1,21 @@
+import argparse;
+
+struct Params
+{
+ // If name is not provided then member name is used: "--greeting"
+ @NamedArgument
+ string greeting;
+
+ // If member name is single character then it becomes a short name: "-a"
+ @NamedArgument
+ string a;
+
+ // Argument with multiple names: "--name", "--first-name", "-n"
+ // Note that single character becomes a short name
+ @NamedArgument(["name", "first-name", "n"])
+ string name;
+
+ // Another way to specify multiple names: "--family", "--last-name"
+ @NamedArgument("family", "last-name")
+ string family;
+}
diff --git a/docs/code_snippets/optional_required_arguments.d b/docs/code_snippets/optional_required_arguments.d
new file mode 100644
index 0000000..01796b6
--- /dev/null
+++ b/docs/code_snippets/optional_required_arguments.d
@@ -0,0 +1,14 @@
+import argparse;
+
+struct T
+{
+ @(PositionalArgument(0, "a").Optional)
+ string a = "not set";
+
+ @(NamedArgument.Required)
+ int b;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-b", "4"]));
+assert(t == T("not set", 4));
diff --git a/docs/code_snippets/parsing_customization.d b/docs/code_snippets/parsing_customization.d
new file mode 100644
index 0000000..8d7d721
--- /dev/null
+++ b/docs/code_snippets/parsing_customization.d
@@ -0,0 +1,16 @@
+import argparse;
+
+struct T
+{
+ @(NamedArgument
+ .PreValidation!((string s) { return s.length > 1 && s[0] == '!'; })
+ .Parse !((string s) { return s[1]; })
+ .Validation !((char v) { return v >= '0' && v <= '9'; })
+ .Action !((ref int a, char v) { a = v - '0'; })
+ )
+ int a;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-a","!4"]));
+assert(t == T(4));
diff --git a/docs/code_snippets/positional_arguments.d b/docs/code_snippets/positional_arguments.d
new file mode 100644
index 0000000..2e09089
--- /dev/null
+++ b/docs/code_snippets/positional_arguments.d
@@ -0,0 +1,10 @@
+import argparse;
+
+struct Params
+{
+ @PositionalArgument(0)
+ string firstName;
+
+ @PositionalArgument(1, "lastName")
+ string arg;
+}
diff --git a/docs/code_snippets/styling_helloworld.d b/docs/code_snippets/styling_helloworld.d
new file mode 100644
index 0000000..3a82e3a
--- /dev/null
+++ b/docs/code_snippets/styling_helloworld.d
@@ -0,0 +1,14 @@
+import argparse.ansi;
+
+void printText(bool enableStyle)
+{
+ // style is enabled at runtime when `enableStyle` is true
+ auto myStyle = enableStyle ? bold.italic.cyan.onRed : noStyle;
+
+ // "Hello" is always printed in green;
+ // "world!" is printed in bold, italic, cyan and on red when `enableStyle` is true, or "as is" otherwise
+ writeln(green("Hello "), myStyle("world!"));
+}
+
+printText(true);
+printText(false);
\ No newline at end of file
diff --git a/docs/code_snippets/styling_help.d b/docs/code_snippets/styling_help.d
new file mode 100644
index 0000000..4f30847
--- /dev/null
+++ b/docs/code_snippets/styling_help.d
@@ -0,0 +1,11 @@
+import argparse;
+import argparse.ansi;
+
+struct T
+{
+ @(NamedArgument("red").Description(bold.underline("Colorize the output:")~" make everything "~red("red")))
+ bool red_;
+}
+
+T t;
+CLI!T.parseArgs(t, ["-h"]);
diff --git a/docs/code_snippets/subcommands.d b/docs/code_snippets/subcommands.d
new file mode 100644
index 0000000..cf16b4d
--- /dev/null
+++ b/docs/code_snippets/subcommands.d
@@ -0,0 +1,25 @@
+import argparse;
+
+struct cmd1 {}
+struct cmd2 {}
+struct cmd3 {}
+
+struct T
+{
+ // name of the subcommand is the same as a name of the type by default
+ SubCommand!(cmd1, cmd2, cmd3) cmd;
+}
+
+T t;
+
+assert(CLI!T.parseArgs(t, []));
+assert(t == T.init);
+
+assert(CLI!T.parseArgs(t, ["cmd1"]));
+assert(t == T(typeof(T.cmd)(cmd1.init)));
+
+assert(CLI!T.parseArgs(t, ["cmd2"]));
+assert(t == T(typeof(T.cmd)(cmd2.init)));
+
+assert(CLI!T.parseArgs(t, ["cmd3"]));
+assert(t == T(typeof(T.cmd)(cmd3.init)));
diff --git a/docs/code_snippets/subcommands_common_args.d b/docs/code_snippets/subcommands_common_args.d
new file mode 100644
index 0000000..119a4cd
--- /dev/null
+++ b/docs/code_snippets/subcommands_common_args.d
@@ -0,0 +1,26 @@
+import argparse;
+
+struct min {}
+struct max {}
+struct sum {}
+
+struct T
+{
+ int[] n; // common argument for all subcommands
+
+ // name of the subcommand is the same as a name of the type by default
+ SubCommand!(min, max, sum) cmd;
+}
+
+T t;
+
+assert(CLI!T.parseArgs(t, ["min","-n","1","2","3"]));
+assert(t == T([1,2,3],typeof(T.cmd)(min.init)));
+
+t = T.init;
+assert(CLI!T.parseArgs(t, ["max","-n","4","5","6"]));
+assert(t == T([4,5,6],typeof(T.cmd)(max.init)));
+
+t = T.init;
+assert(CLI!T.parseArgs(t, ["sum","-n","7","8","9"]));
+assert(t == T([7,8,9],typeof(T.cmd)(sum.init)));
diff --git a/docs/code_snippets/subcommands_default.d b/docs/code_snippets/subcommands_default.d
new file mode 100644
index 0000000..83c7720
--- /dev/null
+++ b/docs/code_snippets/subcommands_default.d
@@ -0,0 +1,22 @@
+import argparse;
+
+struct min {}
+struct max {}
+struct sum {}
+
+struct T
+{
+ int[] n; // common argument for all subcommands
+
+ // name of the subcommand is the same as a name of the type by default
+ SubCommand!(min, max, Default!sum) cmd;
+}
+
+T t;
+
+assert(CLI!T.parseArgs(t, ["-n","7","8","9"]));
+assert(t == T([7,8,9],typeof(T.cmd)(sum.init)));
+
+t = T.init;
+assert(CLI!T.parseArgs(t, ["max","-n","4","5","6"]));
+assert(t == T([4,5,6],typeof(T.cmd)(max.init)));
diff --git a/docs/code_snippets/subcommands_enumerate.d b/docs/code_snippets/subcommands_enumerate.d
new file mode 100644
index 0000000..5540109
--- /dev/null
+++ b/docs/code_snippets/subcommands_enumerate.d
@@ -0,0 +1,12 @@
+import argparse;
+
+struct cmd1 {}
+struct cmd2 {}
+struct cmd3 {}
+
+// This mixin defines standard main function that parses command line and calls the provided function:
+mixin CLI!(cmd1, cmd2, cmd3).main!((cmd)
+{
+ import std.stdio;
+ cmd.writeln;
+});
diff --git a/docs/code_snippets/subcommands_names.d b/docs/code_snippets/subcommands_names.d
new file mode 100644
index 0000000..e1f079a
--- /dev/null
+++ b/docs/code_snippets/subcommands_names.d
@@ -0,0 +1,22 @@
+import argparse;
+
+@Command("minimum", "min")
+struct min {}
+@Command("maximum", "max")
+struct max {}
+
+struct T
+{
+ int[] n; // common argument for all subcommands
+
+ SubCommand!(min, max) cmd;
+}
+
+T t;
+
+assert(CLI!T.parseArgs(t, ["minimum","-n","1","2","3"]));
+assert(t == T([1,2,3],typeof(T.cmd)(min.init)));
+
+t = T.init;
+assert(CLI!T.parseArgs(t, ["max","-n","4","5","6"]));
+assert(t == T([4,5,6],typeof(T.cmd)(max.init)));
diff --git a/docs/code_snippets/types_array.d b/docs/code_snippets/types_array.d
new file mode 100644
index 0000000..f94b3d5
--- /dev/null
+++ b/docs/code_snippets/types_array.d
@@ -0,0 +1,14 @@
+import argparse;
+
+struct T
+{
+ int[] a;
+ int[][] b;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-a","1","2","3","-a","4","5"]));
+assert(t.a == [1,2,3,4,5]);
+
+assert(CLI!T.parseArgs(t, ["-b","1","2","3","-b","4","5"]));
+assert(t.b == [[1,2,3],[4,5]]);
diff --git a/docs/code_snippets/types_array_comma.d b/docs/code_snippets/types_array_comma.d
new file mode 100644
index 0000000..c1bf22e
--- /dev/null
+++ b/docs/code_snippets/types_array_comma.d
@@ -0,0 +1,12 @@
+import argparse;
+
+struct T
+{
+ int[] a;
+}
+
+enum Config cfg = { arraySep: ',' };
+
+T t;
+assert(CLI!(cfg, T).parseArgs(t, ["-a=1,2,3","-a","4,5"]));
+assert(t == T([1,2,3,4,5]));
diff --git a/docs/code_snippets/types_assoc_array.d b/docs/code_snippets/types_assoc_array.d
new file mode 100644
index 0000000..2e11093
--- /dev/null
+++ b/docs/code_snippets/types_assoc_array.d
@@ -0,0 +1,10 @@
+import argparse;
+
+struct T
+{
+ int[string] a;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-a=foo=3","-a","boo=7"]));
+assert(t == T(["foo":3,"boo":7]));
diff --git a/docs/code_snippets/types_assoc_array_comma.d b/docs/code_snippets/types_assoc_array_comma.d
new file mode 100644
index 0000000..d597ddf
--- /dev/null
+++ b/docs/code_snippets/types_assoc_array_comma.d
@@ -0,0 +1,12 @@
+import argparse;
+
+struct T
+{
+ int[string] a;
+}
+
+enum Config cfg = { arraySep: ',' };
+
+T t;
+assert(CLI!(cfg, T).parseArgs(t, ["-a=foo=3,boo=7","-a","bar=4,baz=9"]));
+assert(t == T(["foo":3,"boo":7,"bar":4,"baz":9]));
diff --git a/docs/code_snippets/types_counter.d b/docs/code_snippets/types_counter.d
new file mode 100644
index 0000000..19da8ab
--- /dev/null
+++ b/docs/code_snippets/types_counter.d
@@ -0,0 +1,11 @@
+import argparse;
+
+struct T
+{
+ @(NamedArgument.Counter)
+ int v;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-v","-v","-v"]));
+assert(t == T(3));
diff --git a/docs/code_snippets/types_counter_bundling.d b/docs/code_snippets/types_counter_bundling.d
new file mode 100644
index 0000000..ae0c991
--- /dev/null
+++ b/docs/code_snippets/types_counter_bundling.d
@@ -0,0 +1,13 @@
+import argparse;
+
+struct T
+{
+ @(NamedArgument.Counter)
+ int v;
+}
+
+enum Config cfg = { bundling: true };
+
+T t;
+assert(CLI!(cfg, T).parseArgs(t, ["-vv","-v"]));
+assert(t == T(3));
diff --git a/docs/code_snippets/types_custom.d b/docs/code_snippets/types_custom.d
new file mode 100644
index 0000000..5b719f1
--- /dev/null
+++ b/docs/code_snippets/types_custom.d
@@ -0,0 +1,15 @@
+import argparse;
+
+struct Value
+{
+ string a;
+}
+struct T
+{
+ @(NamedArgument.Parse!((string s) { return Value(s); }))
+ Value s;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-s","foo"]));
+assert(t == T(Value("foo")));
\ No newline at end of file
diff --git a/docs/code_snippets/types_enum.d b/docs/code_snippets/types_enum.d
new file mode 100644
index 0000000..a8677cb
--- /dev/null
+++ b/docs/code_snippets/types_enum.d
@@ -0,0 +1,15 @@
+import argparse;
+
+struct T
+{
+ enum Fruit { apple, pear };
+
+ Fruit a;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-a","apple"]));
+assert(t == T(T.Fruit.apple));
+
+assert(CLI!T.parseArgs(t, ["-a=pear"]));
+assert(t == T(T.Fruit.pear));
diff --git a/docs/code_snippets/types_enum_custom_values.d b/docs/code_snippets/types_enum_custom_values.d
new file mode 100644
index 0000000..b488718
--- /dev/null
+++ b/docs/code_snippets/types_enum_custom_values.d
@@ -0,0 +1,19 @@
+import argparse;
+
+struct T
+{
+ enum Fruit {
+ apple,
+ @ArgumentValue("no-apple","noapple")
+ noapple
+ };
+
+ Fruit a;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-a=no-apple"]));
+assert(t == T(T.Fruit.noapple));
+
+assert(CLI!T.parseArgs(t, ["-a","noapple"]));
+assert(t == T(T.Fruit.noapple));
diff --git a/docs/code_snippets/types_function.d b/docs/code_snippets/types_function.d
new file mode 100644
index 0000000..b695478
--- /dev/null
+++ b/docs/code_snippets/types_function.d
@@ -0,0 +1,21 @@
+import argparse;
+
+struct T
+{
+ int a_;
+ string[] b_;
+ string[][] c_;
+
+ @NamedArgument
+ {
+ void a() { a_++; }
+ void b(string s) { b_ ~= s; }
+ void c(string[] s) { c_ ~= s; }
+ }
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-a","-b","1","-c","q","w",
+ "-a","-b","2","-c","e","r",
+ "-a","-b","3","-c","t","y",]));
+assert(t == T(3, ["1","2","3"], [["q","w"],["e","r"],["t","y"]]));
diff --git a/docs/code_snippets/types_number_string.d b/docs/code_snippets/types_number_string.d
new file mode 100644
index 0000000..a5ec910
--- /dev/null
+++ b/docs/code_snippets/types_number_string.d
@@ -0,0 +1,15 @@
+import argparse;
+
+struct T
+{
+ int i;
+ uint u;
+ double f;
+ string s;
+ wstring w;
+ dstring d;
+}
+
+T t;
+assert(CLI!T.parseArgs(t, ["-i","-5","-u","8","-f","12.345","-s","sss","-w","www","-d","ddd"]));
+assert(t == T(-5,8,12.345,"sss","www","ddd"));
diff --git a/docs/images/allowed_values_error.png b/docs/images/allowed_values_error.png
new file mode 100644
index 0000000..82ad184
Binary files /dev/null and b/docs/images/allowed_values_error.png differ
diff --git a/docs/images/allowed_values_error_dark.png b/docs/images/allowed_values_error_dark.png
new file mode 100644
index 0000000..56bba60
Binary files /dev/null and b/docs/images/allowed_values_error_dark.png differ
diff --git a/docs/images/ansiStylingArgument.png b/docs/images/ansiStylingArgument.png
new file mode 100644
index 0000000..fc3aca7
Binary files /dev/null and b/docs/images/ansiStylingArgument.png differ
diff --git a/docs/images/ansiStylingArgument_dark.png b/docs/images/ansiStylingArgument_dark.png
new file mode 100644
index 0000000..22109f3
Binary files /dev/null and b/docs/images/ansiStylingArgument_dark.png differ
diff --git a/docs/images/config_help.png b/docs/images/config_help.png
new file mode 100644
index 0000000..fc60413
Binary files /dev/null and b/docs/images/config_help.png differ
diff --git a/docs/images/config_help_dark.png b/docs/images/config_help_dark.png
new file mode 100644
index 0000000..15e34ec
Binary files /dev/null and b/docs/images/config_help_dark.png differ
diff --git a/docs/images/config_styling.png b/docs/images/config_styling.png
new file mode 100644
index 0000000..3fbadcf
Binary files /dev/null and b/docs/images/config_styling.png differ
diff --git a/docs/images/config_stylingMode.png b/docs/images/config_stylingMode.png
new file mode 100644
index 0000000..c82d168
Binary files /dev/null and b/docs/images/config_stylingMode.png differ
diff --git a/docs/images/config_stylingMode_dark.png b/docs/images/config_stylingMode_dark.png
new file mode 100644
index 0000000..6271ffd
Binary files /dev/null and b/docs/images/config_stylingMode_dark.png differ
diff --git a/docs/images/config_styling_dark.png b/docs/images/config_styling_dark.png
new file mode 100644
index 0000000..010e585
Binary files /dev/null and b/docs/images/config_styling_dark.png differ
diff --git a/docs/images/default_styling.png b/docs/images/default_styling.png
new file mode 100644
index 0000000..43e1831
Binary files /dev/null and b/docs/images/default_styling.png differ
diff --git a/docs/images/default_styling_dark.png b/docs/images/default_styling_dark.png
new file mode 100644
index 0000000..2056906
Binary files /dev/null and b/docs/images/default_styling_dark.png differ
diff --git a/docs/images/hello_world_with_uda.png b/docs/images/hello_world_with_uda.png
new file mode 100644
index 0000000..f99d2f1
Binary files /dev/null and b/docs/images/hello_world_with_uda.png differ
diff --git a/docs/images/hello_world_with_uda_dark.png b/docs/images/hello_world_with_uda_dark.png
new file mode 100644
index 0000000..a1d18d9
Binary files /dev/null and b/docs/images/hello_world_with_uda_dark.png differ
diff --git a/docs/images/hello_world_without_uda.png b/docs/images/hello_world_without_uda.png
new file mode 100644
index 0000000..890c1c6
Binary files /dev/null and b/docs/images/hello_world_without_uda.png differ
diff --git a/docs/images/hello_world_without_uda_dark.png b/docs/images/hello_world_without_uda_dark.png
new file mode 100644
index 0000000..1a0661f
Binary files /dev/null and b/docs/images/hello_world_without_uda_dark.png differ
diff --git a/docs/images/help_argument_group.png b/docs/images/help_argument_group.png
new file mode 100644
index 0000000..607ee3d
Binary files /dev/null and b/docs/images/help_argument_group.png differ
diff --git a/docs/images/help_argument_group_dark.png b/docs/images/help_argument_group_dark.png
new file mode 100644
index 0000000..23be326
Binary files /dev/null and b/docs/images/help_argument_group_dark.png differ
diff --git a/docs/images/help_example.png b/docs/images/help_example.png
new file mode 100644
index 0000000..1ff3d8f
Binary files /dev/null and b/docs/images/help_example.png differ
diff --git a/docs/images/help_example1.png b/docs/images/help_example1.png
new file mode 100644
index 0000000..08591e7
Binary files /dev/null and b/docs/images/help_example1.png differ
diff --git a/docs/images/help_example1_dark.png b/docs/images/help_example1_dark.png
new file mode 100644
index 0000000..7de7e97
Binary files /dev/null and b/docs/images/help_example1_dark.png differ
diff --git a/docs/images/help_example_dark.png b/docs/images/help_example_dark.png
new file mode 100644
index 0000000..dff12f8
Binary files /dev/null and b/docs/images/help_example_dark.png differ
diff --git a/docs/images/styling_help.png b/docs/images/styling_help.png
new file mode 100644
index 0000000..db2faa5
Binary files /dev/null and b/docs/images/styling_help.png differ
diff --git a/docs/images/styling_help_dark.png b/docs/images/styling_help_dark.png
new file mode 100644
index 0000000..09717ac
Binary files /dev/null and b/docs/images/styling_help_dark.png differ
diff --git a/docs/redirection-rules.xml b/docs/redirection-rules.xml
new file mode 100644
index 0000000..e9206e6
--- /dev/null
+++ b/docs/redirection-rules.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+ Created after removal of "Param and RawParam" from argparse documentation
+ Param-and-RawParam.html
+
+
+ Created after removal of "ANSI styling" from argparse documentation
+ ANSI-styling.html
+
+
+ Created after removal of "ANSI colors and styles" from argparse documentation
+ ANSI-colors-and-styles.html
+
+
+ Created after removal of "Without User-Defined Attributes" from argparse documentation
+
+ Without-User-Defined-Attributes.html
+
+
+ Created after removal of "With User-Defined Attributes" from argparse documentation
+ With-User-Defined-Attributes.html
+
+
+ Created after removal of "About argparse documentation" from argparse documentation
+ starter-topic.html
+
+
+ Created after removal of "Default" from argparse documentation
+ Default.html
+
+
\ No newline at end of file
diff --git a/docs/topics/ANSI-coloring-and-styling.md b/docs/topics/ANSI-coloring-and-styling.md
new file mode 100644
index 0000000..efae02c
--- /dev/null
+++ b/docs/topics/ANSI-coloring-and-styling.md
@@ -0,0 +1,98 @@
+# ANSI coloring and styling
+
+Using colors in the command line tool’s output does not just look good: **contrasting** important elements like argument
+names from the rest of the text **reduces the cognitive load** on the user. `argparse` uses [ANSI escape sequences](https://en.wikipedia.org/wiki/ANSI_escape_code)
+to add coloring and styling to the error messages and help text. In addition, `argparse` offers public API to apply
+colors and styles to any text printed to the console (see below).
+
+> Coloring and styling API is provided in a separate `argparse.ansi` submodule. It has no dependencies on other parts of
+> `argparse` so can be easily used in any other parts of a program unrelated to command line parsing.
+>
+{style="tip"}
+
+
+
+## Styles and colors
+
+The following styles and colors are available in `argparse.ansi` submodule:
+
+**Font styles:**
+- `bold`
+- `italic`
+- `underline`
+
+**Colors:**
+
+| **Foreground** | **Background** |
+|----------------|------------------|
+| `black` | `onBlack` |
+| `red` | `onRed` |
+| `green` | `onGreen` |
+| `yellow` | `onYellow` |
+| `blue` | `onBlue` |
+| `magenta` | `onMagenta` |
+| `cyan` | `onCyan` |
+| `lightGray` | `onLightGray` |
+| `darkGray` | `onDarkGray` |
+| `lightRed` | `onLightRed` |
+| `lightGreen` | `onLightGreen` |
+| `lightYellow` | `onLightYellow` |
+| `lightBlue` | `onLightBlue` |
+| `lightMagenta` | `onLightMagenta` |
+| `lightCyan` | `onLightCyan` |
+| `white` | `onWhite` |
+
+There is also a “virtual” style `noStyle` that means no styling is applied. It’s useful in ternary operations as a fallback
+for the case when styling is disabled. See below example for details.
+
+All styles above can be combined using `.` and even be used in regular output:
+
+
+
+The following example shows how styling can be used in custom help text (`Usage`, `Description`, `ShortDescription`, `Epilog` API):
+
+
+
+Here is how help screen will look like:
+
+
+
+
+## Enable/disable the styling
+
+By default `argparse` will try to detect whether ANSI styling is supported, and if so, it will apply styling to the help text.
+
+There is `Config.stylingMode` parameter that can be used to override default behavior:
+- If it’s set to `Config.StylingMode.on`, then styling is **always enabled**.
+- If it’s set to `Config.StylingMode.off`, then styling is **always disabled**.
+- If it’s set to `Config.StylingMode.autodetect`, then [heuristics](#heuristic) are used to determine
+ whether styling will be applied.
+
+In some cases styling control should be exposed to a user as a command line argument (similar to `--color` argument in `ls` or `grep` command).
+`argparse` supports this use case – just add an argument to a command (it can be customized with `@NamedArgument` UDA):
+
+
+
+This will add the following argument:
+
+
+
+
+## Heuristics for enabling styling {id="heuristic"}
+
+Below is the exact sequence of steps `argparse` uses to determine whether or not to emit ANSI escape codes
+(see detectSupport() function [here](https://github.com/andrey-zherikov/argparse/blob/master/source/argparse/ansi.d) for details):
+
+1. If environment variable `NO_COLOR != ""`, then styling is **disabled**. See [here](https://no-color.org/) for details.
+2. If environment variable `CLICOLOR_FORCE != "0"`, then styling is **enabled**. See [here](https://bixense.com/clicolors/) for details.
+3. If environment variable `CLICOLOR == "0"`, then styling is **disabled**. See [here](https://bixense.com/clicolors/) for details.
+4. If environment variable `ConEmuANSI == "OFF"`, then styling is **disabled**. See [here](https://conemu.github.io/en/AnsiEscapeCodes.html#Environment_variable) for details.
+5. If environment variable `ConEmuANSI == "ON"`, then styling is **enabled**. See [here](https://conemu.github.io/en/AnsiEscapeCodes.html#Environment_variable) for details.
+6. If environment variable `ANSICON` is defined (regardless of its value), then styling is **enabled**. See [here](https://github.com/adoxa/ansicon/blob/master/readme.txt) for details.
+7. **Windows only** (`version(Windows)`):
+ 1. If environment variable `TERM` contains `"cygwin"` or starts with `"xterm"`, then styling is **enabled**.
+ 2. If `GetConsoleMode` call for `STD_OUTPUT_HANDLE` returns a mode that has `ENABLE_VIRTUAL_TERMINAL_PROCESSING` set, then styling is **enabled**.
+ 3. If `SetConsoleMode` call for `STD_OUTPUT_HANDLE` with `ENABLE_VIRTUAL_TERMINAL_PROCESSING` mode was successful, then styling is **enabled**.
+8. **Posix only** (`version(Posix)`):
+ 1. If `STDOUT` is **not** redirected, then styling is **enabled**.
+9. If none of the above applies, then styling is **disabled**.
diff --git a/docs/topics/Argument-dependencies.md b/docs/topics/Argument-dependencies.md
new file mode 100644
index 0000000..dcf2115
--- /dev/null
+++ b/docs/topics/Argument-dependencies.md
@@ -0,0 +1,30 @@
+# Argument dependencies
+
+## Mutually exclusive arguments {id="MutuallyExclusive"}
+
+Mutually exclusive arguments (i.e., those that can’t be used together) can be declared using `MutuallyExclusive()` UDA:
+
+
+
+> Parentheses `()` are required for this UDA to work correctly.
+>
+{style="warning"}
+
+Set of mutually exclusive arguments can be marked as required in order to require exactly one of the arguments:
+
+
+
+
+## Mutually required arguments {id="RequiredTogether"}
+
+Mutually required arguments (i.e., those that require other arguments) can be declared using `RequiredTogether()` UDA:
+
+
+
+> Parentheses `()` are required for this UDA to work correctly.
+>
+{style="warning"}
+
+Set of mutually required arguments can be marked as required in order to require all arguments:
+
+
diff --git a/docs/topics/Arguments-bundling.md b/docs/topics/Arguments-bundling.md
new file mode 100644
index 0000000..ac0e668
--- /dev/null
+++ b/docs/topics/Arguments-bundling.md
@@ -0,0 +1,10 @@
+# Arguments bundling
+
+Some command line tools allow bundling of single-character argument names in a form of `-abc` where `a`, `b` and `c` are
+separate arguments. `argparse` supports this through [`Config.bundling`](Config.md#bundling) setting and allows the following usages:
+
+
+
+To explain what happens under the hood, let's consider that a command line has `-abc` entry and there is no `abc` argument.
+In this case, `argparse` tries to parse it as `-a bc` if there is an `a` argument and it accepts a value, or as `-a -bc`
+if there is an `a` argument and it does not accept any value. In case if there is no `a` argument, `argparse` will error out.
diff --git a/docs/topics/Arguments.md b/docs/topics/Arguments.md
new file mode 100644
index 0000000..d217ffa
--- /dev/null
+++ b/docs/topics/Arguments.md
@@ -0,0 +1,4 @@
+# Arguments
+
+Command line usually consists of arguments that can be separated into _named arguments_ and _positional arguments_.
+There is no restriction that one should be before another one so they may be mixed in command line.
diff --git a/docs/topics/Arity.md b/docs/topics/Arity.md
new file mode 100644
index 0000000..03a7f68
--- /dev/null
+++ b/docs/topics/Arity.md
@@ -0,0 +1,49 @@
+# Arity
+
+Sometimes an argument might accept more than one value. This is especially a case when a data member is an array.
+
+`argparse` supports these use cases:
+- Exact number of values.
+- Limited range of minimum-maximum number of values.
+- Unlimited range where only minimum number of values is provided (e.g. argument accepts _any number_ of values).
+
+To adjust the arity, use one the following API:
+- `NumberOfValues(ulong min, ulong max)` – sets both minimum and maximum number of values.
+- `NumberOfValues(ulong num)` – sets the exact number of values.
+- `MinNumberOfValues(ulong min)` – sets minimum number of values.
+- `MaxNumberOfValues(ulong max)` – sets maximum number of values.
+
+> Positional argument must have at least one value.
+>
+{style="warning"}
+
+Example:
+
+
+
+## Default arity
+
+| Type | Default arity | Notes |
+|-----------------------|:---------------:|-----------------------------------------------------------------------------------------------------------------------------|
+| `bool` | 0 | Boolean flags do not accept values with the only exception when they are specified in `--flag=true` format in command line. |
+| String or scalar | 1 | Exactly one value is accepted. |
+| Static array | Length of array | If a range is desired then use provided API to adjust arity. |
+| Dynamic array | 1 ... ∞ | |
+| Associative array | 1 ... ∞ | |
+| `function ()` | 0 | Same as boolean flag. |
+| `function (string)` | 1 | Same as `string`. |
+| `function (string[])` | 1 ... ∞ | Same as `string[]` array. |
+| `function (RawParam)` | 1 ... ∞ | Same as `string[]` array. |
+
+## Named arguments with no values
+
+Sometimes named arguments are can have no values in command line. Here are two cases that arise in this situation:
+
+- Argument should get specific value if there is no value provided in command line. Use `AllowNoValue` in this case.
+
+- Argument must not have any values in command line. Use `RequireNoValue` in this case.
+
+Both `AllowNoValue` and `RequireNoValue` accept a value that should be used when no value is provided in the command line.
+The difference between them can be seen in this example:
+
+
diff --git a/docs/topics/Calling-the-parser.md b/docs/topics/Calling-the-parser.md
new file mode 100644
index 0000000..66aebe0
--- /dev/null
+++ b/docs/topics/Calling-the-parser.md
@@ -0,0 +1,119 @@
+# Calling the parser
+
+`argparse` provides `CLI` template to call the parser covering different use cases. It has the following signatures:
+- `template CLI(Config config, COMMAND)` – this is main template that provides multiple API (see below) for all
+ supported use cases.
+- `template CLI(Config config, COMMANDS...)` – convenience wrapper of the previous template that provides `main`
+ template mixin only for the simplest use case with subcommands. See [Subcommands](Subcommands.md) section for details.
+- `alias CLI(COMMANDS...) = CLI!(Config.init, COMMANDS)` – alias provided for convenience that allows using default
+ `Config`, i.e., `config = Config.init`.
+
+## Wrapper for `main` function
+
+The recommended and most convenient way to use `argparse` is through `CLI!(...).main(alias newMain)` mixin template.
+It declares the standard `main` function that parses command line arguments and calls provided `newMain` function with
+an object that contains parsed arguments.
+
+`newMain` function must satisfy these requirements:
+- It must accept `COMMAND` type as a first parameter if `CLI` template is used with one `COMMAND`.
+- It must accept all `COMMANDS` types as a first parameter if `CLI` template is used with multiple `COMMANDS...`.
+ `argparse` uses `std.sumtype.match` for matching. Possible implementation of such `newMain` function would be a
+ function that is overridden for every command type from `COMMANDS`. Another example would be a lambda that does
+ compile-time checking of the type of the first parameter (see examples below for details).
+- Optionally `newMain` function can take a `string[]` parameter as a second argument. Providing such a function will
+ mean that `argparse` will parse known arguments only and all unknown ones will be passed into the second parameter of
+ `newMain` function. If `newMain` function doesn’t have such parameter, then `argparse` will error out if there is an
+ unknown argument provided in command line.
+- Optionally `newMain` can return a result that can be cast to `int`. In this case, this result will be returned from
+ standard `main` function.
+
+**Usage examples:**
+
+
+
+
+
+
+## Call parser with custom `main` function
+
+In the case when wrapping of standard `main` function does not fit the needs (e.g., some initialization has to be done before parsing
+the command line), `argparse` offers `CLI!(...).parseArgs` function:
+
+`int parseArgs(alias newMain)(string[] args, COMMAND initialValue = COMMAND.init)`
+
+**Parameters:**
+
+- `newMain` – function that’s called with object of type `COMMAND` as a first parameter that is filled with the data parsed from
+ command line; optionally it can take `string[]` as a second parameter which will contain unknown arguments
+ (see [Wrapper for main function](#wrapper-for-main-function) section for details).
+- `args` – raw command line arguments (excluding `argv[0]` – first command line argument in `main` function).
+- `initialValue` – initial value for the object passed to `newMain` function.
+
+**Return value:**
+
+If there is an error happened during the parsing, then non-zero value is returned. In case of no error, if `newMain`
+function returns a value that can be cast to `int`, then this value is returned, or `0` otherwise.
+
+**Usage example:**
+
+
+
+
+## Low-level calling of parser
+
+For the cases when providing `newMain` function is not possible or feasible, `parseArgs` function can accept a reference
+to an object that receives the values of command line arguments:
+
+`Result parseArgs(ref COMMAND receiver, string[] args)`
+
+**Parameters:**
+
+- `receiver` – object that is populated with parsed values.
+- `args` – raw command line arguments (excluding `argv[0]` – first command line argument in `main` function).
+
+**Return value:**
+
+An object that can be cast to `bool` to check whether the parsing was successful or not.
+
+> Note that this function will error out if command line contains unknown arguments.
+>
+{style="warning"}
+
+**Usage example:**
+
+
+
+
+## Partial argument parsing
+
+Sometimes a program may only parse a few of the command line arguments and process the remaining arguments in some different
+way. In these cases, `CLI!(...).parseKnownArgs` function can be used. It works much like `CLI!(...).parseArgs` except
+that it does not produce an error when unknown arguments are present. It has the following signatures:
+
+- `Result parseKnownArgs(ref COMMAND receiver, string[] args, out string[] unrecognizedArgs)`
+
+ **Parameters:**
+
+ - `receiver` – the object that’s populated with parsed values.
+ - `args` – raw command line arguments (excluding `argv[0]` – first command line argument in `main` function).
+ - `unrecognizedArgs` – raw command line arguments that were not parsed.
+
+ **Return value:**
+
+ An object that can be cast to `bool` to check whether the parsing was successful or not.
+
+- `Result parseKnownArgs(ref COMMAND receiver, ref string[] args)`
+
+ **Parameters:**
+
+ - `receiver` – the object that’s populated with parsed values.
+ - `args` – raw command line arguments that are modified to have parsed arguments removed (excluding `argv[0]` – first
+ command line argument in `main` function).
+
+ **Return value:**
+
+ An object that can be cast to `bool` to check whether the parsing was successful or not.
+
+**Usage example:**
+
+
diff --git a/docs/topics/End-of-named-arguments.md b/docs/topics/End-of-named-arguments.md
new file mode 100644
index 0000000..ea76ff4
--- /dev/null
+++ b/docs/topics/End-of-named-arguments.md
@@ -0,0 +1,7 @@
+# End of named arguments
+
+When the command line contains an entry that is equal to [`Config.endOfNamedArgs`](Config.md#endOfNamedArgs)
+(double dash `--` by default), `argparse` interprets all following command line entries as positional arguments, even
+if they can match a named argument or a subcommand.
+
+
diff --git a/docs/topics/Getting-started.md b/docs/topics/Getting-started.md
new file mode 100644
index 0000000..3a64eea
--- /dev/null
+++ b/docs/topics/Getting-started.md
@@ -0,0 +1,25 @@
+# Getting started
+
+`argparse` provides User-Defined Attributes (UDA) that can be used to annotate `struct` members that are part of
+command line interface.
+
+## Without User-Defined Attributes
+
+Using UDAs is not required and if a `struct` has no UDAs then all data members are treated as named command line
+arguments:
+
+
+
+Running the program above with `-h` argument will have the following output:
+
+
+
+## With User-Defined Attributes
+
+Although UDA-less approach is useful as a starting point, it's not enough for real command line tool:
+
+
+
+Running the program above with `-h` argument will have the following output:
+
+
diff --git a/docs/topics/Help-generation.md b/docs/topics/Help-generation.md
new file mode 100644
index 0000000..117ec0c
--- /dev/null
+++ b/docs/topics/Help-generation.md
@@ -0,0 +1,67 @@
+# Help generation
+
+
+## Command
+
+`Command` UDA provides few customizations that affect help text. It can be used for **top-level command** and **subcommands**.
+
+- Program name (i.e., the name of top-level command) and subcommand name can be provided to `Command` UDA as a parameter.
+ If program name is not provided, then `Runtime.args[0]` (a.k.a. `argv[0]` from `main` function) is used.
+ If subcommand name is not provided (e.g., `@(Command.Description(...))`), then the name of the type that represents the command is used.
+- `Usage` – allows custom usage text. By default, the parser calculates the usage message from the arguments it contains
+ but this can be overridden with `Usage` call. If the custom text contains `%(PROG)` then it will be replaced by the
+ command/program name.
+- `Description` – used to provide a description of what the command/program does and how it works. In help messages, the
+ description is displayed between the usage string and the list of the command arguments.
+- `ShortDescription` – used to provide a brief description of what the subcommand does. It is applicable to subcommands
+ only and is displayed in *Available commands* section on help screen of the parent command.
+- `Epilog` – custom text that is printed after the list of the arguments.
+
+`Usage`, `Description`, `ShortDescription` and `Epilog` modifiers take either `string` or `string function()`
+value – the latter can be used to return a value that is not known at compile time.
+
+## Argument
+
+There are some customizations supported on argument level for both `PositionalArgument` and `NamedArgument` UDAs:
+
+- `Description` – provides brief description of the argument. This text is printed next to the argument
+ in the argument-list section of a help message. `Description` takes either `string` or `string function()`
+ value – the latter can be used to return a value that is not known at compile time.
+- `HideFromHelp` – can be used to indicate that the argument shouldn’t be printed in help message.
+- `Placeholder` – provides custom text that is used to indicate the value of the argument in help message.
+
+## Help text styling
+
+`argparse` uses `Config.styling` to determine what style should be applied to different parts of the help text.
+Please refer to [ANSI coloring and styling](ANSI-coloring-and-styling.md) section for details.
+
+## Example
+
+Here is an example of how this customization can be used:
+
+
+
+This example will print the following help message:
+
+
+
+## Argument groups
+
+By default, parser groups command line arguments into “required arguments” and “optional arguments” when displaying help
+message. When there is a better conceptual grouping of arguments than this default one, appropriate groups can be
+created using `ArgumentGroup` UDA.
+
+This UDA has some customization for displaying help text:
+
+- `Description` – provides brief description of the group. This text is printed right after group name.
+ It takes either `string` or `string function()` value – the latter can be used to return a value that is not known
+ at compile time.
+
+Example:
+
+
+
+When an argument is attributed with a group, the parser treats it just like a normal argument, but displays the argument
+in a separate group for help messages:
+
+
diff --git a/docs/topics/Introduction.md b/docs/topics/Introduction.md
new file mode 100644
index 0000000..ce8f1f2
--- /dev/null
+++ b/docs/topics/Introduction.md
@@ -0,0 +1,20 @@
+# Introduction
+
+`argparse` is a flexible parser of command line arguments that allows easy creation of terminal applications with rich
+command line interface.
+
+## Features
+
+`argparse` provides a lot of features to support different use cases:
+- Positional arguments
+- Named arguments
+- Argument grouping
+- Subcommands
+- Built-in help screen
+- ANSI colors and styles
+- Shell completion
+- Support for different types, for example: scalars, enums, arrays, associative arrays, callbacks
+
+Example of help screen with ANSI colors and styles:
+
+
diff --git a/docs/topics/Named-arguments.md b/docs/topics/Named-arguments.md
new file mode 100644
index 0000000..cba98ac
--- /dev/null
+++ b/docs/topics/Named-arguments.md
@@ -0,0 +1,30 @@
+# Named arguments
+
+_Named arguments_ (they are also called as flags or options) have one or more name that can be separated into two categories:
+- _Short names_ are those that start with single dash `-` (see [`Config.namedArgPrefix`](Config.md#namedArgPrefix) for customization).
+- _Long names_ start with double dash `--` (see [`Config.namedArgPrefix`](Config.md#namedArgPrefix) for customization).
+
+Both cases are fully supported with one caveat:
+if a single-character argument is used with a double dash (e.g., `--n`) in command line, then it behaves the same as a
+multi-character argument.
+
+The following usages of the argument in the command line are equivalent:
+- `--name John`
+- `--name=John`
+- `--n John`
+- `--n=John`
+- `-n John`
+- `-n=John`
+- `-nJohn` - this works for single-character names only
+
+> Any other character can be used instead of `=` – see [`Config.assignChar`](Config.md#assignChar) for details.
+
+_Named arguments_ can be declared using `NamedArgument` UDA which has the following parameters:
+
+| # | Name | Type | Optional/
Required | Description |
+|---|--------|------------------------|------------------------|------------------------------------------------------------|
+| 1 | `name` | `string` or `string[]` | optional | Name(s) of this argument that can show up in command line. |
+
+Example:
+
+
diff --git a/docs/topics/Optional-and-required-arguments.md b/docs/topics/Optional-and-required-arguments.md
new file mode 100644
index 0000000..830ceb6
--- /dev/null
+++ b/docs/topics/Optional-and-required-arguments.md
@@ -0,0 +1,10 @@
+# Optional and required arguments
+
+Arguments can be marked as required or optional by adding `.Required` or `.Optional` to UDA. If required argument is
+not present in command line, `argparse` will error out.
+
+By default, _positional arguments_ are **required** and _named arguments_ are **optional**.
+
+Example:
+
+
diff --git a/docs/topics/Parsing-customization.md b/docs/topics/Parsing-customization.md
new file mode 100644
index 0000000..c503c3c
--- /dev/null
+++ b/docs/topics/Parsing-customization.md
@@ -0,0 +1,135 @@
+# Parsing customization
+
+Sometime the functionality that is provided out of the box is not enough and needs to be tuned.
+`argparse` allows customizing of every step of command line parsing:
+
+- **Pre-validation** – argument values are validated as raw strings.
+- **Parsing** – raw argument values are converted to a different type (usually the type of the receiving data member).
+- **Validation** – converted value is validated.
+- **Action** – depending on a type of the receiving data member, for example, it can be an assignment of converted value to a
+ data member, or appending value if type is an array.
+
+In case if argument does not have any value to parse, then the only one step is involved in parsing:
+
+- **Action if no value** – similar to **Action** step above but without converted value.
+
+> If any of the steps above fails, then the command line parsing fails as well.
+>
+{style="note"}
+
+Each of the steps above can be customized with UDA modifiers below.
+
+## Pre-validation {id="PreValidation"}
+
+`PreValidation` modifier can be used to customize the validation of raw string values. It accepts a function with one of
+the following signatures:
+
+- `bool validate(string value)`
+
+ `Result validate(string value)`
+
+ > In this case, function will be called once for every value specified in command line for an argument in case of multiple values.
+ >
+ {style="note"}
+
+- `bool validate(string[] value)`
+
+ `Result validate(string[] value)`
+
+- `bool validate(RawParam param)`
+
+ `Result validate(RawParam param)`
+
+Parameters:
+
+- `value`/`param` values to be parsed.
+
+Return value:
+
+- `true`/`Result.Success` if validation passed or
+- `false`/`Result.Error` otherwise.
+
+## Parsing {id="Parse"}
+
+`Parse` modifier allows providing custom conversion from raw string to a typed value. It accepts a function with one of
+the following signatures:
+
+- `ParseType parse(string value)`
+- `ParseType parse(string[] value)`
+- `ParseType parse(RawParam param)`
+- `bool parse(ref ParseType receiver, RawParam param)`
+- `void parse(ref ParseType receiver, RawParam param)`
+- `Result parse(ref ParseType receiver, RawParam param)`
+
+> `ParseType` is a type that a string value is supposed to be parsed to and it is not required be the same as
+a type of destination - `argparse` tries to detect this type from provided function.
+>
+{title="ParseType"}
+
+Parameters:
+
+- `value`/`param` raw (string) values to be parsed.
+- `receiver` is an output variable for parsed value.
+
+Return value for functions that return `bool` or `Result` (in other cases parsing is always considered successful):
+- `true`/`Result.Success` if parsing was successful or
+- `false`/`Result.Error` otherwise.
+
+## Validation {id="Validation"}
+
+`Validation` modifier can be used to validate parsed value. It accepts a function with one of the following
+signatures:
+
+- `bool validate(ParseType value)`
+
+ `Result validate(ParseType value)`
+
+- `bool validate(ParseType[] value)`
+
+ `Result validate(ParseType[] value)`
+
+- `bool validate(Param!ParseType param)`
+
+ `Result validate(Param!ParseType param)`
+
+Parameters:
+
+- `value`/`param` contains a value returned from `Parse` step.
+
+Return value:
+
+- `true`/`Result.Success` if validation passed or
+- `false`/`Result.Error` otherwise.
+
+## Action {id="Action"}
+
+`Action` modifier allows customizing a logic of how "destination" should be changed when argument has a value in
+command line. It accepts a function with one of the following signatures:
+
+- `bool action(ref T receiver, ParseType value)`
+
+ `void action(ref T receiver, ParseType value)`
+
+- `Result action(ref T receiver, ParseType value)`
+
+ `bool action(ref T receiver, Param!ParseType param)`
+
+- `void action(ref T receiver, Param!ParseType param)`
+
+ `Result action(ref T receiver, Param!ParseType param)`
+
+Parameters:
+
+- `receiver` is a receiver (destination) which is supposed to be changed based on a `value`/`param`.
+- `value`/`param` has a value returned from `Parse` step.
+
+Return value:
+
+- `true`/`Result.Success` if operation was successful or
+- `false`/`Result.Error` otherwise.
+
+## Example
+
+All the above modifiers can be combined in any way:
+
+
diff --git a/docs/topics/Positional-arguments.md b/docs/topics/Positional-arguments.md
new file mode 100644
index 0000000..e586ee5
--- /dev/null
+++ b/docs/topics/Positional-arguments.md
@@ -0,0 +1,21 @@
+# Positional arguments
+
+_Positional arguments_ are arguments that have specific position within the command line. This argument can be declared
+using `PositionalArgument` UDA. It has the following parameters:
+
+| # | Name | Type | Optional/
Required | Description |
+|---|---------------|----------|------------------------|--------------------------------------------------------------------------------------------------------------|
+| 1 | `position` | `uint` | required | Zero-based unsigned position of the argument. |
+| 2 | `placeholder` | `string` | optional | Name of this argument that is shown in help text.
If not provided, then the name of data member is used. |
+
+Since that both _named_ and _positional arguments_ can be mixed in the command line, `argparse` enforces the following
+restrictions to be able to parse a command line unambiguously:
+- Positions of _positional arguments_ must be consecutive starting with zero without missing or repeating.
+- _Positional argument_ must not have variable number of values except for the last argument.
+- Optional _positional argument_ must have index greater than required _positional arguments_.
+- If a command has default subcommand (see Subcommand section for details) the optional _positional argument_ is not
+ allowed in this command.
+
+Example:
+
+
diff --git a/docs/topics/Restrict-allowed-values.md b/docs/topics/Restrict-allowed-values.md
new file mode 100644
index 0000000..3a690ad
--- /dev/null
+++ b/docs/topics/Restrict-allowed-values.md
@@ -0,0 +1,17 @@
+# Restrict allowed values
+
+In some cases an argument can receive one of the limited set of values. This can be achieved by adding `.AllowedValues!()`
+to UDA:
+
+
+
+For the value that is not in the allowed list, this error will be printed:
+
+
+
+> If the type of destination data member is `enum`, then the allowed values are automatically limited to those
+> listed in the `enum`.
+>
+> See [Enum](Supported-types.md#enum) section for details.
+>
+{style="note"}
\ No newline at end of file
diff --git a/docs/topics/Shell-completion.md b/docs/topics/Shell-completion.md
new file mode 100644
index 0000000..95195a4
--- /dev/null
+++ b/docs/topics/Shell-completion.md
@@ -0,0 +1,90 @@
+# Shell completion
+
+`argparse` supports tab completion of last argument for certain shells (see below). However, this support is limited
+to the names of arguments and subcommands.
+
+## Wrappers for main function
+
+If you are using `CLI!(...).main(alias newMain)` mixin template in your code then you can easily build a completer
+(program that provides completion) by defining `argparse_completion` version (`-version=argparse_completion` option of
+`dmd`). Don’t forget to use different output file for completer than your main program (`-of` option in `dmd`). No other
+changes are necessary to generate completer, but you should consider minimizing the set of imported modules when
+`argparse_completion` version is defined. For example, you can put all imports into your main function that is passed to
+`CLI!(...).main(alias newMain)` – `newMain` parameter is not used in completer.
+
+If you prefer having separate main module for completer, then you can use `CLI!(...).mainComplete` mixin template:
+```c++
+mixin CLI!(...).mainComplete;
+```
+
+In case if you prefer to have your own `main` function and would like to call completer by yourself, you can use
+`int CLI!(...).complete(string[] args)` function. This function executes the completer by parsing provided `args` (note
+that you should remove the first argument from `argv` passed to `main` function). The returned value is meant to be
+returned from `main` function, having zero value in case of success.
+
+## Low level completion
+
+In case if none of the above methods is suitable, `argparse` provides `string[] CLI!(...).completeArgs(string[] args)`
+function. It takes arguments that should be completed and returns all possible completions.
+
+`completeArgs` function expects to receive all command line arguments (excluding `argv[0]` – first command line argument
+in `main` function) in order to provide completions correctly (set of available arguments depends on subcommand). This
+function supports two workflows:
+- If the last argument in `args` is empty and it’s not supposed to be a value for a command line argument, then all
+ available arguments and subcommands (if any) are returned.
+- If the last argument in `args` is not empty and it’s not supposed to be a value for a command line argument, then only
+ those arguments and subcommands (if any) are returned that start with the same text as the last argument in `args`.
+
+For example, if there are `--foo`, `--bar` and `--baz` arguments available, then:
+- Completion for `args=[""]` will be `["--foo", "--bar", "--baz"]`.
+- Completion for `args=["--b"]` will be `["--bar", "--baz"]`.
+
+## Using the completer
+
+Completer that is provided by `argparse` supports the following shells:
+- bash
+- zsh
+- tcsh
+- fish
+
+Its usage consists of two steps: completion setup and completing of the command line. Both are implemented as
+subcommands (`init` and `complete` accordingly).
+
+### Completion setup
+
+Before using completion, completer should be added to the shell. This can be achieved by using `init` subcommand. It
+accepts the following arguments (you can get them by running ` init --help`):
+- `--bash`: provide completion for bash.
+- `--zsh`: provide completion for zsh. Note: zsh completion is done through bash completion so you should execute `bashcompinit` first.
+- `--tcsh`: provide completion for tcsh.
+- `--fish`: provide completion for fish.
+- `--completerPath `: path to completer. By default, the path to itself is used.
+- `--commandName `: command name that should be completed. By default, the first name of your main command is used.
+
+Either `--bash`, `--zsh`, `--tcsh` or `--fish` is expected.
+
+As a result, completer prints the script to setup completion for requested shell into standard output (`stdout`)
+which should be executed. To make this more streamlined, you can execute the output inside the current shell or to do
+this during shell initialization (e.g., in `.bashrc` for bash). To help doing so, completer also prints sourcing
+recommendation to standard output as a comment.
+
+Example of completer output for ` init --bash --commandName mytool --completerPath /path/to/completer` arguments:
+```bash
+# Add this source command into .bashrc:
+# source <(/path/to/completer init --bash --commandName mytool)
+complete -C 'eval /path/to/completer --bash -- $COMP_LINE ---' mytool
+```
+
+Recommended workflow is to install completer into a system according to your installation policy and update shell
+initialization/config file to source the output of `init` command.
+
+### Completing of the command line
+
+Argument completion is done by `complete` subcommand (it’s default one). It accepts the following arguments (you can get them by running ` complete --help`):
+- `--bash`: provide completion for bash.
+- `--tcsh`: provide completion for tcsh.
+- `--fish`: provide completion for fish.
+
+As a result, completer prints all available completions, one per line, assuming that it’s called according to the output
+of `init` command.
+
diff --git a/docs/topics/Subcommands.md b/docs/topics/Subcommands.md
new file mode 100644
index 0000000..c2b16ac
--- /dev/null
+++ b/docs/topics/Subcommands.md
@@ -0,0 +1,46 @@
+# Subcommands
+
+Sophisticated command line tools, like `git`, have many subcommands (e.g., `git clone`, `git commit`, `git push`, etc.),
+each with its own set of arguments. There are few ways how to use subcommands with `argparse`.
+
+## `Subcommand` type
+
+General approach to declare subcommands is to use `SubCommand` type. This type is behaving like a `SumType` from standard library
+with few additions:
+- It allows no command to be chosen.
+- It supports at most one default subcommand (see [below](#default-subcommand) for details).
+
+> See [SubCommand](SubCommand.md) section in the Reference for more detailed description of `SubCommand` type.
+>
+{style="note"}
+
+
+
+## Subcommands with shared common arguments
+
+In some cases command line tool has arguments that are common across all subcommands. They can be specified as regular
+arguments in a struct that represents the whole program:
+
+
+
+## Subcommand name and aliases
+
+Using type name as a subcommand name in command line might not be convenient, moreover, the same subcommand might have
+multiple names in command line (e.g. short and long versions). `Command` UDA can be used to list all acceptable names for
+a subcommand:
+
+
+
+## Default subcommand
+
+Default subcommand is one that is selected when user does not specify any subcommand in the command line.
+To mark a subcommand as default, use `Default` template:
+
+
+
+## Enumerating subcommands in CLI mixin
+
+One of the possible ways to use subcommands with `argparse` is to list all subcommands in `CLI` mixin. Although this might
+be a useful feature, it is very limited: `CLI` mixin only allows overriding of the `main` function for this case:
+
+
diff --git a/docs/topics/Supported-types.md b/docs/topics/Supported-types.md
new file mode 100644
index 0000000..9f4fc4c
--- /dev/null
+++ b/docs/topics/Supported-types.md
@@ -0,0 +1,115 @@
+# Supported types
+
+When command line entries are mapped to the annotated data members, the text value is converted to the type of the
+data member.
+
+## Boolean flags
+
+Boolean types usually represent command line flags. `argparse` supports multiple ways of providing flag value including
+negation (i.e., `--no-flag`):
+
+| Command line entries | Result |
+|--------------------------------|-----------|
+| `-b` / `--boo` | `true` |
+| `-b=` / `--boo=` | `` |
+| `--no-b` / `--no-boo` | `false` |
+| `-b ` / `--boo ` | error |
+
+> `` is accepted only if it's provided with assignment `=` character ([`Config.assignChar`](Config.md#assignChar)),
+> not as a separate command line entry.
+>
+{style="warning"}
+
+`argparse` supports the following strings as a `` (comparison is case-insensitive):
+
+| `` | Result |
+|------------------|--------|
+| `true`,`yes`,`y` | true |
+| `false`,`no`,`n` | false |
+
+## Numbers and strings
+
+Numeric (according to `std.traits.isNumeric`) and string (according to `std.traits.isSomeString`) data types are
+seamlessly converted to destination type using `std.conv.to`:
+
+
+
+## Arrays
+
+`argparse` supports 1D and 2D arrays:
+- If an argument is bound to 1D array, a new element is appended to this array each time the argument is provided in
+command line.
+- In case of 2D array, new elements are grouped in a way as they appear in
+command line and then each group is appended to this array.
+
+The difference can be easily shown in the following example:
+
+
+
+Alternatively one can set [`Config.arraySep`](Config.md#arraySep) to allow multiple elements in one command line entry:
+
+
+
+## Associative arrays
+
+`argparse` also supports associative array where simple value type (e.g. numbers, strings etc.). In this case, expected
+format of the value is `key=value` (equal sign can be customized with [`Config.assignChar`](Config.md#assignChar)):
+
+
+
+Alternatively one can set [`Config.arraySep`](Config.md#arraySep) to allow multiple elements in one command line entry:
+
+
+
+## Enums {id="enum"}
+
+It is encouraged to use `enum` types for arguments that have a limited set of valid values. In this case, `argparse`
+validates that the value specified in command line matches one of enum identifiers:
+
+
+
+In some cases the value for command line argument might have characters that are not allowed in enum identifiers.
+Actual values that are allowed in command line can be adjusted with `ArgumentValue` UDA:
+
+
+
+> When `ArgumentValue` UDA is used, enum identifier is ignored so if argument is supposed to accept it, identifier
+> must be listed in the UDA as well - see `"noapple"` in the example above.
+>
+{style="note"}
+
+## Counter
+
+Counter is an argument that tracks the number of times it's specified in the command line:
+
+
+
+The same example with enabled [bundling](Arguments-bundling.md):
+
+
+
+## Callback
+
+If member type is a function, `argparse` will try to call it when the corresponding argument is specified in the
+command line.
+
+`argparse` supports the following function signatures (return value is ignored, if any):
+
+- `... func()` - argument is treated as a boolean flag.
+
+- `... func(string)` - argument has exactly one value. The value specified in command line is provided into `string` parameter.
+
+- `... func(string[])` - argument has zero or more values. Values specified in command line are provided into `string[]` parameter.
+
+- `... func(RawParam)` - argument has zero or more values. Values specified in command line are provided into parameter.
+
+Example:
+
+
+
+## Custom types
+
+`argparse` can actually work with any arbitrary type - just provide parsing function (see [Parsing customization](Parsing-customization.md#Parse)
+for details):
+
+
diff --git a/docs/topics/reference/ArgumentGroup.md b/docs/topics/reference/ArgumentGroup.md
new file mode 100644
index 0000000..19f08fc
--- /dev/null
+++ b/docs/topics/reference/ArgumentGroup.md
@@ -0,0 +1,48 @@
+# ArgumentGroup
+
+`ArgumentGroup` UDA is used to group arguments on help screen.
+
+## Usage
+
+**Signature**
+```C++
+ArgumentGroup(string name)
+```
+
+**Usage example**
+
+```C++
+@ArgumentGroup("my group")
+{
+...
+}
+```
+
+
+## Public members
+
+### Description
+
+`Description` is used to add description text to a group.
+
+**Signature**
+
+```C++
+... Description(auto ref ... group, string text)
+... Description(auto ref ... group, string function() text)
+```
+
+**Parameters**
+
+- `text`
+
+ Text that contains group description or a function that returns such text.
+
+**Usage example**
+
+```C++
+@(ArgumentGroup("my group").Description("custom description"))
+{
+...
+}
+```
diff --git a/docs/topics/reference/ArgumentValue.md b/docs/topics/reference/ArgumentValue.md
new file mode 100644
index 0000000..38a684e
--- /dev/null
+++ b/docs/topics/reference/ArgumentValue.md
@@ -0,0 +1,26 @@
+# ArgumentValue
+
+`ArgumentValue` UDA is used to list all values that an argument can accept. This is very useful in the cases when an argument
+must have a value from a specific list, for example, when argument type is `enum`.
+
+**Signature**
+
+```C++
+ArgumentValue(string[] values...)
+```
+
+**Parameters**
+
+- `values`
+
+ Values that argument can have.
+
+**Usage example**
+
+```C++
+enum Fruit {
+ apple,
+ @ArgumentValue("no-apple","noapple")
+ noapple
+};
+```
diff --git a/docs/topics/reference/CLI-API.md b/docs/topics/reference/CLI-API.md
new file mode 100644
index 0000000..cee7c0d
--- /dev/null
+++ b/docs/topics/reference/CLI-API.md
@@ -0,0 +1,191 @@
+# CLI API
+
+`CLI` is a template that provides entry-point functions to call `argparse`.
+
+Here are the signatures that `CLI` template has:
+```c++
+template CLI(Config config, COMMAND)
+template CLI(Config config, COMMANDS...)
+```
+
+The second template with multiple `COMMANDS...` has only `main` function which wraps all `COMMANDS` inside internal
+struct with only data member of type `SubCommand!COMMANDS` and calls `CLI(Config config, CMD).main` with that.
+
+There is also an `alias` that uses default `Config.init` to simplify default behavior:
+```c++
+alias CLI(COMMANDS...) = CLI!(Config.init, COMMANDS);
+```
+
+## Public members
+
+### parseKnownArgs
+
+`CLI.parseKnownArgs` is a function that parses only known arguments from the command line.
+
+All arguments that were not recognized during parsing are returned to a caller.
+
+**Signature**
+
+```c++
+Result parseKnownArgs(ref COMMAND receiver, string[] args, out string[] unrecognizedArgs)
+Result parseKnownArgs(ref COMMAND receiver, ref string[] args)
+```
+
+**Parameters**
+
+- `receiver`
+
+ Object that receives parsed command line arguments.
+
+- `args`
+
+ Command line arguments to parse (excluding `argv[0]` – first command line argument in `main` function).
+
+- `unrecognizedArgs`
+
+ Command line arguments that were not parsed.
+
+**Notes**
+
+- The second signature (without `unrecognizedArgs` parameter) returns not parsed arguments through `args` reference parameter.
+
+**Return value**
+
+`Result` object that can be cast to `bool` to check whether the parsing was successful or not.
+Successful parsing for `parseKnownArgs` function means that there are no error during parsing of known arguments.
+This means that having unrecognized arguments in a command line is not an error.
+
+### parseArgs
+
+`CLI.parseArgs` is a function that parses command line arguments and validates that there are no unknown ones.
+
+**Signature**
+
+```c++
+Result parseArgs(ref COMMAND receiver, string[] args)
+int parseArgs(alias newMain)(string[] args, COMMAND initialValue = COMMAND.init)
+```
+
+**Parameters**
+
+- `receiver`
+
+ Object that receives parsed command line arguments.
+
+- `args`
+
+ Command line arguments to parse (excluding `argv[0]` – first command line argument in `main` function).
+
+- `newMain`
+
+ Function that is called after successful command line parsing. See [`newMain`](#newMain) for details.
+
+- `initialValue`
+
+ Initial value for the object passed to `newMain` function.
+
+
+**Notes**
+
+- `newMain` will not be called in case of parsing error.
+
+**Return value**
+
+- In case of parsing error - `Result.exitCode` (`1` by default).
+- In case of success:
+ - `0` for the `parseArgs` version that doesn't accept `newMain` function.
+ - `0` if `newMain` doesn't return a value that can be cast to `int`.
+ - Value returned by `newMain` that is cast to `int`.
+
+### complete
+
+`CLI.complete` is a function that performs shell completion for command line arguments.
+
+**Signature**
+
+```c++
+int complete()(string[] args)
+```
+
+**Parameters**
+
+- `args`
+
+ Command line arguments (excluding `argv[0]` – first command line argument in `main` function).
+
+**Notes**
+
+This function provides completion for the last argument in the command line:
+- If the last entry in command line is an empty string (`""`) then it provides all available argument names prepended
+ with [`Config.namedArgPrefix`](Config.md#namedArgPrefix).
+- If the last entry in command line contains characters then `complete` provides completion only with those arguments
+ that have names starting with specified characters.
+
+**Return value**
+
+- `0` in case of successful parsing.
+- Non-zero otherwise.
+
+### mainComplete
+
+`CLI.mainComplete` is a mixin template that provides global `main` function which calls [`CLI.complete`](#complete).
+
+**Signature**
+
+```c++
+template mainComplete()
+```
+
+**Notes**
+
+Ingested `main` function is a simple wrapper of [`CLI.complete`](#complete) function that removes `argv[0]` from command line.
+
+**Return value**
+
+Value returned from [`CLI.complete`](#complete) function.
+
+### main
+
+`CLI.main` is a mixin template that does one of these:
+
+- If `argparse_completion` version is defined then it instantiates `CLI.mainComplete` template mixin.
+- Otherwise it provides global `main` function that calls [`CLI.parseArgs`](#parseargs) function.
+
+**Signature**
+
+```c++
+template main(alias newMain)
+```
+
+**Parameters**
+
+- `newMain`
+
+ Function that is called after successful command line parsing. See [`newMain`](#newMain) for details.
+
+**Notes**
+
+- `newMain` parameter is not used in case if `argparse_completion` version is defined.
+
+**Return value**
+
+See [`CLI.mainComplete`](#maincomplete) and [`CLI.parseArgs`](#parseargs).
+
+## newMain parameter {id="newMain"}
+
+`newMain` parameter in `CLI` API is a substitution for classic `main` function with the following differences:
+- Its first parameter has type of a command struct that is passed to `CLI` API. This parameter is filled with the data
+ parsed from actual command line.
+
+ `... newMain(COMMAND command)`
+
+- It might have optional second parameter of type `string[]` that receives unknown command line arguments.
+
+ `... newMain(COMMAND command, string[] unrecognizedArgs)`
+
+- `newMain` can optionally return anything that can be cast to `int`. In this case, `argparse` will return that value from `CLI` API
+ or from injected `main` function in case of `CLI.main`.
+
+> If `newMain` has only one parameter, `argparse` will error out when command line contains unrecognized arguments.
+>
+{style="warning"}
\ No newline at end of file
diff --git a/docs/topics/reference/Command.md b/docs/topics/reference/Command.md
new file mode 100644
index 0000000..55e77ee
--- /dev/null
+++ b/docs/topics/reference/Command.md
@@ -0,0 +1,139 @@
+# Command
+
+`Command` UDA is used to customize **top-level command** as well as **subcommands**.
+
+This UDA can be chained with functions listed below to adjust different settings.
+
+**Signature**
+
+```c++
+Command(string[] names...)
+```
+
+**Parameters**
+
+- `names`
+
+ For **subcommands**, these are the names of the subcommand that can appear in the command line. If no name is provided then
+ the name of the type that represents the command is used.
+
+ For **top-level command**, this is a name of a program/tool that is appeared on help screen. If multiple names are passed, only first is used.
+ If no name is provided then `Runtime.args[0]` (a.k.a. `argv[0]` from `main` function) is used.
+
+
+## Public members
+
+### Usage
+
+`Usage` allows customize the usage text. By default, the parser calculates the usage message from the arguments it contains
+but this can be overridden with `Usage` call. If the custom text contains `%(PROG)` then it will be replaced by the
+`argv[0]` (from `main` function) in case of top-level command or by a list of commands (all parent commands and current one)
+in case of subcommand.
+
+
+**Signature**
+
+```C++
+Usage(auto ref ... command, string text)
+Usage(auto ref ... command, string function() text)
+```
+
+**Parameters**
+
+- `text`
+
+ Usage text or a function that returns such text.
+
+**Usage example**
+
+```C++
+@(Command.Usage("%(PROG) [...]"))
+struct my_command
+{
+...
+}
+```
+
+### Description
+
+`Description` can be used to provide a description of what the command/program does and how it works. In help messages, the
+ description is displayed between the usage string and the list of the command arguments.
+
+**Signature**
+
+```C++
+Description(auto ref ... command, string text)
+Description(auto ref ... command, string function() text)
+```
+
+**Parameters**
+
+- `text`
+
+ Text that contains command description or a function that returns such text.
+
+**Usage example**
+
+```C++
+@(Command.Description("custom description"))
+struct my_command
+{
+...
+}
+```
+
+### ShortDescription
+
+`ShortDescription` can be used to provide a brief description of what the subcommand does. It is applicable to subcommands
+ only and is displayed in *Available commands* section on help screen of the parent command.
+
+**Signature**
+
+```C++
+ShortDescription(auto ref ... command, string text)
+ShortDescription(auto ref ... command, string function() text)
+```
+
+**Parameters**
+
+- `text`
+
+ Text that contains short description for a subcommand or a function that returns such text.
+
+**Usage example**
+
+```C++
+@(Command.ShortDescription("custom description"))
+struct my_command
+{
+...
+}
+```
+
+
+### Epilog
+
+`Epilog` can be used to provide some custom text that is printed at the end after the list of command arguments.
+
+**Signature**
+
+```C++
+Epilog(auto ref ... command, string text)
+Epilog(auto ref ... command, string function() text)
+```
+
+**Parameters**
+
+- `text`
+
+ Epilog text or a function that returns such text.
+
+**Usage example**
+
+```C++
+@(Command.Epilog("extra info about the command"))
+struct my_command
+{
+...
+}
+```
diff --git a/docs/topics/reference/Config.md b/docs/topics/reference/Config.md
new file mode 100644
index 0000000..80ce66d
--- /dev/null
+++ b/docs/topics/reference/Config.md
@@ -0,0 +1,148 @@
+# Config
+
+`argparse` provides decent amount of settings to customize the parser. All customizations can be done by creating
+`Config` object with required settings (see below) and passing it to [CLI API](CLI-API.md).
+
+## Assign character {id="assignChar"}
+
+`Config.assignChar` is an assignment character used in arguments with value: `-a=5`, `-b=foo`.
+
+Default is equal sign `=`.
+
+Example:
+
+
+
+## Array separator {id="arraySep"}
+
+When `Config.arraySep` is set to `char.init`, values to array and associative-array receivers are treated as an individual
+value. That is, only one argument is appended/inserted per appearance of the argument. If `arraySep` is set to something
+else, then each value is first split by the separator, and the individual pieces are treated as values to the same
+argument.
+
+Default is `char.init`.
+
+Example:
+
+
+
+## Named argument prefix {id="namedArgPrefix"}
+
+`Config.namedArgPrefix` is a character that named arguments begin with.
+
+Default is dash (`-`).
+
+Example:
+
+
+
+## End of named arguments {id="endOfNamedArgs"}
+
+`Config.endOfNamedArgs` is a string that marks the end of all named arguments. All arguments that are specified
+after this one are treated as positional regardless to the value which can start with `namedArgPrefix` (dash `-` by default)
+or be a subcommand.
+
+Default is double dash (`--`).
+
+Example:
+
+
+
+## Case sensitivity {id="caseSensitive"}
+
+`Config.caseSensitive` controls whether the argument names are case-sensitive. By default they are and it can be changed
+by setting this member to `false`.
+
+Default is `true`.
+
+Example:
+
+
+
+## Bundling of single-character arguments {id="bundling"}
+
+`Config.bundling` controls whether single-character arguments (usually boolean flags) can be bundled together.
+If it is set to `true` then `-abc` is the same as `-a -b -c`.
+
+Default is `false`.
+
+Example:
+
+
+
+## Adding help generation {id="addHelp"}
+
+`Config.addHelp` can be used to add (if `true`) or not (if `false`) `-h`/`--help` argument.
+In case if the command line has `-h` or `--help`, then the corresponding help text is printed and the parsing is stopped.
+If `CLI!(...).parseArgs(alias newMain)` or `CLI!(...).main(alias newMain)` is used, then provided `newMain` function will
+not be called.
+
+Default is `true`.
+
+Example:
+
+
+
+Help text from the first part of the example code above:
+
+
+
+
+## Styling mode {id="stylingMode"}
+
+`Config.stylingMode` controls whether styling for help text and errors should be enabled.
+It has the following type: `enum StylingMode { autodetect, on, off }`:
+- `Config.StylingMode.on`: styling is **always enabled**.
+- `Config.StylingMode.off`: styling is **always disabled**.
+- `Config.StylingMode.autodetect`: styling will be enabled when possible.
+
+See [ANSI coloring and styling](ANSI-coloring-and-styling.md) for details.
+
+Default value is `Config.StylingMode.autodetect`.
+
+Example:
+
+
+
+Help text from the first part of the example code above:
+
+
+
+## Styling scheme {id="styling"}
+
+`Config.styling` contains style for the text output (error messages and help text). It has the following members:
+
+- `programName`: style for the program name. Default is `bold`.
+- `subcommandName`: style for the subcommand name. Default is `bold`.
+- `argumentGroupTitle`: style for the title of argument group. Default is `bold.underline`.
+- `argumentName`: style for the argument name. Default is `lightYellow`.
+- `namedArgumentValue`: style for the value of named argument. Default is `italic`.
+- `positionalArgumentValue`: style for the value of positional argument. Default is `lightYellow`.
+- `errorMessagePrefix`: style for *Error:* prefix in error messages. Default is `red`.
+
+See [ANSI coloring and styling](ANSI-coloring-and-styling.md) for details.
+
+Example:
+
+
+
+Help text from the first part of the example code above:
+
+
+
+## Error handling {id="errorHandler"}
+
+`Config.errorHandler` is a handler function for all errors occurred during command line parsing.
+It is a function that receives `string` parameter which would contain an error message.
+
+> Function must ne `nothrow`
+>
+{style="warning"}
+
+The default behavior is to print error message to `stderr`.
+
+Example:
+
+
+
+This code prints `Detected an error: Unrecognized arguments: ["-b"]` to `stderr`.
diff --git a/docs/topics/reference/MutuallyExclusive.md b/docs/topics/reference/MutuallyExclusive.md
new file mode 100644
index 0000000..bc25b4b
--- /dev/null
+++ b/docs/topics/reference/MutuallyExclusive.md
@@ -0,0 +1,18 @@
+# MutuallyExclusive
+
+`MutuallyExclusive` UDA is used to mark a set of arguments as mutually exclusive. This means that as soon as one argument from
+this group is specified in the command line then no other arguments from the same group can be specified.
+
+See ["Argument dependencies"](Argument-dependencies.md#MutuallyExclusive) section for more details.
+
+## Required
+
+"Mutually exclusive" group can be marked as required in order to require exactly one argument from the group:
+
+```C++
+@(MutuallyExclusive.Required)
+{
+ int a;
+ int b;
+}
+```
diff --git a/docs/topics/reference/Param-RawParam.md b/docs/topics/reference/Param-RawParam.md
new file mode 100644
index 0000000..051a02b
--- /dev/null
+++ b/docs/topics/reference/Param-RawParam.md
@@ -0,0 +1,18 @@
+# Param / RawParam
+
+[Parsing customization API](Parsing-customization.md) works with Param/RawParam struct under the hood which is publicly available for usage.
+
+`Param` is a template struct parametrized by `VALUE_TYPE` (see below) which is usually a `string[]` or a type of destination data member.
+
+> `RawParam` is an alias where `VALUE_TYPE` is `string[]`. This alias represents "raw" values from command line.
+>
+{style="note"}
+
+`Param` struct has the following fields:
+
+- `const(Config)*` `config`- The content is almost the same as the [`Config`](Config.md) object that was passed into [CLI API](CLI-API.md).
+ The only difference is in [`Config.stylingMode`](Config.md#stylingMode) - it is either `Config.StylingMode.on` or `Config.StylingMode.off`
+ based on [auto-detection](ANSI-coloring-and-styling.md#heuristic) results.
+- `string` `name` – For named argument, it contains a name that is specified in command line exactly including prefix(es)
+ ([`Config.namedArgPrefix`](Config.md#namedArgPrefix)). For positional arguments, it contains placeholder value.
+- `VALUE_TYPE` `value` – Argument values that are provided in command line.
diff --git a/docs/topics/reference/PositionalNamedArgument.md b/docs/topics/reference/PositionalNamedArgument.md
new file mode 100644
index 0000000..ec5cc60
--- /dev/null
+++ b/docs/topics/reference/PositionalNamedArgument.md
@@ -0,0 +1,447 @@
+# PositionalArgument/NamedArgument
+
+`PositionalArgument` UDA is used to declare an argument that has specific position in the command line.
+
+
+**Signature**
+
+```c++
+PositionalArgument(uint position)
+PositionalArgument(uint position, string placeholder)
+NamedArgument(string[] names...)
+```
+
+**Parameters**
+
+- `position`
+
+ Zero-based unsigned position of the argument.
+
+- `placeholder`
+
+ Name of this argument that is shown in help text.
+ By default, the name of data member is used.
+
+- `names`
+
+ Name(s) of this argument that can be used in command line.
+ By default, the name of data member is used.
+
+## Public members
+
+### Description
+
+`Description` can be used to provide a description of the argument. This text is printed next to the argument
+in the argument list section of a help message.
+
+**Signature**
+
+```C++
+Description(auto ref ... argument, string text)
+Description(auto ref ... argument, string function() text)
+```
+
+**Parameters**
+
+- `text`
+
+ Text that contains argument description or a function that returns such text.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.Description("custom description"))
+ int a;
+}
+```
+
+### HideFromHelp
+
+`HideFromHelp` can be used to indicate that the argument should not be printed in help message.
+
+**Signature**
+
+```C++
+HideFromHelp(auto ref ... argument, bool hide = true)
+```
+
+**Parameters**
+
+- `hide`
+
+ If `true` then argument is not printed in help message.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.HideFromHelp)
+ int a;
+}
+```
+
+### Placeholder
+
+`Placeholder` provides custom text that is used to indicate the value of the argument in help message.
+
+**Signature**
+
+```C++
+Placeholder(auto ref ... argument, string value)
+```
+
+**Parameters**
+
+- `value`
+
+ Text that is used as a placeholder for a value of an argument in help message.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.Placeholder("VALUE"))
+ int a;
+}
+```
+
+### Required
+
+Mark an argument as required so if it is not provided in command line, `argparse` will error out.
+
+By default all positional arguments are required.
+
+**Signature**
+
+```C++
+Required(auto ref ... argument)
+```
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.Required)
+ int a;
+}
+```
+
+### Optional
+
+Mark an argument as optional so it can be omitted in command line without causing errors.
+
+By default all named arguments are optional.
+
+**Signature**
+
+```C++
+Optional(auto ref ... argument)
+```
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.Optional)
+ int a;
+}
+```
+
+### NumberOfValues
+
+`NumberOfValues` is used to limit number of values that an argument can accept.
+
+**Signature**
+
+```C++
+NumberOfValues(auto ref ... argument, ulong min, ulong max)
+NumberOfValues(auto ref ... argument, ulong num)
+```
+
+**Parameters**
+
+- `min`
+
+ Minimum number of values.
+
+- `max`
+
+ Maximum number of values.
+
+- `num`
+
+ Exact number of values.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.NumberOfValues(1,3))
+ int[] a;
+
+ @(NamedArgument.NumberOfValues(2))
+ int[] b;
+}
+```
+
+### MinNumberOfValues
+
+`MinNumberOfValues` is used to set minimum number of values that an argument can accept.
+
+**Signature**
+
+```C++
+MinNumberOfValues(auto ref ... argument, ulong min)
+```
+
+**Parameters**
+
+- `min`
+
+ Minimum number of values.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.MinNumberOfValues(2))
+ int[] a;
+}
+```
+
+### MaxNumberOfValues
+
+`MaxNumberOfValues` is used to set maximum number of values that an argument can accept.
+
+**Signature**
+
+```C++
+MaxNumberOfValues(auto ref ... argument, ulong max)
+```
+
+**Parameters**
+
+- `max`
+
+ Maximum number of values.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.MinNumberOfValues(3))
+ int[] a;
+}
+```
+
+### AllowNoValue
+
+`AllowNoValue` allows an argument to not have a value in the command line - in this case, the value provided to this function will be used.
+
+**Signature**
+
+```C++
+AllowNoValue(alias valueToUse)(auto ref ... argument)
+```
+
+**Parameters**
+
+- `valueToUse`
+
+ Value that is used when argument has no value specified in command line.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.AllowNoValue!10)
+ int a;
+}
+```
+
+### RequireNoValue
+
+`RequireNoValue` requires an argument to have no value in the command line. The argument is behaving like a boolean flag
+but instead of `true`/`false` values, there can be either a value provided to this function or a default one (`.init`).
+
+**Signature**
+
+```C++
+RequireNoValue(alias valueToUse)(auto ref ... argument)
+```
+
+**Parameters**
+
+- `valueToUse`
+
+ Value that is used when argument is specified in command line.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.RequireNoValue!10)
+ int a;
+}
+```
+
+### AllowedValues
+
+`AllowedValues` can be used to restrict what value can be provided in the command line for an argument.
+
+**Signature**
+
+```C++
+AllowedValues(alias values)(auto ref ... argument)
+```
+
+**Parameters**
+
+- `values`
+
+ List of values that an argument can have.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.AllowedValues!([1,4,16,8]))
+ int a;
+}
+```
+
+### Counter
+
+`Counter` can be used to mark an argument that tracks the number of times it's specified in the command line.
+
+**Signature**
+
+```C++
+Counter(auto ref ... argument)
+```
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.Counter)
+ int a;
+}
+```
+
+### PreValidation
+
+`PreValidation` can be used to customize the validation of raw string values.
+
+**Signature**
+
+```C++
+PreValidation(alias func)(auto ref ... argument)
+```
+
+**Parameters**
+
+- `func`
+
+ Function that is called to validate raw value. See [parsing customization](Parsing-customization.md#PreValidation) for details.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.PreValidation!((string s) { return s.length > 0;}))
+ int a;
+}
+```
+
+### Parse
+
+`Parse` can be used to provide custom conversion from raw string to a value.
+
+**Signature**
+
+```C++
+Parse(alias func)(auto ref ... argument)
+```
+
+**Parameters**
+
+- `func`
+
+ Function that is called to convert raw value. See [parsing customization](Parsing-customization.md#Parse) for details.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.Parse!((string s) { return s[1]; }))
+ char a;
+}
+```
+
+### Validation
+
+`Validation` can be used to validate parsed value.
+
+**Signature**
+
+```C++
+Validation(alias func)(auto ref ... argument)
+```
+
+**Parameters**
+
+- `func`
+
+ Function that is called to validate the value. See [parsing customization](Parsing-customization.md#Validation) for details.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.Validation!((int a) { return a >= 0 && a <= 9; }))
+ int a;
+}
+```
+
+### Action
+
+`Action` can be used to customize a logic of how "destination" should be changed based on parsed argument value.
+
+**Signature**
+
+```C++
+Action(alias func)(auto ref ... argument)
+```
+
+**Parameters**
+
+- `func`
+
+ Function that is called to update the destination. See [parsing customization](Parsing-customization.md#Action) for details.
+
+**Usage example**
+
+```C++
+struct my_command
+{
+ @(NamedArgument.Action!((ref int a, int v) { a += v; })
+ int a;
+}
+```
diff --git a/docs/topics/reference/RequiredTogether.md b/docs/topics/reference/RequiredTogether.md
new file mode 100644
index 0000000..72e2fc7
--- /dev/null
+++ b/docs/topics/reference/RequiredTogether.md
@@ -0,0 +1,17 @@
+# RequiredTogether
+
+`RequiredTogether` UDA is used to mark a set of arguments as mutually required. This means that as soon as one argument from
+this group is specified in the command line then all arguments from the same group must also be specified.
+
+See ["Argument dependencies"](Argument-dependencies.md#RequiredTogether) section for more details.
+
+## Required
+
+"Required together" group can be marked as required in order to require all arguments:
+
+```C++
+@(RequiredTogether.Required)
+{
+...
+}
+```
diff --git a/docs/topics/reference/Result.md b/docs/topics/reference/Result.md
new file mode 100644
index 0000000..66c3c85
--- /dev/null
+++ b/docs/topics/reference/Result.md
@@ -0,0 +1,80 @@
+# Result struct
+
+`Result` is a struct that is used to communicate between `argparse` and user functions.
+Its main responsibility is to hold the result of an operation: success or failure.
+
+## Public members
+
+### Success
+
+`Result.Success` is an compile-time constant (`enum`) that represents a successful result of an operation.
+
+**Signature**
+```c++
+static enum Success
+```
+
+### Error
+
+`Result.Error` is a function that returns a failed result of an operation.
+
+**Signature**
+
+```c++
+static auto Error(T...)(string msg, T extraArgs)
+static auto Error(T...)(int resultCode, string msg, T extraArgs)
+```
+
+**Parameters**
+
+- `resultCode`
+
+ Result/exit code of an operation. If it's not specified then `1` is used.
+
+- `msg`
+
+ Text of an error message.
+
+- `extraArgs`
+
+ Additional arguments that are added to the text of an error message.
+
+**Notes**
+
+- `msg` and `extraArgs` are converted to a single error message string using `std.conv.text(msg, extraArgs)`.
+- Error message supports ANSI styling. See [ANSI coloring and styling](ANSI-coloring-and-styling.md) how to use.
+- Error message is passed to [`Config.errorHandler`](Config.md#errorHandler) if it's set or printed to `stderr` otherwise
+ by [CLI API](CLI-API.md) at the end of parsing.
+
+**Return value**
+
+`Result` object that represents the failed result of an operation.
+
+### exitCode
+
+`Result.exitCode` is a property that returns the result/exit code. It's supposed to be returned from `main()` function.
+
+**Signature**
+
+```c++
+int exitCode() const
+```
+
+**Return value**
+
+Result/exit code of an operation.
+
+### opCast
+
+`Result.opCast` can be used to determine whether result of an operation is successful.
+
+**Signature**
+
+```c++
+bool opCast(T : bool)() const
+```
+
+**Return value**
+
+- `true` if operation is successful.
+- `false` otherwise.
diff --git a/docs/topics/reference/SubCommand.md b/docs/topics/reference/SubCommand.md
new file mode 100644
index 0000000..0621c1b
--- /dev/null
+++ b/docs/topics/reference/SubCommand.md
@@ -0,0 +1,118 @@
+# SubCommand
+
+`SubCommand` type can be used to enumerate type for subcommands. This is a wrapper of `SumType`:
+
+```c++
+struct SubCommand(Commands...)
+```
+
+## Public members
+
+### Copy constructor
+
+**Signature**
+
+```c++
+this(T)(T value)
+```
+
+**Parameters**
+
+- `T value`
+
+ Value that is copied to a new object. Its type `T` must be one of the `Commands`.
+
+### Assignment operator
+
+**Signature**
+
+```c++
+ref SubCommand opAssign(T)(T value)
+```
+
+**Parameters**
+
+- `T value`
+
+ Value to be assigned. Its type `T` must be one of the `Commands`.
+
+### isSetTo
+
+Checks whether the object is set to a specific command type;
+
+**Signature**
+
+```c++
+bool isSetTo(T)() const
+```
+
+**Parameters**
+
+- `T`
+
+ Type `T` must be one of the `Commands`.
+
+**Return value**
+
+`true` if object contains `T` type, `false` otherwise.
+
+### isSet
+
+Checks whether the object is set to any command type;
+
+**Signature**
+
+```c++
+bool isSet() const
+```
+
+**Return value**
+
+If one of the `Commands` is a default command then this function always returns `true`.
+
+In case if there is no default command, then:
+- `true` if object contains any type from `Commands`, `false` otherwise.
+
+## Default
+
+`Default` type is a struct that can be used to mark a subcommand as default, i.e. it's chosen if no other subcommand is specified
+in command line explicitly.
+
+This struct has no members and is erased by `SubCommand` before passing to internal `SumType` member.
+
+**Signature**
+
+```c++
+struct Default(COMMAND)
+```
+
+## match
+
+`match` is a function template that is similar to the one from standard library but adapted to work with `SubCommand`.
+
+**Signature**
+
+```c++
+template match(handlers...)
+{
+ auto ref match(Sub : const SubCommand!Args, Args...)(auto ref Sub sc)
+ ...
+}
+```
+
+**Parameters**
+
+- `handlers`
+
+ Functions that have the same meaning as for `match` function in standard library with an exception that they must not use `Default`
+ type because the latter is erased by `SubCommand` (i.e. just use `T` instead of `Default!T` here).
+
+- `sc`
+
+ `SubCommand` parameter that the matching is applied to.
+
+**Return value**
+
+- If `SubCommand` is set to any subcommand (or has default one) then function returns the result from `match` function from standard library.
+- Otherwise, `init` value of the type that would be returned from `match` function from standard library if that type is not `void`.
+- Otherwise, this function has no return value (i.e. it's `void`).
diff --git a/docs/topics/reference/ansiStylingArgument.md b/docs/topics/reference/ansiStylingArgument.md
new file mode 100644
index 0000000..084bf71
--- /dev/null
+++ b/docs/topics/reference/ansiStylingArgument.md
@@ -0,0 +1,31 @@
+# ansiStylingArgument
+
+Almost every command line tool that supports ANSI coloring and styling provides command line argument to control whether
+this coloring/styling should be forcefully enabled or disabled.
+
+`argparse` provides `ansiStylingArgument` function that returns an object which allows checking the status of styling/coloring.
+This function adds a command line argument that can have one of these values:
+- `always` or no value - coloring/styling should be enabled.
+- `never` - coloring/styling should be disabled.
+- `auto` - in this case, `argparse` will try to detect whether ANSI coloring/styling is supported by a system.
+
+See [ANSI coloring and styling](ANSI-coloring-and-styling.md) for details.
+
+**Signature**
+
+```C++
+... ansiStylingArgument()
+```
+
+**Usage example**
+
+```C++
+static auto color = ansiStylingArgument;
+```
+
+> Explicit `static` is not required because returned object has only `static` data members.
+
+**Return value**
+
+Returned object that can be cast to boolean. Its value is `true` when the ANSI coloring/styling should be enabled in the output,
+otherwise it's `false`.
diff --git a/docs/v.list b/docs/v.list
new file mode 100644
index 0000000..2d12cb3
--- /dev/null
+++ b/docs/v.list
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/docs/writerside.cfg b/docs/writerside.cfg
new file mode 100644
index 0000000..a3c205b
--- /dev/null
+++ b/docs/writerside.cfg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/dub.json b/examples/dub.json
index 323c765..001870b 100644
--- a/examples/dub.json
+++ b/examples/dub.json
@@ -7,8 +7,8 @@
"all:completion-separate_main-completer":"*",
"all:completion-single_main-app":"*",
"all:completion-single_main-completer":"*",
- "all:getting_started-advanced":"*",
- "all:getting_started-basic":"*",
+ "all:getting_started-with_uda":"*",
+ "all:getting_started-without_uda":"*",
"all:sub_commands-advanced":"*",
"all:sub_commands-basic":"*",
"all:sub_commands-common_args":"*",
@@ -20,8 +20,8 @@
"completion/separate_main/completer",
"completion/single_main/app",
"completion/single_main/completer",
- "getting_started/advanced",
- "getting_started/basic",
+ "getting_started/with_uda",
+ "getting_started/without_uda",
"sub_commands/advanced",
"sub_commands/basic",
"sub_commands/common_args",
diff --git a/examples/getting_started/advanced/app.d b/examples/getting_started/advanced/app.d
deleted file mode 100644
index 316dbd6..0000000
--- a/examples/getting_started/advanced/app.d
+++ /dev/null
@@ -1,75 +0,0 @@
-import argparse;
-import argparse.ansi;
-
-struct Advanced
-{
- // Positional arguments are required by default
- @PositionalArgument(0)
- string name;
-
- // Named arguments can be attributed in bulk (parentheses can be omitted)
- @NamedArgument
- {
- string unused = "some default value";
- int number;
- bool boolean;
- }
-
- // Named argument can have custom or multiple names
- @NamedArgument("apple","appl")
- int apple;
-
- @NamedArgument(["b","banana","ban"])
- int banana;
-
- // Enums can have a value that is not an identifier
- enum Enum {
- @ArgumentValue("value1","value-1","value.1")
- value1,
- value2,
- }
- @NamedArgument
- Enum choice;
-
- // Custom types can also be used with custom parsing function
- struct CustomType {
- double d;
- }
- @(NamedArgument.Parse!((string value) { import std.conv: to; return CustomType(value.to!double); }))
- CustomType custom;
-
- @(NamedArgument.Description(green.bold.underline("Colorize")~" the output. If value is omitted then '"~red("always")~"' is used."))
- static auto color = ansiStylingArgument;
-}
-
-// Customize parsing config
-auto config()
-{
- Config cfg;
-
- cfg.styling.programName = blue.onYellow;
- cfg.styling.argumentName = bold.italic.cyan.onRed;
-
- return cfg;
-}
-
-// This mixin defines standard main function that parses command line and calls the provided function:
-mixin CLI!(config(), Advanced).main!((args, unparsed)
-{
- // 'args' has 'Advanced' type
- static assert(is(typeof(args) == Advanced));
-
- // unparsed arguments has 'string[]' type
- static assert(is(typeof(unparsed) == string[]));
-
- // do whatever you need
- import std.stdio: writeln;
- args.writeln;
- writeln("Unparsed args: ", unparsed);
-
- // use actual styling mode to print output
- auto style = Advanced.color ? red.onWhite : noStyle;
- writeln(style("Styling mode: "), Advanced.color ? "on" : "off");
-
- return 0;
-});
\ No newline at end of file
diff --git a/examples/getting_started/with_uda/app.d b/examples/getting_started/with_uda/app.d
new file mode 100644
index 0000000..40cd050
--- /dev/null
+++ b/examples/getting_started/with_uda/app.d
@@ -0,0 +1,48 @@
+import argparse;
+
+struct Example
+{
+ // Positional arguments are required by default
+ @PositionalArgument(0)
+ string name;
+
+ // Named arguments can be attributed in bulk (parentheses can be omitted)
+ @NamedArgument
+ {
+ // '--number' argument
+ int number;
+
+ // '--boolean' argument
+ bool boolean;
+
+ // Argument can have default value if it's not specified in command line
+ // '--unused' argument
+ string unused = "some default value";
+ }
+
+ // Enums are also supported
+ enum Enum { unset, foo, boo }
+
+ // '--choice' argument
+ @NamedArgument
+ Enum choice;
+
+ // Named argument can have specific or multiple names
+ @NamedArgument("apple","appl")
+ int apple;
+
+ @NamedArgument("b","banana","ban")
+ int banana;
+}
+
+// This mixin defines standard main function that parses command line and calls the provided function:
+mixin CLI!Example.main!((args)
+{
+ // 'args' has 'Example' type
+ static assert(is(typeof(args) == Example));
+
+ // do whatever you need
+ import std.stdio: writeln;
+ args.writeln;
+ return 0;
+});
\ No newline at end of file
diff --git a/examples/getting_started/advanced/dub.json b/examples/getting_started/with_uda/dub.json
similarity index 75%
rename from examples/getting_started/advanced/dub.json
rename to examples/getting_started/with_uda/dub.json
index 34a8805..cc05706 100644
--- a/examples/getting_started/advanced/dub.json
+++ b/examples/getting_started/with_uda/dub.json
@@ -1,6 +1,6 @@
{
"license": "BSL-1.0",
- "name": "getting_started-advanced",
+ "name": "getting_started-with_uda",
"targetType":"executable",
"sourcePaths":["."],
"dependencies":{ "all:argparse":"*" }
diff --git a/examples/getting_started/basic/app.d b/examples/getting_started/without_uda/app.d
similarity index 88%
rename from examples/getting_started/basic/app.d
rename to examples/getting_started/without_uda/app.d
index 4131aab..d06c152 100644
--- a/examples/getting_started/basic/app.d
+++ b/examples/getting_started/without_uda/app.d
@@ -1,7 +1,7 @@
import argparse;
// If struct has no UDA then all members are named arguments
-struct Basic
+struct Example
{
// Basic data types are supported:
// '--name' argument
@@ -18,7 +18,7 @@ struct Basic
string unused = "some default value";
- // Enums are also supported
+ // Enums are supported
enum Enum { unset, foo, boo }
// '--choice' argument
Enum choice;
@@ -41,10 +41,10 @@ struct Basic
}
// This mixin defines standard main function that parses command line and calls the provided function:
-mixin CLI!Basic.main!((args)
+mixin CLI!Example.main!((args)
{
- // 'args' has 'Baisc' type
- static assert(is(typeof(args) == Basic));
+ // 'args' has 'Example' type
+ static assert(is(typeof(args) == Example));
// do whatever you need
import std.stdio: writeln;
diff --git a/examples/getting_started/basic/dub.json b/examples/getting_started/without_uda/dub.json
similarity index 74%
rename from examples/getting_started/basic/dub.json
rename to examples/getting_started/without_uda/dub.json
index 4e4299b..07a0e3c 100644
--- a/examples/getting_started/basic/dub.json
+++ b/examples/getting_started/without_uda/dub.json
@@ -1,6 +1,6 @@
{
"license": "BSL-1.0",
- "name": "getting_started-basic",
+ "name": "getting_started-without_uda",
"targetType":"executable",
"sourcePaths":["."],
"dependencies":{ "all:argparse":"*" }
diff --git a/images/default_styling.png b/images/default_styling.png
deleted file mode 100644
index a53edbe..0000000
Binary files a/images/default_styling.png and /dev/null differ