{"id":13629150,"url":"https://github.com/dotmake-build/command-line","last_synced_at":"2025-12-25T21:57:01.844Z","repository":{"id":212163098,"uuid":"730729268","full_name":"dotmake-build/command-line","owner":"dotmake-build","description":"Declarative syntax for System.CommandLine via attributes for easy, fast, strongly-typed (no reflection) usage. Includes a source generator which automagically converts your classes to CLI commands and properties to CLI options or CLI arguments.","archived":false,"fork":false,"pushed_at":"2025-04-10T15:11:44.000Z","size":3375,"stargazers_count":99,"open_issues_count":2,"forks_count":9,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-10T16:44:10.842Z","etag":null,"topics":["cli","command-line","commandlineparser","console","csharp","dotmake","dotnet","source-generator","system-commandline"],"latest_commit_sha":null,"homepage":"https://dotmake.build","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dotmake-build.png","metadata":{"files":{"readme":"docs/README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-12-12T14:47:52.000Z","updated_at":"2025-04-10T15:08:07.000Z","dependencies_parsed_at":"2024-01-20T00:27:57.782Z","dependency_job_id":"08f1f114-a38d-4738-b337-022c5758b588","html_url":"https://github.com/dotmake-build/command-line","commit_stats":null,"previous_names":["dotmake-build/command-line"],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotmake-build%2Fcommand-line","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotmake-build%2Fcommand-line/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotmake-build%2Fcommand-line/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotmake-build%2Fcommand-line/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dotmake-build","download_url":"https://codeload.github.com/dotmake-build/command-line/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249316056,"owners_count":21249885,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","command-line","commandlineparser","console","csharp","dotmake","dotnet","source-generator","system-commandline"],"created_at":"2024-08-01T22:01:03.391Z","updated_at":"2025-12-25T21:57:01.771Z","avatar_url":"https://github.com/dotmake-build.png","language":"C#","funding_links":[],"categories":["Content"],"sub_categories":["108. [CommandLine](https://ignatandrei.github.io/RSCG_Examples/v2/docs/CommandLine) , in the [EnhancementProject](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enhancementproject) category"],"readme":"![DotMake Command-Line Logo](https://raw.githubusercontent.com/dotmake-build/command-line/master/images/logo-wide.png \"DotMake Command-Line Logo\")\n\n# DotMake Command-Line\n\nSystem.CommandLine is a very good parser but you need a lot of boilerplate code to get going and the API is hard to discover.\nThis becomes complicated to newcomers and also you would have a lot of ugly code in your `Program.cs` to maintain. \nWhat if you had an easy class-based layer combined with a good parser?\n\nDotMake.CommandLine is a library which provides declarative syntax for \n[System.CommandLine](https://github.com/dotnet/command-line-api) \nvia attributes for easy, fast, strongly-typed (no reflection) usage. The library includes a source generator \nwhich automagically converts your classes to CLI commands and properties to CLI options or CLI arguments. \nSupports \n[trimming](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-self-contained), \n[AOT compilation](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot) and\n[dependency injection](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection)!\n\n[![Nuget](https://img.shields.io/nuget/v/DotMake.CommandLine?style=for-the-badge\u0026logo=nuget)](https://www.nuget.org/packages/DotMake.CommandLine)\n\n![DotMake Command-Line Intro](https://raw.githubusercontent.com/dotmake-build/command-line/master/images/intro.gif \"DotMake Command-Line Intro\")\n\n![DotMake Command-Line Themes](https://raw.githubusercontent.com/dotmake-build/command-line/master/images/themes.gif \"DotMake Command-Line Themes\")\n\n## Getting started\n\nInstall the library to your console app project with  [NuGet](https://www.nuget.org/).\n\nIn your project directory, via dotnet cli:\n```console\ndotnet add package DotMake.CommandLine\n```\nor in Visual Studio Package Manager Console:\n```console\nPM\u003e Install-Package DotMake.CommandLine\n```\n\n### Prerequisites\n\n- .NET 8.0 and later project or .NET Standard 2.0 and later project.  \n  Note that .NET Framework 4.7.2+ or .NET Core 2.0 to NET 7.0 projects can reference our netstandard2.0 target (automatic in nuget).  \n  If your target framework is below net5.0, you also need `\u003cLangVersion\u003e9.0\u003c/LangVersion\u003e` tag (minimum) in your .csproj file.\n- Visual Studio 2022 v17.3+ or .NET SDK 6.0.407+ (when building via `dotnet` cli).  \n  Our incremental source generator requires performance features added first in these versions.\n- Usually a console app project but you can also use a class library project which will be consumed later.  \n\n## Usage\n\nDotMake.CommandLine offers 2 models: class-based model and delegate-based model.\nDelegate-based model is useful for simple apps, for more complex apps, you should use the class-based model \nbecause you can have sub-commands and command inheritance.\n\n### Class-based model\n\nCreate a CLI App with DotMake.Commandline in seconds!\n\nIn `Program.cs`, add this simple code:\n```c#\nusing System;\nusing DotMake.CommandLine;\n\n// Add this single line to run you app!\nCli.Run\u003cRootCliCommand\u003e(args);\n\n// Create a simple class like this to define your root command:\n[CliCommand(Description = \"A root cli command\")]\npublic class RootCliCommand\n{\n    [CliOption(Description = \"Description for Option1\")]\n    public string Option1 { get; set; } = \"DefaultForOption1\";\n \n    [CliArgument(Description = \"Description for Argument1\")]\n    public string Argument1 { get; set; }\n \n    public void Run()\n    {\n        Console.WriteLine($@\"Handler for '{GetType().FullName}' is run:\");\n        Console.WriteLine($@\"Value for {nameof(Option1)} property is '{Option1}'\");\n        Console.WriteLine($@\"Value for {nameof(Argument1)} property is '{Argument1}'\");\n        Console.WriteLine();\n    }\n}\n```\nAnd that's it! You now have a fully working command-line app. You just specify the name of your class which represents your root command to `Cli.Run\u003c\u003e` method and everything is wired.\n\n\u003e `args` is the string array typically passed to a program. This is usually\nthe special variable `args` available in `Program.cs` (new style with top-level statements)\nor the string array passed to the program's `Main` method (old style).\nWe also have method signatures which does not require `args`, \nfor example you can also call `Cli.Run\u003cRootCliCommand\u003e()` and in that case `args` will be retrieved automatically from the current process via `Cli.GetArgs()`.\n\nIf you want to go async, just use this:\n```c#\nawait Cli.RunAsync\u003cRootCliCommand\u003e(args);\n```\nTo handle exceptions, you just use a try-catch block:\n```c#\ntry\n{\n    Cli.Run\u003cRootCliCommand\u003e(args);\n}\ncatch (Exception e)\n{\n    Console.WriteLine(@\"Exception in main: {0}\", e.Message);\n}\n```\nSystem.CommandLine, by default overtakes your exceptions that are thrown in command handlers\n(even if you don't set an exception handler explicitly) but DotMake.CommandLine, by default allows\nthe exceptions to pass through. However if you wish, you can easily use the default exception handler\nby passing a `CliSettings` instance like below. Default exception handler prints the exception in red color to console:\n```c#\nCli.Run\u003cRootCliCommand\u003e(args, new CliSettings { EnableDefaultExceptionHandler = true });\n```\nIf you need to simply parse the command-line arguments without invocation, use this:\n```c#\nvar parseResult = Cli.Parse\u003cRootCliCommand\u003e(args);\nvar rootCliCommand = parseResult.Bind\u003cRootCliCommand\u003e();\n```\nIf you need to examine the parse result, such as errors:\n```c#\nvar parseResult = Cli.Parse\u003cRootCliCommand\u003e(args);\nif (parseResult.Errors.Count \u003e 0)\n{\n\n}\n```\n#### Summary\n- Mark the class with `CliCommand` attribute to make it a CLI command (see [CliCommandAttribute](https://dotmake.build/api/html/T_DotMake_CommandLine_CliCommandAttribute.htm) docs for more info).\n- Mark a property with `CliOption` attribute to make it a CLI option (see [CliOptionAttribute](https://dotmake.build/api/html/T_DotMake_CommandLine_CliOptionAttribute.htm) docs for more info).\n- Mark a property with `CliArgument` attribute to make it a CLI argument (see [CliArgumentAttribute](https://dotmake.build/api/html/T_DotMake_CommandLine_CliArgumentAttribute.htm) docs for more info).\n- Add a method with name `Run` or `RunAsync` to make it the handler for the CLI command. The method can have one of the following signatures: \n  \n  - \n    ```c#\n    void Run()\n    ```\n  - \n    ```c#\n    int Run()\n    ```\n  - \n    ```c#\n    async Task RunAsync()\n    ```\n  - \n    ```c#\n    async Task\u003cint\u003e RunAsync()\n    ```\n  Optionally the method signature can have a `CliContext` parameter in case you need to access it:\n  \n  - \n    ```c#\n    Run(CliContext context)\n    ```\n  -\n    ```c#  \n    RunAsync(CliContext context)\n    ```\n\n  The signatures which return int value, sets the ExitCode of the app.\n  If no handler method is provided, then by default it will show help for the command.\n  This can be also controlled manually by extension method `ShowHelp` in `CliContext`.\n  Other extension methods `IsEmptyCommand`, `ShowValues` and `ShowHierarchy` are also useful.\n- Call `Cli.Run\u003c\u003e` or`Cli.RunAsync\u003c\u003e` method with your class name to run your CLI app (see [Cli](https://dotmake.build/api/html/T_DotMake_CommandLine_Cli.htm) docs for more info).\n- For best practice, create a subfolder named `Commands` in your project and put your command classes there \n  so that they are easy to locate and maintain in the future.\n\n\n### Delegate-based model\n\nCreate a CLI App with DotMake.Commandline in seconds!\n\nIn `Program.cs`, add this simple code:\n```c#\nusing System;\nusing DotMake.CommandLine;\n\nCli.Run(([CliArgument]string arg1, bool opt1) =\u003e\n{\n    Console.WriteLine($@\"Value for {nameof(arg1)} parameter is '{arg1}'\");\n    Console.WriteLine($@\"Value for {nameof(opt1)} parameter is '{opt1}'\");\n});\n```\nAnd that's it! You now have a fully working command-line app.\n\n#### Summary\n- Pass a delegate (a parenthesized lambda expression or a method reference) which has parameters that represent your options and arguments, to `Cli.Run`.\n- A parameter is by default considered as a CLI option but you can;\n  - Mark a parameter with `CliArgument` attribute to make it a CLI argument and specify settings (see [CliArgumentAttribute](https://dotmake.build/api/html/T_DotMake_CommandLine_CliArgumentAttribute.htm) docs for more info).\n  - Mark a parameter with `CliOption` attribute to specify CLI option settings (see [CliOptionAttribute](https://dotmake.build/api/html/T_DotMake_CommandLine_CliOptionAttribute.htm) docs for more info).\n  - Mark the delegate itself with `CliCommand` attribute to specify CLI command settings (see [CliCommandAttribute](https://dotmake.build/api/html/T_DotMake_CommandLine_CliCommandAttribute.htm) docs for more info).\n  - Note that for being able to mark a parameter with an attribute in an anonymous lambda function, \n    if your target framework is below net6.0, you also need `\u003cLangVersion\u003e10.0\u003c/LangVersion\u003e` tag (minimum) in your .csproj file.\n- Set a default value for a parameter if you want it to be optional (not required to be specified on the command-line).\n- Your delegate can be `async`.\n- Your delegate can have a return type `void` or `int` and if it's async `Task` or `Task\u003cint\u003e`.\n\n\n## Help output\n\nWhen you run the app via \n- `TestApp.exe -?` in project output path (e.g. in `TestApp\\bin\\Debug\\net8.0`)\n- or `dotnet run -- -?` in project directory (e.g. in `TestApp`) (note the double hyphen/dash which allows `dotnet run` to pass arguments to our actual application)\n\n- You see this usage help:\n    ```console\n    DotMake Command-Line TestApp v1.6.0\n    Copyright © 2023-2024 DotMake\n\n    A root cli command\n\n    Usage:\n      TestApp \u003cargument-1\u003e [options]\n\n    Arguments:\n      \u003cargument-1\u003e  Description for Argument1 [required]\n\n    Options:\n      -o, --option-1 \u003coption-1\u003e  Description for Option1 [default: DefaultForOption1]\n      -v, --version              Show version information\n      -?, -h, --help             Show help and usage information\n    ```\n- First line comes from `AssemblyProductAttribute` or `AssemblyName` (`\u003cProduct\u003e` tag in your .csproj file).  \n  Version comes from `AssemblyInformationalVersionAttribute` or `AssemblyFileVersionAttribute` or `AssemblyVersionAttribute`\n  (`\u003cInformationalVersion\u003e` or `\u003cFileVersion \u003e` or `\u003cVersion\u003e` tag in your .csproj file).\n- Second line comes from `AssemblyCopyrightAttribute` (`\u003cCopyright\u003e` tag in your .csproj file).\n- Third line comes from `Description` property of `[CliCommand]` or for root commands, `AssemblyDescriptionAttribute` (`\u003cDescription\u003e` tag in your .csproj file).\n\nNote, how command/option/argument names, descriptions and default values are automatically populated.\n\nBy default,  command/option/argument names are generated as follows;\n- First the following suffixes are stripped out from class and property names:\n    - For commands:\n      \"RootCliCommand\", \"RootCommand\", \"SubCliCommand\", \"SubCommand\", \"CliCommand\", \"Command\", \"Cli\"\n    - For options: \n     \"RootCommandOption\", \"SubCliCommandOption\", \"SubCommandOption\", \"CliCommandOption\", \"CommandOption\", \"CliOption\", \"Option\"\n    - For arguments: \n    \"RootCliCommandArgument\", \"RootCommandArgument\", \"SubCliCommandArgument\", \"SubCommandArgument\", \"CliCommandArgument\", \"CommandArgument\", \"CliArgument\", \"Argument\"\n    \n- Then the names are converted to **kebab-case**, this can be changed by setting `NameCasingConvention`  property of the `CliCommand` attribute to one of the following values:\n  - `CliNameCasingConvention.None`\n  - `CliNameCasingConvention.LowerCase`\n  - `CliNameCasingConvention.UpperCase`\n  - `CliNameCasingConvention.TitleCase`\n  - `CliNameCasingConvention.PascalCase`\n  - `CliNameCasingConvention.CamelCase`\n  - `CliNameCasingConvention.KebabCase`\n  - `CliNameCasingConvention.SnakeCase`\n  \n- For options, double hyphen/dash prefix is added to the name (e.g. `--option`), this can be changed by setting `NamePrefixConvention`  (default: DoubleHyphen) property of the `CliCommand` attribute to one of the following values:\n  - `CliNamePrefixConvention.SingleHyphen`\n  - `CliNamePrefixConvention.DoubleHyphen`\n  - `CliNamePrefixConvention.ForwardSlash`\n  \n- For options, short-form alias with first letter (e.g. `-o`) is automatically added. This can be changed by setting `ShortFormAutoGenerate` (default: true) and `ShortFormPrefixConvention` (default: SingleHyphen) properties of the `CliCommand` attribute.\n\n---\nFor example, change the name casing and prefix convention:\n```c#\nusing System;\nusing DotMake.CommandLine;\n \n[CliCommand(\n    Description = \"A cli command with snake_case name casing and forward slash prefix conventions\",\n    NameCasingConvention = CliNameCasingConvention.SnakeCase,\n    NamePrefixConvention = CliNamePrefixConvention.ForwardSlash,\n    ShortFormPrefixConvention = CliNamePrefixConvention.ForwardSlash\n)]\npublic class RootSnakeSlashCliCommand\n{\n    [CliOption(Description = \"Description for Option1\")]\n    public string Option1 { get; set; } = \"DefaultForOption1\";\n \n    [CliArgument(Description = \"Description for Argument1\")]\n    public string Argument1 { get; set; }\n \n    public void Run()\n    {\n        Console.WriteLine($@\"Handler for '{GetType().FullName}' is run:\");\n        Console.WriteLine($@\"Value for {nameof(Option1)} property is '{Option1}'\");\n        Console.WriteLine($@\"Value for {nameof(Argument1)} property is '{Argument1}'\");\n        Console.WriteLine();\n    }\n}\n```\nWhen you run the app via `TestApp.exe -?` or `dotnet run -- -?`, you see this usage help:\n```console\nDotMake Command-Line TestApp v1.6.0\nCopyright © 2023-2024 DotMake\n\nA cli command with snake_case name casing and forward slash prefix conventions\n\nUsage:\n  TestApp \u003cargument_1\u003e [options]\n\nArguments:\n  \u003cargument_1\u003e  Description for Argument1 [required]\n\nOptions:\n  /o, /option_1 \u003coption_1\u003e  Description for Option1 [default: DefaultForOption1]\n  /v, /version              Show version information\n  -?, -h, /help             Show help and usage information\n```\nNote how even the default options `version` and `help` use the new prefix convention `ForwardSlash`. By the way, as `help` is a special option, which allows user to discover your app, we still add short-form aliases with other prefix to prevent confusion.\n\n### Themes\n\nCli app theme can be changed via setting `CliSettings.Theme` property to predefined themes Red, DarkRed, Green, DarkGreen, Blue, DarkBlue\nor a custom `CliTheme`. These color and formatting option are mainly used by the help output.\n\n```c#\nCli.Run\u003cRootCliCommand\u003e(args, new CliSettings { Theme = CliTheme.Red });\n\nCli.Run\u003cRootCliCommand\u003e(args, new CliSettings { Theme = CliTheme.DarkRed });\n\nCli.Run\u003cRootCliCommand\u003e(args, new CliSettings { Theme = CliTheme.Green });\n\nCli.Run\u003cRootCliCommand\u003e(args, new CliSettings { Theme = CliTheme.DarkGreen });\n\nCli.Run\u003cRootCliCommand\u003e(args, new CliSettings { Theme = CliTheme.Blue });\n\nCli.Run\u003cRootCliCommand\u003e(args, new CliSettings { Theme = CliTheme.DarkBlue });\n\nCli.Run\u003cRootCliCommand\u003e(args, new CliSettings\n{\n    Theme = new CliTheme(CliTheme.Default)\n    {\n        HeadingCasing = CliNameCasingConvention.UpperCase,\n        HeadingNoColon = true\n    }\n});\n```\n\nNote that [NO_COLOR](https://no-color.org/) is supported, i.e. if `NO_COLOR` environment variable is set, the colors will be disabled.\n\n### Localization\n\nLocalizing commands, options and arguments is supported.\nYou can specify a `nameof` operator expression with a resource property (generated by resx) in the attribute's argument (for `string` types only)\nand the source generator will smartly use the resource property accessor as the value of the argument so that it can localize at runtime.\nIf the property in the `nameof` operator expression does not point to a resource property, then the name of that property will be used as usual.\nThe reason we use `nameof` operator is that attributes in `.NET` only accept compile-time constants and you get `CS0182` error if not,\nso specifying resource property directly is not possible as it's not a compile-time constant but it's a static property access.\n\n```c#\n[CliCommand(Description = nameof(TestResources.CommandDescription))]\ninternal class LocalizedCliCommand\n{\n    [CliOption(Description = nameof(TestResources.OptionDescription))]\n    public string Option1 { get; set; } = \"DefaultForOption1\";\n\n    [CliArgument(Description = nameof(TestResources.ArgumentDescription))]\n    public string Argument1 { get; set; }\n\n    public void Run()\n    {\n        Console.WriteLine($@\"Handler for '{GetType().FullName}' is run:\");\n        Console.WriteLine($@\"Value for {nameof(Option1)} property is '{Option1}'\");\n        Console.WriteLine($@\"Value for {nameof(Argument1)} property is '{Argument1}'\");\n        Console.WriteLine();\n    }\n}\n```\n\n### Triggering help\n\nIf a command represents a group and not an action, you may want to show help. \nIf `Run` or `RunAsync` method is missing in a command class, then by default it will show help. \nYou can also manually trigger help in `Run` or `RunAsync` method of a command class via calling `CliContext.ShowHelp`.\nFor testing a command, these methods are also useful:\n- `CliContext.IsEmptyCommand` gets value indicating whether current command is specified without any arguments or options.\n  Note that arguments and options should be optional, if they are required (no default values),\n  then handler will not run and missing error message will be shown.\n- `CliContext.ShowValues` shows parsed values for current command and its arguments and options.\n- `CliContext.ShowHierarchy` shows hierarchy for all commands, it will start from the root command and show a tree.\n\nSee below example; root command does not have a handler method so it will always show help \nand sub-command will show help if command is specified without any arguments or option, \nand it will show (dump) values if not:\n\n```c#\n[CliCommand(Description = \"A root cli command\")]\npublic class HelpCliCommand\n{\n  [CliOption(Description = \"Description for Option1\")]\n  public string Option1 { get; set; } = \"DefaultForOption1\";\n\n  [CliArgument(Description = \"Description for Argument1\")]\n  public string Argument1 { get; set; } = \"DefaultForArgument1\";\n\n  [CliCommand(Description = \"A sub cli command\")]\n  public class SubCliCommand\n  {\n      [CliArgument(Description = \"Description for Argument2\")]\n      public string Argument2 { get; set; } = \"DefaultForArgument2\";\n\n      public void Run(CliContext context)\n      {\n          if (context.IsEmptyCommand())\n              context.ShowHelp();\n          else\n              context.ShowValues();\n      }\n  }\n}\n```\n\n## Commands\n\nA *command* in command-line input is a token that specifies an action or defines a group of related actions. For example:\n\n* In `dotnet run`, `run` is a command that specifies an action.\n* In `dotnet tool install`, `install` is a command that specifies an action, and `tool` is a command that specifies a group of related commands. There are other tool-related commands, such as `tool uninstall`, `tool list`, and `tool update`.\n\n### Root commands\n\nThe *root command* is the one that specifies the name of the app's executable. For example, the `dotnet` command specifies the *dotnet.exe* executable.\n\n### Subcommands\n\nMost command-line apps support *subcommands*, also known as *verbs*. For example, the `dotnet` command has a `run` subcommand that you invoke by entering `dotnet run`.\n\nSubcommands can have their own subcommands. In `dotnet tool install`, `install` is a subcommand of `tool`.\n\n### Command Hierarchy\n\nDefining sub-commands in DotMake.Commandline is very easy. We simply use nested classes to create a hierarchy.\nJust make sure you apply `CliCommand` attribute to the nested classes as well:\n```c#\n/*\n    Command hierarchy in below example is:\n        \n     TestApp\n     └╴level-1\n       └╴level-2\n*/\n\n[CliCommand(Description = \"A root cli command with nested children\")]\npublic class RootWithNestedChildrenCliCommand\n{\n    [CliOption(Description = \"Description for Option1\")]\n    public string Option1 { get; set; } = \"DefaultForOption1\";\n\n    [CliArgument(Description = \"Description for Argument1\")]\n    public string Argument1 { get; set; } = \"DefaultForArgument1\";\n\n    public void Run(CliContext context)\n    {\n        if (context.IsEmptyCommand())\n            context.ShowHierarchy();\n        else\n            context.ShowValues();\n    }\n\n    [CliCommand(Description = \"A nested level 1 sub-command\")]\n    public class Level1SubCliCommand\n    {\n        [CliOption(Description = \"Description for Option1\")]\n        public string Option1 { get; set; } = \"DefaultForOption1\";\n\n        [CliArgument(Description = \"Description for Argument1\")]\n        public string Argument1 { get; set; }\n\n        public void Run(CliContext context)\n        {\n            context.ShowValues();\n        }\n\n        [CliCommand(Description = \"A nested level 2 sub-command\")]\n        public class Level2SubCliCommand\n        {\n            [CliOption(Description = \"Description for Option1\")]\n            public string Option1 { get; set; } = \"DefaultForOption1\";\n\n            [CliArgument(Description = \"Description for Argument1\")]\n            public string Argument1 { get; set; }\n\n            public void Run(CliContext context)\n            {\n                context.ShowValues();\n            }\n        }\n    }\n}\n```\n\nAnother way to create hierarchy between commands, especially if you want to use standalone classes,  \nis to \n- Use `Children` property of `CliCommand` attribute to specify array of `typeof` child classes:\n```c#\n/*\n    Command hierarchy in below example is:\n\n     TestApp\n     └╴external-level-1\n       └╴external-level-2\n*/\n\n[CliCommand(\n    Description = \"A root cli command with external children\",\n    Children = new []\n    {\n        typeof(ExternalLevel1SubCliCommand)\n    }\n)]\npublic class RootWithExternalChildrenCliCommand\n{\n    [CliOption(Description = \"Description for Option1\")]\n    public string Option1 { get; set; } = \"DefaultForOption1\";\n\n    [CliArgument(Description = \"Description for Argument1\")]\n    public string Argument1 { get; set; } = \"DefaultForArgument1\";\n\n    public void Run(CliContext context)\n    {\n        if (context.IsEmptyCommand())\n            context.ShowHierarchy();\n        else\n            context.ShowValues();\n    }\n}\n\n[CliCommand(\n    Description = \"An external level 1 sub-command\",\n    Children = new[]\n    {\n        typeof(ExternalLevel2SubCliCommand)\n    }\n)]\npublic class ExternalLevel1SubCliCommand\n{\n    [CliOption(Description = \"Description for Option1\")]\n    public string Option1 { get; set; } = \"DefaultForOption1\";\n\n    [CliArgument(Description = \"Description for Argument1\")]\n    public string Argument1 { get; set; }\n\n    public void Run(CliContext context)\n    {\n        context.ShowValues();\n    }\n}\n\n[CliCommand(Description = \"An external level 2 sub-command\")]\npublic class ExternalLevel2SubCliCommand\n{\n    [CliOption(Description = \"Description for Option1\")]\n    public string Option1 { get; set; } = \"DefaultForOption1\";\n\n    [CliArgument(Description = \"Description for Argument1\")]\n    public string Argument1 { get; set; }\n\n    public void Run(CliContext context)\n    {\n        context.ShowValues();\n    }\n}\n\n```\n\n- Use `Parent` property of `CliCommand` attribute to specify `typeof` parent class:\n```c#\n/*\n    Command hierarchy in below example is:\n\n     TestApp\n     └╴external-level-1-with-parent\n       └╴external-level-2-with-parent\n*/\n\n[CliCommand(\n    Description = \"A root cli command with external children\"\n)]\npublic class RootAsExternalParentCliCommand\n{\n    [CliOption(Description = \"Description for Option1\")]\n    public string Option1 { get; set; } = \"DefaultForOption1\";\n\n    [CliArgument(Description = \"Description for Argument1\")]\n    public string Argument1 { get; set; } = \"DefaultForArgument1\";\n\n    public void Run(CliContext context)\n    {\n        if (context.IsEmptyCommand())\n            context.ShowHierarchy();\n        else\n            context.ShowValues();\n    }\n}\n\n[CliCommand(\n    Description = \"An external level 1 sub-command\",\n    Parent = typeof(RootAsExternalParentCliCommand)\n)]\npublic class ExternalLevel1WithParentSubCliCommand\n{\n    [CliOption(Description = \"Description for Option1\")]\n    public string Option1 { get; set; } = \"DefaultForOption1\";\n\n    [CliArgument(Description = \"Description for Argument1\")]\n    public string Argument1 { get; set; }\n\n    public void Run(CliContext context)\n    {\n        context.ShowValues();\n    }\n}\n\n[CliCommand(\n    Description = \"An external level 2 sub-command\",\n    Parent = typeof(ExternalLevel1WithParentSubCliCommand)\n)]\npublic class ExternalLevel2WithParentSubCliCommand\n{\n    [CliOption(Description = \"Description for Option1\")]\n    public string Option1 { get; set; } = \"DefaultForOption1\";\n\n    [CliArgument(Description = \"Description for Argument1\")]\n    public string Argument1 { get; set; }\n\n    public void Run(CliContext context)\n    {\n        context.ShowValues();\n    }\n}\n\n```\n\nThe class that `CliCommand` attribute is applied to,\n- will be a root command if the class is not a nested class and other's `Children` property and self's `Parent` property is not set.\n- will be a sub command if the class is a nested class or other's `Children` property or self's `Parent` property is set.\n\nYou can create a complex hierarchy like this by mixing nested classes and external classes:\n```c#\n TestApp\n ├╴external-level-1-with-nested\n │ └╴level-2\n └╴level_1\n   └╴external_level_2_with_nested\n     └╴level_3\n```\n`Parent` property can even refer to a nested class in another class, `Children` property can not because having a nested parent\nis higher priority. A nested child can use `Children` property to refer non-nested classes though.\n\n#### Accessing parent commands\n\nSub-commands can get a reference to the parent command by adding a property of the parent command type.  \nAlternatively `ParseResult.Bind\u003cTDefinition\u003e` method can be called to manually get reference to a parent command.  \nNote that binding will be done only once per definition class, so calling this method consecutively\nfor the same definition class will return the cached result.\n\n```c#\n// Sub-commands can get a reference to the parent command by adding a property of the parent command type.\n\n[CliCommand(Description = \"A root cli command with children that can access parent commands\")]\npublic class ParentCommandAccessorCliCommand\n{\n    [CliOption(\n        Description = \"This is a global option (Recursive option on the root command), it can appear anywhere on the command line\",\n        Recursive = true)]\n    public string GlobalOption1 { get; set; } = \"DefaultForGlobalOption1\";\n\n    [CliArgument(Description = \"Description for RootArgument1\")]\n    public string RootArgument1 { get; set; }\n\n    public void Run(CliContext context)\n    {\n        context.ShowValues();\n    }\n\n    [CliCommand(Description = \"A nested level 1 sub-command which accesses the root command\")]\n    public class Level1SubCliCommand\n    {\n        [CliOption(\n            Description = \"This is global for all sub commands (it can appear anywhere after the level-1 verb)\",\n            Recursive = true)]\n        public string Level1RecursiveOption1 { get; set; } = \"DefaultForLevel1RecusiveOption1\";\n\n        [CliArgument(Description = \"Description for Argument1\")]\n        public string Argument1 { get; set; }\n\n        // The parent command gets automatically injected\n        public ParentCommandAccessorCliCommand RootCommand { get; set; }\n\n        public void Run(CliContext context)\n        {\n            context.ShowValues();\n        }\n\n        [CliCommand(Description = \"A nested level 2 sub-command which accesses its parent commands\")]\n        public class Level2SubCliCommand\n        {\n            [CliOption(Description = \"Description for Option1\")]\n            public string Option1 { get; set; } = \"DefaultForOption1\";\n\n            [CliArgument(Description = \"Description for Argument1\")]\n            public string Argument1 { get; set; }\n\n            // All ancestor commands gets injected\n            public ParentCommandAccessorCliCommand RootCommand { get; set; }\n            public Level1SubCliCommand ParentCommand { get; set; }\n\n            public void Run(CliContext context)\n            {\n                context.ShowValues();\n\n                Console.WriteLine();\n                Console.WriteLine(@$\"Level1RecursiveOption1 = {ParentCommand.Level1RecursiveOption1}\");\n                Console.WriteLine(@$\"parent Argument1 = {ParentCommand.Argument1}\");\n                Console.WriteLine(@$\"GlobalOption1 = {RootCommand.GlobalOption1}\");\n                Console.WriteLine(@$\"RootArgument1 = {RootCommand.RootArgument1}\");\n            }\n        }\n    }\n}\n```\n\n### Command Inheritance\n\nWhen you have repeating/common options and arguments for your commands, you can define them once in a base class and then \nshare them by inheriting that base class in other command classes. Interfaces are also supported !\n\n```c#\n[CliCommand]\npublic class InheritanceCliCommand : CredentialCommandBase, IDepartmentCommand\n{\n    public string Department { get; set; } = \"Accounting\";\n}\n\npublic abstract class CredentialCommandBase\n{\n    [CliOption(Description = \"Username of the identity performing the command\")]\n    public string Username { get; set; } = \"admin\";\n\n    [CliOption(Description = \"Password of the identity performing the command\")]\n    public string Password { get; set; }\n\n    public void Run()\n    {\n        Console.WriteLine($@\"I am {Username}\");\n    }\n}\n\npublic interface IDepartmentCommand\n{\n    [CliOption(Description = \"Department of the identity performing the command (interface)\")]\n    string Department { get; set; }\n}\n```\n\nThe property attribute and the property initializer from the most derived class in the hierarchy will be used \n(they will override the base ones). The command handler (Run or RunAsync) will be also inherited.\nSo in the above example, `InheritanceCliCommand` inherits options `Username`, `Password` from a base class and\noption `Department` from an interface. Note that the property initializer for `Department` is in the derived class, \nso that default value will be used.\n\n---\nThe properties for `CliCommand` attribute (see [CliCommandAttribute](https://dotmake.build/api/html/T_DotMake_CommandLine_CliCommandAttribute.htm) docs for more info):\n- Name\n- Description\n- Aliases\n- Hidden\n- Parent\n- TreatUnmatchedTokensAsErrors\n- NameCasingConvention *(inherited by child options, child arguments and subcommands)*\n- NamePrefixConvention *(inherited by child options and subcommands)*\n- ShortFormPrefixConvention *(inherited by child options and subcommands)*\n- ShortFormAutoGenerate *(inherited by child options and subcommands)*\n\n## Options\n\nAn option is a named parameter that can be passed to a command. [POSIX](https://en.wikipedia.org/wiki/POSIX) CLIs typically prefix the option name with two hyphens (`--`). The following example shows two options:\n\n```dotnetcli\ndotnet tool update dotnet-suggest --verbosity quiet --global\n                                  ^---------^       ^------^\n```\n\nAs this example illustrates, the value of the option may be explicit (`quiet` for `--verbosity`) or implicit (nothing follows `--global`). Options that have no value specified are typically Boolean parameters that default to `true` if the option is specified on the command line.\n\nFor some Windows command-line apps, you identify an option by using a leading slash (`/`) with the option name. For example:\n\n```console\nmsbuild /version\n        ^------^\n```\n\nBoth POSIX and Windows prefix conventions are supported.\nWhen manually setting a name (overriding decorated property's name), you should specify the option name including the prefix (e.g. `--option`, `-o`, `-option` or `/option`).\n\nBundling of single-character options are supported, also known as stacking.\nBundled options are single-character option aliases specified together after a single hyphen prefix.\nFor example if you have options \"-a\", \"-b\" and \"-c\", you can bundle them like \"-abc\".\nOnly the last option can specify an argument.\nNote that if you have an explicit option named \"-abc\" then it will win over bundled options.\n\n---\nThe properties for `CliOption` attribute (see [CliOptionAttribute](https://dotmake.build/api/html/T_DotMake_CommandLine_CliOptionAttribute.htm) docs for more info):\n- Name\n- Description\n- Aliases\n- HelpName\n- Hidden\n- Required\n- Recursive\n- Arity\n- AllowedValues\n- AllowMultipleArgumentsPerToken\n- ValidationRules\n- ValidationPattern\n- ValidationMessage\n\n## Arguments\n\nAn argument is a value passed to an option or a command. The following examples show an argument for the `verbosity` option and an argument for the `build` command.\n\n```console\ndotnet tool update dotnet-suggest --verbosity quiet --global\n                                              ^---^\n```\n\n```console\ndotnet build myapp.csproj\n             ^----------^\n```\n\nArguments can have default values that apply if no argument is explicitly provided. For example, many options are implicitly Boolean parameters with a default of `true` when the option name is in the command line. The following command-line examples are equivalent:\n\n```dotnetcli\ndotnet tool update dotnet-suggest --global\n                                  ^------^\n\ndotnet tool update dotnet-suggest --global true\n                                  ^-----------^\n```\n\nSome options have required arguments. For example in the .NET CLI, `--output` requires a folder name argument. If the argument is not provided, the command fails.\n\nArguments can have expected types, and `System.CommandLine` displays an error message if an argument can't be parsed into the expected type. For example, the following command errors because \"silent\" isn't one of the valid values for `--verbosity`:\n\n```dotnetcli\ndotnet build --verbosity silent\n```\n\n```output\nCannot parse argument 'silent' for option '-v' as expected type 'Microsoft.DotNet.Cli.VerbosityOptions'. Did you mean one of the following?\nDetailed\nDiagnostic\nMinimal\nNormal\nQuiet\n```\n\n---\nThe properties for `CliArgument` attribute (see [CliArgumentAttribute](https://dotmake.build/api/html/T_DotMake_CommandLine_CliArgumentAttribute.htm) docs for more info):\n- Name\n- Description\n- HelpName\n- Hidden\n- Required\n- Arity\n- AllowedValues\n- ValidationRules\n- ValidationPattern\n- ValidationMessage\n\n## Model binding\n\nWhen the command handler is run, the properties for CLI options and arguments will be already populated \nand bound from values passed in the command-line. If no matching value is passed, the property will have its default value if\nit has one or an error will be displayed if it's a required option/argument and it was not specified on the command-line.\n\nAn option/argument will be considered required when\n- There is no property initializer and the property type is a reference type (e.g. `public string Arg { get; set; }`). \n  `string` is a reference type which has a null as the default value but `bool` and `enum` are value\n  types which already have non-null default values. `Nullable\u003cT\u003e` is a reference type, e.g. `bool?`.\n- There is a property initializer, but it's initialized with `null` or `null!` (SuppressNullableWarningExpression)\n  (e.g. `public string Arg { get; set; } = null!;`).\n- If it's forced via attribute property `Required` (e.g. `[CliArgument(Required = true)]`).\n- If it's forced via `required` modifier (e.g. `public required string Opt { get; set; }`).\n  Note that for being able to use `required` modifier, if your target framework is below net7.0, \n  you also need `\u003cLangVersion\u003e11.0\u003c/LangVersion\u003e` tag (minimum) in your .csproj file (our source generator supplies the polyfills\n  automatically as long as you set C# language version to 11).\n\nAn option/argument will be considered optional when\n- There is no property initializer (e.g. `public bool Opt { get; set; }`) but the property type is a value type \n  which already have non-null default value.\n- There is a property initializer, and it's not initialized with `null` or `null!` (SuppressNullableWarningExpression)\n  (e.g. `public string Arg { get; set; } = \"Default\";`).\n- If it's forced via attribute property `Required` (e.g. `[CliArgument(Required = false)]`).\n---\nWhen you run,\n```console\nTestApp.exe NewValueForArgument1\n```\nor (note the double hyphen/dash which allows `dotnet run` to pass arguments to our actual application):\n```console\ndotnet run -- NewValueForArgument1\n```\nYou see this result:\n```console\nHandler for 'TestApp.Commands.RootCliCommand' is run:\nValue for Option1 property is 'DefaultForOption1'\nValue for Argument1 property is 'NewValueForArgument1'\n```\n---\n### Supported types\nNote that you can have a specific type (other than `string`) for a property which a `CliOption` or `CliArgument` attribute is applied to, for example these properties will be parsed and bound/populated automatically:\n```c#\n[CliCommand]\npublic class WriteFileCliCommand\n{\n    [CliArgument]\n    public FileInfo OutputFile { get; set; }\n\n    [CliOption]\n    public List\u003cstring\u003e Lines { get; set; }\n}\n```\nThe following types for properties are supported:\n* Booleans (flags) - If `true` or `false` is passed for an option having a `bool` argument, it is parsed and bound as expected.\n  But an option whose argument type is `bool` doesn't require an argument to be specified.\n  The presence of the option token on the command line, with no argument following it, results in a value of `true`.\n* Enums - The values are bound by name, and the binding is case insensitive\n* Common CLR types:\n  \n  * `FileSystemInfo`, `FileInfo`, `DirectoryInfo`\n  * `int`, `long`, `short`, `uint`, `ulong`, `ushort`\n  * `double`, `float`, `decimal`\n  * `byte`, `sbyte`\n  * `DateTime`, `DateTimeOffset`, `TimeSpan`, `DateOnly`, `TimeOnly`\n  * `Guid`\n  * `Uri`, `IPAddress`, `IPEndPoint`\n\n* Any type with a public constructor or a static `Parse` method with a string parameter (other parameters, if any, should be optional) - These types can be bound/parsed \n  automatically even if they are wrapped with `Enumerable` or `Nullable` type.\n    ```c#\n    [CliCommand]\n    public class ArgumentConverterCliCommand\n    {\n        [CliOption]\n        public ClassWithConstructor Opt { get; set; }\n\n        [CliOption(AllowMultipleArgumentsPerToken = true)]\n        public ClassWithConstructor[] OptArray { get; set; }\n\n        [CliOption]\n        public CustomStruct? OptNullable { get; set; }\n\n        [CliOption]\n        public IEnumerable\u003cClassWithConstructor\u003e OptEnumerable { get; set; }\n\n        [CliOption]\n        public List\u003cClassWithConstructor\u003e OptList { get; set; }\n\n        [CliOption]\n        public CustomList\u003cClassWithConstructor\u003e OptCustomList { get; set; }\n\n        [CliArgument]\n        public IEnumerable\u003cClassWithParser\u003e Arg { get; set; }\n    }\n\n    public class ClassWithConstructor\n    {\n        private readonly string value;\n\n        public ClassWithConstructor(string value)\n        {\n            this.value = value;\n        }\n\n        public override string ToString()\n        {\n            return value;\n        }\n    }\n    \n    public class ClassWithParser\n    {\n        private string value;\n\n        public override string ToString()\n        {\n            return value;\n        }\n\n        public static ClassWithParser Parse(string value)\n        {\n            var instance = new ClassWithParser();\n            instance.value = value;\n            return instance;\n        }\n    }\n\n    public struct CustomStruct\n    {\n        private readonly string value;\n\n        public CustomStruct(string value)\n        {\n            this.value = value;\n        }\n\n        public override string ToString()\n        {\n            return value;\n        }\n    }\n    ```\n  \n* Arrays, lists, collections:\n  \n  * Any type that implements `IEnumerable\u003cT\u003e` and has a public constructor with a `IEnumerable\u003cT\u003e` or `IList\u003cT\u003e` parameter \n    (other parameters, if any, should be optional). CLR collection types already satisfy this condition.\n  \n  * If type is generic `IEnumerable\u003cT\u003e`, `IList\u003cT\u003e`, `ICollection\u003cT\u003e` interfaces itself, array `T[]` will be used to create an instance.\n  \n  * If type is non-generic `IEnumerable`, `IList`, `ICollection` interfaces itself, array `string[]` will be used to create an instance.\n  \n  ```c#\n  [CliCommand]\n  public class EnumerableCliCommand\n  {\n      [CliOption]\n      public IEnumerable\u003cint\u003e OptEnumerable { get; set; }\n\n      [CliOption]\n      public List\u003cstring\u003e OptList { get; set; }\n\n      [CliOption(AllowMultipleArgumentsPerToken = true)]\n      public FileAccess[] OptEnumArray { get; set; }\n\n      [CliOption]\n      public Collection\u003cstring\u003e OptCollection { get; set; }\n\n      [CliOption]\n      public HashSet\u003cstring\u003e OptHashSet { get; set; }\n\n      [CliOption]\n      public Queue\u003cFileInfo\u003e OptQueue { get; set; }\n\n      [CliOption]\n      public CustomList\u003cstring\u003e OptCustomList { get; set; }\n\n      [CliArgument]\n      public IList ArgIList { get; set; }\n  }\n\n  public class CustomList\u003cT\u003e : List\u003cT\u003e\n  {\n      public CustomList(IEnumerable\u003cT\u003e items)\n          : base(items)\n      {\n\n      }\n  }\n  ```\n\n### Validation\n\nIn `[CliOption]` and `[CliArgument]` attributes;\n`ValidationRules` property allows setting predefined validation rules such as\n- `CliValidationRules.ExistingFile`\n- `CliValidationRules.NonExistingFile`\n- `CliValidationRules.ExistingDirectory`\n- `CliValidationRules.NonExistingDirectory`\n- `CliValidationRules.ExistingFileOrDirectory`\n- `CliValidationRules.NonExistingFileOrDirectory`\n- `CliValidationRules.LegalPath`\n- `CliValidationRules.LegalFileName`\n- `CliValidationRules.LegalUri` \n- `CliValidationRules.LegalUrl`\n\nValidation rules can be combined via using bitwise 'or' operator(`|` in C#).\n\n`ValidationPattern` property allows setting a regular expression pattern for custom validation,\nand `ValidationMessage` property allows setting a custom error message to show when `ValidationPattern` does not match.\n\n```c#\n[CliCommand]\npublic class ValidationCliCommand\n{\n    [CliOption(Required = false, ValidationRules = CliValidationRules.ExistingFile)]\n    public FileInfo OptFile1 { get; set; }\n\n    [CliOption(Required = false, ValidationRules = CliValidationRules.NonExistingFile | CliValidationRules.LegalPath)]\n    public string OptFile2 { get; set; }\n\n    [CliOption(Required = false, ValidationPattern = @\"(?i)^[a-z]+$\")]\n    public string OptPattern1 { get; set; }\n\n    [CliOption(Required = false, ValidationPattern = @\"(?i)^[a-z]+$\", ValidationMessage = \"Custom error message\")]\n    public string OptPattern2 { get; set; }\n\n    [CliOption(Required = false, ValidationRules = CliValidationRules.LegalUrl)]\n    public string OptUrl { get; set; }\n\n    [CliOption(Required = false, ValidationRules = CliValidationRules.LegalUri)]\n    public string OptUri { get; set; }\n\n    [CliArgument(Required = false, ValidationRules = CliValidationRules.LegalFileName)]\n    public string OptFileName { get; set; }\n\n    public void Run(CliContext context)\n    {\n        context.ShowValues();\n    }\n}\n```\n\n## Dependency Injection\n\nCommands can have injected dependencies, this is supported via `Microsoft.Extensions.DependencyInjection` package (version \u003e= 2.1.1).\nIn your project directory, via dotnet cli:\n```console\ndotnet add package Microsoft.Extensions.DependencyInjection\n```\nor in Visual Studio Package Manager Console:\n```console\nPM\u003e Install-Package Microsoft.Extensions.DependencyInjection\n```\nWhen the source generator detects that your project has reference to `Microsoft.Extensions.DependencyInjection`,\nit will generate extension methods for supporting dependency injection.\nFor example, you can now add your services with the extension method `Cli.Ext.ConfigureServices`:\n```c#\nusing DotMake.CommandLine;\nusing Microsoft.Extensions.DependencyInjection;\n\nCli.Ext.ConfigureServices(services =\u003e\n{\n    services.AddTransient\u003cTransientClass\u003e();\n    services.AddScoped\u003cScopedClass\u003e();\n    services.AddSingleton\u003cSingletonClass\u003e();\n});\n\nCli.Run\u003cRootCliCommand\u003e();\n```\nThen let them be injected to your command class automatically by providing a constructor with the required services:\n```c#\n[CliCommand(Description = \"A root cli command with dependency injection\")]\npublic class RootCliCommand\n{\n    private readonly TransientClass transientDisposable;\n    private readonly ScopedClass scopedDisposable;\n    private readonly SingletonClass singletonDisposable;\n\n    public RootCliCommand(\n        TransientClass transientDisposable,\n        ScopedClass scopedDisposable,\n        SingletonClass singletonDisposable\n    )\n    {\n        this.transientDisposable = transientDisposable;\n        this.scopedDisposable = scopedDisposable;\n        this.singletonDisposable = singletonDisposable;\n    }\n\n    [CliOption(Description = \"Description for Option1\")]\n    public string Option1 { get; set; } = \"DefaultForOption1\";\n\n    [CliArgument(Description = \"Description for Argument1\")]\n    public string Argument1 { get; set; }\n\n    public void Run()\n    {\n        Console.WriteLine($@\"Handler for '{GetType().FullName}' is run:\");\n        Console.WriteLine($@\"Value for {nameof(Option1)} property is '{Option1}'\");\n        Console.WriteLine($@\"Value for {nameof(Argument1)} property is '{Argument1}'\");\n        Console.WriteLine();\n\n        Console.WriteLine($\"Instance for {transientDisposable.Name} is available\");\n        Console.WriteLine($\"Instance for {scopedDisposable.Name} is available\");\n        Console.WriteLine($\"Instance for {singletonDisposable.Name} is available\");\n        Console.WriteLine();\n    }\n}\n\npublic sealed class TransientClass : IDisposable\n{\n    public string Name =\u003e nameof(TransientClass);\n\n    public void Dispose() =\u003e Console.WriteLine($\"{nameof(TransientClass)}.Dispose()\");\n}\n\npublic sealed class ScopedClass : IDisposable\n{\n    public string Name =\u003e nameof(ScopedClass);\n\n    public void Dispose() =\u003e Console.WriteLine($\"{nameof(ScopedClass)}.Dispose()\");\n}\n\npublic sealed class SingletonClass : IDisposable\n{\n    public string Name =\u003e nameof(SingletonClass);\n\n    public void Dispose() =\u003e Console.WriteLine($\"{nameof(SingletonClass)}.Dispose()\");\n}\n```\nOther dependency injection containers (e.g. Autofac) are also supported \nvia `Microsoft.Extensions.DependencyInjection.Abstractions` package (version \u003e= 2.1.1).\nIn your project directory, via dotnet cli:\n```console\ndotnet add package Microsoft.Extensions.DependencyInjection.Abstractions\n```\nor in Visual Studio Package Manager Console:\n```console\nPM\u003e Install-Package Microsoft.Extensions.DependencyInjection.Abstractions\n```\nWhen the source generator detects that your project has reference to `Microsoft.Extensions.DependencyInjection.Abstractions`,\nit will generate extension methods for supporting custom service providers.\nFor example, you can now set your custom service provider with the extension method `Cli.Ext.SetServiceProvider`:\n```c#\nusing DotMake.CommandLine;\nusing Autofac.Core;\nusing Autofac.Core.Registration;\n\nvar cb = new ContainerBuilder();\ncb.RegisterType\u003cobject\u003e();\nvar container = cb.Build();\n\nCli.Ext.SetServiceProvider(container);\n\nCli.Run\u003cRootCliCommand\u003e();\n```\n\n## Response files\n\nA *response file* is a file that contains a set of tokens for a command-line app. Response files are a feature of `System.CommandLine` that is useful in two scenarios:\n\n* To invoke a command-line app by specifying input that is longer than the character limit of the terminal.\n* To invoke the same command repeatedly without retyping the whole line.\n\nTo use a response file, enter the file name prefixed by an `@` sign wherever in the line you want to insert commands, options, and arguments. The *.rsp* file extension is a common convention, but you can use any file extension.\n\nThe following lines are equivalent:\n\n```dotnetcli\ndotnet build --no-restore --output ./build-output/\ndotnet @sample1.rsp\ndotnet build @sample2.rsp --output ./build-output/\n```\n\nContents of *sample1.rsp*:\n\n```console\nbuild\n--no-restore \n--output\n./build-output/\n```\n\nContents of *sample2.rsp*:\n\n```console\n--no-restore\n```\n\nHere are syntax rules that determine how the text in a response file is interpreted:\n\n* Tokens are delimited by spaces. A line that contains *Good morning!* is treated as two tokens, *Good* and *morning!*.\n* Multiple tokens enclosed in quotes are interpreted as a single token. A line that contains *\"Good morning!\"* is treated as one token, *Good morning!*.\n* Any text between a `#` symbol and the end of the line is treated as a comment and ignored.\n* Tokens prefixed with `@` can reference additional response files.\n* The response file can have multiple lines of text. The lines are concatenated and interpreted as a sequence of tokens.\n\n## Directives\n\n`System.CommandLine` introduces a syntactic element called a *directive*. The `[diagram]` directive is an example. When you include `[diagram]` after the app's name, `System.CommandLine` displays a diagram of the parse result instead of invoking the command-line app:\n\n```dotnetcli\ndotnet [diagram] build --no-restore --output ./build-output/\n       ^-----^\n```\n\n```output\n[ dotnet [ build [ --no-restore \u003cTrue\u003e ] [ --output \u003c./build-output/\u003e ] ] ]\n```\n\nThe purpose of directives is to provide cross-cutting functionality that can apply across command-line apps. Because directives are syntactically distinct from the app's own syntax, they can provide functionality that applies across apps.\n\nA directive must conform to the following syntax rules:\n\n* It's a token on the command line that comes after the app's name but before any subcommands or options.\n* It's enclosed in square brackets.\n* It doesn't contain spaces.\n\nAn unrecognized directive is ignored without causing a parsing error.\n\nA directive can include an argument, separated from the directive name by a colon.\n\nThe following directives are built in:\n\n### The `[diagram]` directive\n\nThis directive can be enabled with `CliSettings.EnableDiagramDirective`.\n\nBoth users and developers may find it useful to see how an app will interpret a given input. One of the default features of a `System.CommandLine` app is the `[diagram]` directive, which lets you preview the result of parsing command input. For example:\n\n```console\nmyapp [diagram] --delay not-an-int --interactive --file filename.txt extra\n```\n\n```output\n![ myapp [ --delay !\u003cnot-an-int\u003e ] [ --interactive \u003cTrue\u003e ] [ --file \u003cfilename.txt\u003e ] *[ --fgcolor \u003cWhite\u003e ] ]   ???--\u003e extra\n```\n\nIn the preceding example:\n\n* The command (`myapp`), its child options, and the arguments to those options are grouped using square brackets.\n* For the option result `[ --delay !\u003cnot-an-int\u003e ]`, the `!` indicates a parsing error. The value `not-an-int` for an `int` option can't be parsed to the expected type. The error is also flagged by `!` in front of the command that contains the errored option: `![ myapp...`.\n* For the option result `*[ --fgcolor \u003cWhite\u003e ]`, the option wasn't specified on the command line, so the configured default was used. `White` is the effective value for this option. The asterisk indicates that the value is the default.\n* `???--\u003e` points to input that wasn't matched to any of the app's commands or options.\n\n### The `[suggest]` directive\n\nThis directive is enabled by default and can be disabled with `CliSettings.EnableSuggestDirective`.\n\nThe `[suggest]` directive lets you search for commands when you don't know the exact command.\n\n```dotnetcli\ndotnet [suggest] buil\n```\n\n```output\nbuild\nbuild-server\nmsbuild\n```\n\n### The environment variables directive\n\nThis directive can be enabled with `CliSettings.EnableEnvironmentVariablesDirective`.\n\nEnables the use of the `[env:key=value]` directive, allowing environment variables to be set from the command line during invocation.\n\n## Additional documentation\n- [DotMake Command-Line API docs](https://dotmake.build/api/)\n- [Command-line syntax overview for System.CommandLine](https://learn.microsoft.com/en-us/dotnet/standard/commandline/syntax)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdotmake-build%2Fcommand-line","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdotmake-build%2Fcommand-line","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdotmake-build%2Fcommand-line/lists"}