Skip to content

Commit 7bf9c0d

Browse files
scott-xunatemcmaster
authored andcommitted
Show allowed values in help text
Similar with enum type, if a string argument/option accepts limited value(s), let's show the allowed values in help text.
1 parent 68a3a7b commit 7bf9c0d

File tree

4 files changed

+49
-11
lines changed

4 files changed

+49
-11
lines changed

src/CommandLineUtils/Attributes/AllowedValuesAttribute.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Collections.ObjectModel;
56
using System.ComponentModel.DataAnnotations;
67

78
namespace McMaster.Extensions.CommandLineUtils
@@ -28,6 +29,8 @@ public AllowedValuesAttribute(params string[] allowedValues)
2829
{
2930
}
3031

32+
internal ReadOnlyCollection<string> AllowedValues => Array.AsReadOnly(this._allowedValues);
33+
3134
/// <summary>
3235
/// Initializes an instance of <see cref="AllowedValuesAttribute"/>.
3336
/// </summary>

src/CommandLineUtils/HelpText/DefaultHelpTextGenerator.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Linq;
88
using System.Reflection;
99
using System.Text;
10+
using McMaster.Extensions.CommandLineUtils.Validation;
1011

1112
namespace McMaster.Extensions.CommandLineUtils.HelpText
1213
{
@@ -196,6 +197,13 @@ protected virtual void GenerateArguments(
196197
? $"{arg.Description}\nAllowed values are: {string.Join(", ", enumNames)}."
197198
: arg.Description;
198199

200+
var attributeValidator = arg.Validators.Cast<AttributeValidator>().FirstOrDefault();
201+
202+
if (attributeValidator != null && attributeValidator.ValidationAttribute is AllowedValuesAttribute allowedValuesAttribute)
203+
{
204+
description += $"\nAllowed values are: {string.Join(", ", allowedValuesAttribute.AllowedValues)}.";
205+
}
206+
199207
var wrappedDescription = IndentWriter?.Write(description);
200208
var message = string.Format(outputFormat, arg.Name, wrappedDescription);
201209

@@ -231,6 +239,13 @@ protected virtual void GenerateOptions(
231239
? $"{opt.Description}\nAllowed values are: {string.Join(", ", enumNames)}."
232240
: opt.Description;
233241

242+
var attributeValidator = opt.Validators.Cast<AttributeValidator>().FirstOrDefault();
243+
244+
if (attributeValidator != null && attributeValidator.ValidationAttribute is AllowedValuesAttribute allowedValuesAttribute)
245+
{
246+
description+= $"\nAllowed values are: {string.Join(", ", allowedValuesAttribute.AllowedValues)}.";
247+
}
248+
234249
var wrappedDescription = IndentWriter?.Write(description);
235250
var message = string.Format(outputFormat, Format(opt), wrappedDescription);
236251

src/CommandLineUtils/Validation/AttributeValidator.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public AttributeValidator(ValidationAttribute attribute)
2424
_attribute = attribute ?? throw new ArgumentNullException(nameof(attribute));
2525
}
2626

27+
internal ValidationAttribute ValidationAttribute => this._attribute;
28+
2729
/// <summary>
2830
/// Gets the validation result for a command line option.
2931
/// </summary>

test/CommandLineUtils.Tests/DefaultHelpTextGeneratorTests.cs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -108,25 +108,31 @@ public void ShowHelp()
108108
var app = new CommandLineApplication();
109109
app.HelpOption();
110110
app.Option("--strOpt <E>", "str option desc.", CommandOptionType.SingleValue);
111+
app.Option("--rStrOpt <E>", "restricted str option desc.", CommandOptionType.SingleValue, o => o.Accepts().Values("Foo", "Bar"));
111112
app.Option<int>("--intOpt <E>", "int option desc.", CommandOptionType.SingleValue);
112113
app.Option<SomeEnum>("--enumOpt <E>", "enum option desc.", CommandOptionType.SingleValue);
113114
app.Argument("SomeStringArgument", "string arg desc.");
115+
app.Argument("RestrictedStringArgument", "restricted string arg desc.", a=>a.Accepts().Values("Foo", "Bar"));
114116
app.Argument<SomeEnum>("SomeEnumArgument", "enum arg desc.");
115117
var helpText = GetHelpText(app);
116118

117-
Assert.Equal(@"Usage: [options] <SomeStringArgument> <SomeEnumArgument>
119+
Assert.Equal(@"Usage: [options] <SomeStringArgument> <RestrictedStringArgument> <SomeEnumArgument>
118120
119121
Arguments:
120-
SomeStringArgument string arg desc.
121-
SomeEnumArgument enum arg desc.
122-
Allowed values are: None, Normal, Extreme.
122+
SomeStringArgument string arg desc.
123+
RestrictedStringArgument restricted string arg desc.
124+
Allowed values are: Foo, Bar.
125+
SomeEnumArgument enum arg desc.
126+
Allowed values are: None, Normal, Extreme.
123127
124128
Options:
125-
-?|-h|--help Show help information.
126-
--strOpt <E> str option desc.
127-
--intOpt <E> int option desc.
128-
--enumOpt <E> enum option desc.
129-
Allowed values are: None, Normal, Extreme.
129+
-?|-h|--help Show help information.
130+
--strOpt <E> str option desc.
131+
--rStrOpt <E> restricted str option desc.
132+
Allowed values are: Foo, Bar.
133+
--intOpt <E> int option desc.
134+
--enumOpt <E> enum option desc.
135+
Allowed values are: None, Normal, Extreme.
130136
131137
",
132138
helpText,
@@ -141,15 +147,19 @@ public void ShowHelpFromAttributes()
141147
app.Conventions.UseDefaultConventions();
142148
var helpText = GetHelpText(app);
143149

144-
Assert.Equal(@"Usage: test [options] <SomeStringArgument> <SomeEnumArgument>
150+
Assert.Equal(@"Usage: test [options] <SomeStringArgument> <RestrictedStringArgument> <SomeEnumArgument>
145151
146152
Arguments:
147153
SomeStringArgument string arg desc.
154+
RestrictedStringArgument restricted string arg desc.
155+
Allowed values are: Foo, Bar.
148156
SomeEnumArgument enum arg desc.
149157
Allowed values are: None, Normal, Extreme.
150158
151159
Options:
152160
-strOpt|--str-opt <STR_OPT> str option desc.
161+
-rStrOpt|--r-str-opt <R_STR_OPT> restricted str option desc.
162+
Allowed values are: Foo, Bar.
153163
-intOpt|--int-opt <INT_OPT> int option desc.
154164
-enumOpt|--verbosity <VERBOSITY> enum option desc.
155165
Allowed values are: None, Normal, Extreme.
@@ -165,6 +175,10 @@ public class MyApp
165175
[Option(ShortName = "strOpt", Description = "str option desc.")]
166176
public string strOpt { get; set; }
167177

178+
[Option(ShortName = "rStrOpt", Description = "restricted str option desc.")]
179+
[AllowedValues("Foo", "Bar")]
180+
public string rStrOpt { get; set; }
181+
168182
[Option(ShortName = "intOpt", Description = "int option desc.")]
169183
public int intOpt { get; set; }
170184

@@ -174,7 +188,11 @@ public class MyApp
174188
[Argument(0, Description = "string arg desc.")]
175189
public string SomeStringArgument { get; set; }
176190

177-
[Argument(1, Description = "enum arg desc.")]
191+
[Argument(1, Description = "restricted string arg desc.")]
192+
[AllowedValues("Foo", "Bar")]
193+
public string RestrictedStringArgument { get; set; }
194+
195+
[Argument(2, Description = "enum arg desc.")]
178196
public SomeEnum SomeEnumArgument { get; set; }
179197
}
180198

0 commit comments

Comments
 (0)