diff --git a/Docs/CustomConverters.md b/Docs/CustomConverters.md index 8b670fb..34742fa 100644 --- a/Docs/CustomConverters.md +++ b/Docs/CustomConverters.md @@ -9,7 +9,7 @@ Custom converters allow you to easily work with options whose values are non-sta ## Converter Types There are three converter types: value converter, multiple value converter and enum value converter. They are used in value options, multiple value options and enum value options. However, in the vast majority of situations it is sufficient to use only the value converter. -Furthermore, you can create your own converters. To do this you need to inherit your class from the `IValueConverter` interface. You can also use an existing option class as a base class. See examples of this kind of inheritance, for example, by looking at the implementation of the `MultipleValueConverter` and `EnumValueConverter` classes. +Furthermore, you can create your own converters. To do this you need to inherit your class from the `IValueConverter` interface and implement it. You can also use an existing option class as a base class. See examples of this kind of inheritance, for example, by looking at the implementation of the `MultipleValueConverter` and `EnumValueConverter` classes. Next, you can use this class in the same way as the standard ones. ### Value Converter To create a value converter for type T, you need a function that takes a string and returns T. Pass this function to the constructor of the appropriate class as shown in the example below. diff --git a/Docs/OptionalArguments.md b/Docs/OptionalArguments.md index d532406..2e7f135 100644 --- a/Docs/OptionalArguments.md +++ b/Docs/OptionalArguments.md @@ -189,7 +189,7 @@ parser.Parse(new string[] { "--split-option", "TrimEntries" }); ``` ## Custom Options -You can create your own options. To do this you need to inherit your class from the `ICommonOption` interface. You can also use an existing option class as a base class. See examples of this kind of inheritance, for example, by looking at the implementation of the `FlagOption` and `EnumValueOption` classes. +You can create your own options. To do this you need to inherit your class from the `ICommonOption` interface and implement it. You can also use an existing option class as a base class. See examples of this kind of inheritance, for example, by looking at the implementation of the `FlagOption` and `EnumValueOption` classes. Next, you can use this class in the same way as the standard ones. ## Option Groups Options can be divided into groups. This division may be useful when there are a lot of options. diff --git a/Docs/PrintingHelp.md b/Docs/PrintingHelp.md index 7a0ff0d..a4a2db5 100644 --- a/Docs/PrintingHelp.md +++ b/Docs/PrintingHelp.md @@ -7,11 +7,17 @@ Argument parser uses description generator to geterate command-line help. If you * [Change Headers](#change-headers) * [Change usage header](#change-usage-header) * [Change default option group header](#change-default-option-group-header) + * [Change subcommands header](#change-subcommands-header) * [Change Delimiters](#change-delimiters) + * [Change option example delimiters](#change-option-example-delimiters) + * [Change subcommand name delimiters](#change-subcommand-name-delimiters) * [Configure Printing Space](#configure-printing-space) * [Configure window width](#configure-window-width) * [Configure maximum space for option example](#configure-maximum-space-for-option-example) -* [Custom Description Generator](#custom-description-generator) +* [Change Output Stream](#change-output-stream) +* [Custom Description Generators](#custom-description-generators) + * [Custom Application Description Generator](#custom-application-description-generator) + * [Custom Subcommand Description Generator](#custom-subcommand-description-generator) ## Add Program Information You can specify name, version, description and epilog of your program. To do this, you need to set values in the corresponding properties, as shown in the example below. @@ -43,17 +49,20 @@ Text at the bottom **NetArgumentParser** allows you to customize the generating of command-line help. You can configure an existing generator or [create](#custom-description-generator) your own. ### Change Headers -You can change a header of the `usage` section and a default option group header. +You can change header of the `usage` section, header of the `subcommands` section and a default option group header. #### Change usage header To change a header of the `usage` section you need to create description generator and specify corresponding property in it. You can do this the same way as in the following example. ```cs var parser = new ArgumentParser(); -var generator = new DescriptionGenerator(parser) + +var generator = new ApplicationDescriptionGenerator(parser) { UsageHeader = "My Usage: " }; + +parser.DescriptionGenerator = generator; ``` The output will be like the following: @@ -82,16 +91,50 @@ Default group: ... ``` +#### Change subcommands header +To change a header of the `subcommands` section you need to create description generator and specify corresponding property in it. You can do this the same way as in the following example. + +```cs +var parser = new ArgumentParser(); + +var generator = new ApplicationDescriptionGenerator(parser) +{ + SubcommandsHeader = "My Subcommands:" +}; + +parser.DescriptionGenerator = generator; +``` + +The output will be like the following: + +``` +Usage: ... + +Options: + ... + +My Subcommands: ... + ... +``` + ### Change Delimiters -You can change a delimiters before and after option example. You can do this the same way as in the following example. +You can change the following delimiters: +- Before and after option example. +- Before and after subcommand name. + +#### Change option example delimiters +You can change delimiters before and after option example. You can do this the same way as in the following example. ```cs var parser = new ArgumentParser(); -var generator = new DescriptionGenerator(parser) + +var generator = new ApplicationDescriptionGenerator(parser) { OptionExamplePrefix = "@@", DelimiterAfterOptionExample = " -> " }; + +parser.DescriptionGenerator = generator; ``` The output will be like the following: @@ -104,6 +147,33 @@ Options: @@--version -> show version information ``` +#### Change subcommand name delimiters +You can change delimiters before and after subcommand name. You can do this the same way as in the following example. + +```cs +var parser = new ArgumentParser(); + +var generator = new ApplicationDescriptionGenerator(parser) +{ + SubcommandNamePrefix = "@@", + DelimiterAfterSubcommandName = " -> " +}; + +parser.DescriptionGenerator = generator; +``` + +The output will be like the following: + +``` +Usage: ... + +Options: + ... + +Subcommands: +@@resize -> resize the image +``` + ### Configure Printing Space You can specify window width and maximum space for option example. @@ -112,10 +182,13 @@ The width of the window is set in order to correctly wrap the components of the ```cs var parser = new ArgumentParser(); -var generator = new DescriptionGenerator(parser) + +var generator = new ApplicationDescriptionGenerator(parser) { WindowWidth = Console.WindowWidth }; + +parser.DescriptionGenerator = generator; ``` #### Configure maximum space for option example @@ -123,11 +196,42 @@ You can specify a character limit for the option examples. This is useful for sm ```cs var parser = new ArgumentParser(); -var generator = new DescriptionGenerator(parser) + +var generator = new ApplicationDescriptionGenerator(parser) { OptionExampleCharsLimit = 25 }; + +parser.DescriptionGenerator = generator; ``` -## Custom Description Generator -You can create your own description generator. To do this you need to inherit your class from the `IDescriptionGenerator` interface. You can also use an existing description generator class as a base class. See example of this kind of inheritance, for example, by looking at the implementation of the `DescriptionGenerator` class. +## Change Output Stream +You can change output stream in which all information and messages are written. To do this you need to create a custom class inherited from the `ITextWriter` interface and pass it to the `ChangeOutputWriter()` method. You can also use an existing text writer class as a base class. See example of this kind of inheritance, for example, by looking at the implementation of the `ConsoleTextWriter` class. + +```cs +var parser = new ArgumentParser(); +parser.ChangeOutputWriter(new ConsoleTextWriter()); +``` + +## Custom Description Generators +You can create your own application description generator and subcommand description generator. This can be useful if you want to implement your own command-line help generation system. + +### Custom Application Description Generator +You can create your own application description generator. To do this you need to inherit your class from the `IDescriptionGenerator` interface and implement it. You can also use an existing `ParserQuantumDescriptionGenerator` class as a base class. See example of this kind of inheritance, for example, by looking at the implementation of the `ApplicationDescriptionGenerator` class. Next, you can use this class in the same way as the standard ones. + +```cs +var parser = new ArgumentParser(); +var generator = new ApplicationDescriptionGenerator(parser); + +parser.DescriptionGenerator = generator; +``` + +### Custom Subcommand Description Generator +You can create your own subcommand description generator. To do this you need to inherit your class from the `IDescriptionGenerator` interface and implement it. You can also use an existing `ParserQuantumDescriptionGenerator` class as a base class. See example of this kind of inheritance, for example, by looking at the implementation of the `SubcommandDescriptionGenerator` class. Next, you can use this class in the same way as the standard ones. + +```cs +var parser = new ArgumentParser() +{ + SubcommandDescriptionGeneratorCreator = t => new SubcommandDescriptionGenerator(t) +}; +``` diff --git a/Docs/Subcommands.md b/Docs/Subcommands.md new file mode 100644 index 0000000..0cdcda0 --- /dev/null +++ b/Docs/Subcommands.md @@ -0,0 +1,68 @@ +# Subcommands +Many programs split up their functionality into a number of subcommands. For example, `dotnet` can invoke subcommands like `dotnet new`, `dotnet add`, and `dotnet build`. Splitting up functionality this way can be an extremely good idea when a program performs several different functions which require different kinds of command-line arguments. + +outputweiret +descriptiongeneratorcreator + +## Table of Contents +* [Basics](#basics) + * [Create Subcommand](#create-subcommand) + * [Configure Subcommand](#configure-subcommand) + * [Default Help Option](#default-help-option) +* [Nested Subcommands](#nested-subcommands) + +## Basics +You can create and configure any number of subcommands and nested subcommands. Please note that subcommand names must be unique within each subcommand. Furthermore, subcommands have its own option namespace, which allows you to have options with the same name in different subcommands. + +### Create Subcommand +`ArgumentParser` supports the creation of subcommands with the `AddSubcommand()` method. + +```cs +var parser = new ArgumentParser(); +Subcommand subcommand = parser.AddSubcommand("name", "description"); +``` + +### Configure Subcommand +Subcommands have the same properties and methods for working with options and converters as the parser. For example, you can add options to the subcommand using `AddOptions()` method, add converters using `AddConverters()` method and add option group using `AddOptionGroup()` method. + +```cs +bool verbose = false; +bool debug = false; + +var parser = new ArgumentParser(); +Subcommand subcommand = parser.AddSubcommand("name", "description"); + +subcommand.AddOptions(new FlagOption("verbose", afterHandlingAction: () => verbose = true)); +subcommand.AddConverters(new ValueConverter(Convert.ToInt32)); + +OptionGroup subcommandGroup = subcommand.AddOptionGroup("group"); +subcommandGroup.AddOptions(new FlagOption("debug", afterHandlingAction: () => debug = true)); +``` + +### Default Help Option +By default, subcommands are supplied with standard help option. However, you can specify that help option isn't needed. To do this, you can set the appropriate value for property `UseDefaultHelpOption` or add your own help option. + +```cs +var parser = new ArgumentParser(); + +Subcommand subcommand = parser.AddSubcommand("name", "description"); +resizeSubcommand.UseDefaultHelpOption = false; +``` + +```cs +var parser = new ArgumentParser(); + +Subcommand subcommand = parser.AddSubcommand("name", "description"); +subcommand.AddOptions(new HelpOption()); +``` + +## Nested Subcommands +You can create nested subcommands. It means that each subcommand can have its own subcommands. For example, `dotnet` program has `dotnet add` subcommand, which has a `dotnet add reference` subcommand. + +```cs +var parser = new ArgumentParser(); + +Subcommand subcommand = parser.AddSubcommand("name1", "description1"); +Subcommand subsubcommand = subcommand.AddSubcommand("name2", "description2"); +Subcommand subsubsubcommand = subsubcommand.AddSubcommand("name3", "description3"); +``` diff --git a/README.md b/README.md index d0972b3..e6e5268 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@

## About -**NetArgumentParser** is a cross-platform, free and open source library for parsing command-line options and arguments. +**NetArgumentParser** is a cross-platform, free and open source library for parsing command-line options, arguments and sub-commands. [![Contributors](https://img.shields.io/github/contributors/yakovypg/NetArgumentParser)](https://github.com/yakovypg/NetArgumentParser/graphs/contributors) [![Build Status](https://img.shields.io/github/actions/workflow/status/yakovypg/NetArgumentParser/dotnet.yml?branch=main)](https://github.com/yakovypg/NetArgumentParser/actions/workflows/dotnet.yml?query=branch%3Amain) @@ -31,26 +31,29 @@ ## Main Features This library supports the following main features: -- Parse options starting with a minus (such as `-v`). -- Parse options starting with a double minus (such as `--version`). -- Parse options starting with a slash (such as `/v` or `/version`). +- Parse short-named options (such as `-v`). +- Parse long-named options (such as `--version` or `-version`). +- Parse windows-based options (such as `/v` or `/version`). - Parse compound options (such as `-lah`). -- Parse long name options starting with a minus (such as `-version`). +- Parse nested subcommands (such as `app subcommand subsubcommand`). - Extract extra arguments. -- Support custom converters. -- Configure command-line help generation. +- Provide a lot of default option types. +- Support custom options and converters. +- Configure command-line help generation and output stream. + +Many other features you can find in [documentation](#documentation). ## Quick Start -To start working with the library you need to build it and then connect it to your project. +To start working with the library you need to [connect](#connect-project) it to your project. If you are going to connect a library cloned from a repository, you may want to [build](#build-project) and [test](#test-project) it before doing so. ### Build Project -You can [build](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-build) the library with the following command, which should be run from the root of the library. +You can [build](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-build) the library with the following command, which should be run from the root of the library project. ``` dotnet build ``` ### Test Project -You can [test](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-test) the library with the following command, which should be run from the root of the library. +You can [test](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-test) the library with the following command, which should be run from the root of the library project. ``` dotnet test ``` @@ -60,7 +63,6 @@ You can find instructions for connecting **NetArgumentParser** to your project [ ## Project Status And TODO List **NetArgumentParser** is currently under development. There are some features that need to be added to the project: -- Add support of subcommands. - Add support of reflection-based configuring option set using special attributes. - Add support of import and export JSON configuration. - Add support of parent parsers. @@ -73,6 +75,7 @@ The main topics are: - [Optional arguments](Docs/OptionalArguments.md) - [Optional arguments config](Docs/OptionalArgumentsConfig.md) - [Custom converters](Docs/CustomConverters.md) +- [Subcommands](Docs/Subcommands.md) - [Printing help](Docs/PrintingHelp.md) - [Additional features](Docs/AdditionalFeatures.md) @@ -83,4 +86,4 @@ The project is developed on the .NET 8.0 platform. To continue development you w Contributions are welcome, have a look at the [CONTRIBUTING.md](CONTRIBUTING.md) document for more information. ## License -The project is available under the [GPL-3.0](LICENSE) license. +The project is available under the [GPLv3](LICENSE) license.