Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions Core/NetArgumentParser/Attributes/EnumValueOptionAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public EnumValueOptionAttribute(
T[]? choices = null,
string[]? beforeParseChoices = null,
bool addChoicesToDescription = false,
bool addBeforeParseChoicesToDescription = false)
bool addBeforeParseChoicesToDescription = false,
bool addDefaultValueToDescription = false)
: base(
defaultValue,
longName ?? throw new ArgumentNullException(nameof(longName)),
Expand All @@ -45,7 +46,8 @@ public EnumValueOptionAttribute(
choices,
beforeParseChoices,
addChoicesToDescription,
addBeforeParseChoicesToDescription)
addBeforeParseChoicesToDescription,
addDefaultValueToDescription)
{
UseDefaultChoices = useDefaultChoices;
}
Expand All @@ -65,7 +67,8 @@ public EnumValueOptionAttribute(
T[]? choices = null,
string[]? beforeParseChoices = null,
bool addChoicesToDescription = false,
bool addBeforeParseChoicesToDescription = false)
bool addBeforeParseChoicesToDescription = false,
bool addDefaultValueToDescription = false)
: base(
choices,
longName ?? throw new ArgumentNullException(nameof(longName)),
Expand All @@ -79,7 +82,8 @@ public EnumValueOptionAttribute(
aliases,
beforeParseChoices,
addChoicesToDescription,
addBeforeParseChoicesToDescription)
addBeforeParseChoicesToDescription,
addDefaultValueToDescription)
{
UseDefaultChoices = useDefaultChoices;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ public MultipleValueOptionAttribute(
bool ignoreOrderInChoices = false,
string[]? aliases = null,
ContextCaptureType contextCaptureType = ContextCaptureType.None,
int numberOfItemsToCapture = -1)
int numberOfItemsToCapture = -1,
bool addDefaultValueToDescription = false)
: base(
defaultValue,
longName ?? throw new ArgumentNullException(nameof(longName)),
Expand All @@ -41,7 +42,8 @@ public MultipleValueOptionAttribute(
ignoreCaseInChoices,
aliases,
choices: null,
beforeParseChoices: null)
beforeParseChoices: null,
addDefaultValueToDescription: addDefaultValueToDescription)
{
IgnoreOrderInChoices = ignoreOrderInChoices;
ContextCapture = CreateContextCapture(contextCaptureType, numberOfItemsToCapture);
Expand All @@ -59,7 +61,8 @@ public MultipleValueOptionAttribute(
bool ignoreOrderInChoices = false,
string[]? aliases = null,
ContextCaptureType contextCaptureType = ContextCaptureType.None,
int numberOfItemsToCapture = -1)
int numberOfItemsToCapture = -1,
bool addDefaultValueToDescription = false)
: base(
choices: null,
longName ?? throw new ArgumentNullException(nameof(longName)),
Expand All @@ -71,7 +74,8 @@ public MultipleValueOptionAttribute(
isFinal,
ignoreCaseInChoices,
aliases,
beforeParseChoices: null)
beforeParseChoices: null,
addDefaultValueToDescription: addDefaultValueToDescription)
{
IgnoreOrderInChoices = ignoreOrderInChoices;
ContextCapture = CreateContextCapture(contextCaptureType, numberOfItemsToCapture);
Expand Down
20 changes: 15 additions & 5 deletions Core/NetArgumentParser/Attributes/ValueOptionAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public ValueOptionAttribute(
T[]? choices = null,
string[]? beforeParseChoices = null,
bool addChoicesToDescription = false,
bool addBeforeParseChoicesToDescription = false)
bool addBeforeParseChoicesToDescription = false,
bool addDefaultValueToDescription = false)
: this(
choices,
longName ?? throw new ArgumentNullException(nameof(longName)),
Expand All @@ -44,7 +45,8 @@ public ValueOptionAttribute(
aliases,
beforeParseChoices,
addChoicesToDescription,
addBeforeParseChoicesToDescription)
addBeforeParseChoicesToDescription,
addDefaultValueToDescription)
{
DefaultValue = new DefaultOptionValue<T>(defaultValue);
}
Expand All @@ -62,7 +64,8 @@ public ValueOptionAttribute(
string[]? aliases = null,
string[]? beforeParseChoices = null,
bool addChoicesToDescription = false,
bool addBeforeParseChoicesToDescription = false)
bool addBeforeParseChoicesToDescription = false,
bool addDefaultValueToDescription = false)
: this(
choices: null,
longName ?? throw new ArgumentNullException(nameof(longName)),
Expand All @@ -76,7 +79,8 @@ public ValueOptionAttribute(
aliases,
beforeParseChoices,
addChoicesToDescription,
addBeforeParseChoicesToDescription)
addBeforeParseChoicesToDescription,
addDefaultValueToDescription)
{
}

Expand All @@ -93,7 +97,8 @@ public ValueOptionAttribute(
string[]? aliases = null,
string[]? beforeParseChoices = null,
bool addChoicesToDescription = false,
bool addBeforeParseChoicesToDescription = false)
bool addBeforeParseChoicesToDescription = false,
bool addDefaultValueToDescription = false)
: base(
longName ?? throw new ArgumentNullException(nameof(longName)),
shortName ?? throw new ArgumentNullException(nameof(shortName)),
Expand All @@ -109,6 +114,7 @@ public ValueOptionAttribute(
IgnoreCaseInChoices = ignoreCaseInChoices;
AddChoicesToDescription = addChoicesToDescription;
AddBeforeParseChoicesToDescription = addBeforeParseChoicesToDescription;
AddDefaultValueToDescription = addDefaultValueToDescription;

Choices = choices;
BeforeParseChoices = beforeParseChoices;
Expand All @@ -118,6 +124,7 @@ public ValueOptionAttribute(
public bool IgnoreCaseInChoices { get; }
public bool AddChoicesToDescription { get; }
public bool AddBeforeParseChoicesToDescription { get; }
public bool AddDefaultValueToDescription { get; }

public IEnumerable<T>? Choices { get; }
public IEnumerable<string>? BeforeParseChoices { get; }
Expand Down Expand Up @@ -149,6 +156,9 @@ public override ICommonOption CreateOption(object source, PropertyInfo propertyI
null,
t => propertyInfo.SetValue(source, t));

if (AddDefaultValueToDescription)
valueOption.AddDefaultValueToDescription();

if (AddBeforeParseChoicesToDescription && BeforeParseChoices is not null && BeforeParseChoices.Any())
valueOption.AddBeforeParseChoicesToDescription();
else if (AddChoicesToDescription && Choices is not null && Choices.Any())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.ComponentModel;
using System.Runtime.Serialization;

namespace NetArgumentParser.Options;

[Serializable]
public class DefaultValueAlreadyAddedToDescriptionException : Exception
{
public DefaultValueAlreadyAddedToDescriptionException() { }

public DefaultValueAlreadyAddedToDescriptionException(string? message)
: base(message) { }

public DefaultValueAlreadyAddedToDescriptionException(string? message, Exception? innerException)
: base(message ?? GetDefaultMessage(), innerException) { }

#if NET8_0_OR_GREATER
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId = "SYSLIB0051", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
#endif
protected DefaultValueAlreadyAddedToDescriptionException(SerializationInfo info, StreamingContext context)
: base(info, context) { }

private static string GetDefaultMessage()
{
return "Default value have already been added to description.";
}
}
46 changes: 46 additions & 0 deletions Core/NetArgumentParser/Options/ValueOption.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
Expand All @@ -15,6 +16,7 @@ public class ValueOption<T> : CommonOption, IValueOption<T>
{
private List<T> _choices;
private List<string> _beforeParseChoices;
private bool _areDefaultValueAddedToDescription;
private bool _areChoicesAddedToDescription;

public ValueOption(
Expand Down Expand Up @@ -152,6 +154,50 @@ public bool TrySetConverter(IValueConverter converter)
return false;
}

public void AddDefaultValueToDescription(
string separator = ", ",
string prefix = " [default=",
string postfix = "]",
string arraySeparator = "; ",
string arrayPrefix = "[",
string arrayPostfix = "]",
string nullPresenter = "null")
{
ExtendedArgumentNullException.ThrowIfNull(separator, nameof(separator));
ExtendedArgumentNullException.ThrowIfNull(prefix, nameof(prefix));
ExtendedArgumentNullException.ThrowIfNull(postfix, nameof(postfix));
ExtendedArgumentNullException.ThrowIfNull(arraySeparator, nameof(arraySeparator));
ExtendedArgumentNullException.ThrowIfNull(arrayPrefix, nameof(arrayPrefix));
ExtendedArgumentNullException.ThrowIfNull(arrayPostfix, nameof(arrayPostfix));
ExtendedArgumentNullException.ThrowIfNull(nullPresenter, nameof(nullPresenter));

if (_areDefaultValueAddedToDescription)
throw new DefaultValueAlreadyAddedToDescriptionException();

string defaultValueString;

if (DefaultValue is null)
{
defaultValueString = nullPresenter;
}
else if (DefaultValue.Value is IEnumerable defaultValueEnumerable)
{
defaultValueString = ExtendedString.JoinWithExpand(
separator,
arraySeparator,
arrayPrefix,
arrayPostfix,
defaultValueEnumerable.Cast<object>());
}
else
{
defaultValueString = DefaultValue.Value?.ToString() ?? nullPresenter;
}

Description += $"{prefix}{defaultValueString}{postfix}";
_areDefaultValueAddedToDescription = true;
}

public void AddChoicesToDescription(
string separator = ", ",
string prefix = " (",
Expand Down
45 changes: 45 additions & 0 deletions Documentation/AdditionalFeatures.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* [Parse Known Arguments](#parse-known-arguments)
* [Skip Arguments](#skip-arguments)
* [Getting Info About Handled Options And Subcommands](#getting-info-about-handled-options-and-subcommands)
* [Add Default Value To Description](#add-default-value-to-description)
* [Add Choices To Description](#add-choices-to-description)

## Negative Numbers & Scientific Notation
Expand Down Expand Up @@ -116,6 +117,50 @@ ParseArgumentsResult result = parser.ParseKnownArguments(args, out _);
// result.HandledSubcommands: compressSubcommand
```

## Add Default Value To Description
You can add default value to the value option description automatically. To do this, you can use `AddDefaultValueToDescription()` method as follows:

```cs
var angleOption = new ValueOption<int>(
defaultValue: new DefaultOptionValue<int>(45),
longName: "angle",
description: "Angle");

angleOption.AddDefaultValueToDescription();

var namesOption = new MultipleValueOption<List<string>>(
defaultValue: new DefaultOptionValue<IList<List<string>>>([["Leo", "Max"], ["Eva", "Zoe"]]),
longName: "input",
description: "Names");

namesOption.AddDefaultValueToDescription(
separator: ", ",
prefix: " (default: ",
postfix: ")",
arraySeparator: "; ",
arrayPrefix: "[",
arrayPostfix: "]",
nullPresenter: "null");

var fileModeOption = new ValueOption<FileMode>(
defaultValue: new DefaultOptionValue<FileMode>(FileMode.Open),
longName: "mode",
description: "File mode");

fileModeOption.AddDefaultValueToDescription(
prefix: ". Default ",
postfix: string.Empty);

// Angle [default=45]
Console.WriteLine(angleOption.Description);

// Names (default: [John, Max]; [John1, Max1])
Console.WriteLine(namesOption.Description);

// File mode. Default Open
Console.WriteLine(fileModeOption.Description);
```

## Add Choices To Description
You can add choices to the value option description automatically. To do this, you can use `AddChoicesToDescription()` method as follows:

Expand Down
8 changes: 5 additions & 3 deletions Documentation/ParserGenerationUsingAttributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ internal class CustomParserConfig
choices: [FileMode.Create, FileMode.Open],
beforeParseChoices: ["Create", "Open"],
addChoicesToDescription: false,
addBeforeParseChoicesToDescription: true)
addBeforeParseChoicesToDescription: true,
addDefaultValueToDescription: false)
]
public FileMode Mode { get; set; }

Expand Down Expand Up @@ -143,15 +144,16 @@ internal class CustomParserConfig
choices: [0, 45, 90],
beforeParseChoices: ["0", "45", "90"],
addChoicesToDescription: true,
addBeforeParseChoicesToDescription: false)
addBeforeParseChoicesToDescription: false,
addDefaultValueToDescription: true)
]
public double? Angle { get; set; }
}

internal record Point(double X, double Y, double Z);
```

Note that attributes allow you to add choices and before parse choices to the option description (if the corresponding option supports it) using `addChoicesToDescription` and `addBeforeParseChoicesToDescription` parameters, so you don't need to find the generated options to do this.
Note that attributes allow you to add default value, choices and before parse choices to the option description (if the corresponding option supports it) using `addDefaultValueToDescription`, `addChoicesToDescription`, and `addBeforeParseChoicesToDescription` parameters, so you don't need to find the generated options to do this.

### Group Attributes
Goups can be configured using `OptionGroupAttribute` attribute. In addition to specifying the group header and description, you should specify the group ID. It is necessary for the correct placement of options, since groups can have the same header. Options that you want to put in the same group must be marked with an attribute with the same ID. You should't specify header and description for all group attributes with same id. It is enough to do this for only one attribute.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ public CustomParserConfig()
choices: [FileMode.Create, FileMode.Open],
beforeParseChoices: ["Create", "Open"],
addChoicesToDescription: false,
addBeforeParseChoicesToDescription: true)
addBeforeParseChoicesToDescription: true,
addDefaultValueToDescription: false)
]
[OptionGroup("complex-values", "", "")]
public FileMode Mode { get; set; }
Expand Down Expand Up @@ -178,7 +179,8 @@ public CustomParserConfig()
choices: [0, 45, 90],
beforeParseChoices: ["0", "45", "90"],
addChoicesToDescription: true,
addBeforeParseChoicesToDescription: false)
addBeforeParseChoicesToDescription: false,
addDefaultValueToDescription: true)
]
[OptionGroup("values", "", "")]
public double? Angle { get; set; }
Expand Down