Added the ability to hide CommandOptions. (#642)

CommandOptions now has an IsHidden property that, when set to true, will cause the option to be hidden from the following cases:

- Help text using `-h|--help`
- Xml representations generated with the `cli xml` command
- Diagnostics displayed with the `cli explain` command

Hidden options can still be outputted with `cli explain` using the `--hidden` option that is also used to display hidden commands.

Fixes #631
This commit is contained in:
Tim Waalewijn 2021-11-29 23:16:54 +01:00 committed by GitHub
parent 168f35202d
commit 2e5d18fa78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 138 additions and 7 deletions

View File

@ -53,6 +53,15 @@ There is a special mode for `CommandOptions` on boolean types. Typically all `Co
public bool Debug { get; set; }
```
### Hidden options
`CommandOptions` can be hidden from being rendered in help by setting `IsHidden` to `true`.
```csharp
[CommandOption("--hidden-opt", IsHidden = true)]
public bool HiddenOpt { get; set; }
```
## Description
When rendering help the [`System.ComponentModel.Description`](https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.descriptionattribute?view=net-5.0) attribute is supported for specifying the text displayed to the user for both `CommandOption` and `CommandArgument`.

View File

@ -34,6 +34,11 @@ namespace Spectre.Console.Cli
/// </summary>
public bool ValueIsOptional { get; }
/// <summary>
/// Gets or sets a value indicating whether this option is hidden from the help text.
/// </summary>
public bool IsHidden { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="CommandOptionAttribute"/> class.
/// </summary>

View File

@ -36,7 +36,7 @@ namespace Spectre.Console.Cli
[CommandOption("-d|--detailed")]
public bool? Detailed { get; }
[Description("Include hidden commands.")]
[Description("Include hidden commands and options.")]
[CommandOption("--hidden")]
public bool IncludeHidden { get; }
}
@ -166,7 +166,7 @@ namespace Spectre.Console.Cli
var parametersNode = commandNode.AddNode(ParentMarkup("Parameters"));
foreach (var parameter in command.Parameters)
{
AddParameter(parametersNode, parameter, detailed);
AddParameter(parametersNode, parameter, detailed, includeHidden);
}
}
@ -181,8 +181,13 @@ namespace Spectre.Console.Cli
}
}
private void AddParameter(TreeNode parametersNode, CommandParameter parameter, bool detailed)
private void AddParameter(TreeNode parametersNode, CommandParameter parameter, bool detailed, bool includeHidden)
{
if (!includeHidden && parameter.IsHidden)
{
return;
}
if (!detailed)
{
parametersNode.AddNode(

View File

@ -153,6 +153,7 @@ namespace Spectre.Console.Cli
// Options
foreach (var option in command.Parameters.OfType<CommandOption>()
.Where(x => !x.IsHidden)
.OrderBy(x => string.Join(",", x.LongNames))
.ThenBy(x => string.Join(",", x.ShortNames)))
{

View File

@ -61,7 +61,7 @@ namespace Spectre.Console.Cli
parameters.Add(new HelpOption("v", "version", null, null, "Prints version information"));
}
parameters.AddRange(command?.Parameters?.OfType<CommandOption>()?.Select(o =>
parameters.AddRange(command?.Parameters.OfType<CommandOption>().Where(o => !o.IsHidden).Select(o =>
new HelpOption(
o.ShortNames.FirstOrDefault(), o.LongNames.FirstOrDefault(),
o.ValueName, o.ValueIsOptional, o.Description))

View File

@ -16,7 +16,7 @@ namespace Spectre.Console.Cli
CommandArgumentAttribute argument, ParameterValueProviderAttribute? valueProvider,
IEnumerable<ParameterValidationAttribute> validators)
: base(parameterType, parameterKind, property, description, converter, defaultValue,
null, valueProvider, validators, argument.IsRequired)
null, valueProvider, validators, argument.IsRequired, false)
{
Value = argument.ValueName;
Position = argument.Position;

View File

@ -20,7 +20,7 @@ namespace Spectre.Console.Cli
IEnumerable<ParameterValidationAttribute> validators,
DefaultValueAttribute? defaultValue, bool valueIsOptional)
: base(parameterType, parameterKind, property, description, converter,
defaultValue, deconstructor, valueProvider, validators, false)
defaultValue, deconstructor, valueProvider, validators, false, optionAttribute.IsHidden)
{
LongNames = optionAttribute.LongNames;
ShortNames = optionAttribute.ShortNames;

View File

@ -19,6 +19,7 @@ namespace Spectre.Console.Cli
public List<ParameterValidationAttribute> Validators { get; }
public ParameterValueProviderAttribute? ValueProvider { get; }
public bool Required { get; set; }
public bool IsHidden { get; }
public string PropertyName => Property.Name;
public virtual bool WantRawValue => ParameterType.IsPairDeconstructable()
@ -30,7 +31,7 @@ namespace Spectre.Console.Cli
DefaultValueAttribute? defaultValue,
PairDeconstructorAttribute? deconstructor,
ParameterValueProviderAttribute? valueProvider,
IEnumerable<ParameterValidationAttribute> validators, bool required)
IEnumerable<ParameterValidationAttribute> validators, bool required, bool isHidden)
{
Id = Guid.NewGuid();
ParameterType = parameterType;
@ -43,6 +44,7 @@ namespace Spectre.Console.Cli
ValueProvider = valueProvider;
Validators = new List<ParameterValidationAttribute>(validators ?? Array.Empty<ParameterValidationAttribute>());
Required = required;
IsHidden = isHidden;
}
public bool IsFlagValue()

View File

@ -0,0 +1,12 @@
using Spectre.Console.Cli;
namespace Spectre.Console.Tests.Data
{
public sealed class HiddenOptionsCommand : Command<HiddenOptionSettings>
{
public override int Execute(CommandContext context, HiddenOptionSettings settings)
{
return 0;
}
}
}

View File

@ -0,0 +1,20 @@
using System.ComponentModel;
using Spectre.Console.Cli;
namespace Spectre.Console.Tests.Data
{
public sealed class HiddenOptionSettings : CommandSettings
{
[CommandArgument(0, "<FOO>")]
[Description("Dummy argument FOO")]
public int Foo { get; set; }
[CommandOption("--bar", IsHidden = true)]
[Description("You should not be able to read this unless you used the 'cli explain' command with the '--hidden' option")]
public int Bar { get; set; }
[CommandOption("--baz")]
[Description("Dummy option BAZ")]
public int Baz { get; set; }
}
}

View File

@ -0,0 +1,9 @@
USAGE:
myapp <FOO> [OPTIONS]
ARGUMENTS:
<FOO> Dummy argument FOO
OPTIONS:
-h, --help Prints help information
--baz Dummy option BAZ

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Model>
<!--DEFAULT COMMAND-->
<Command Name="__default_command" IsBranch="false" IsDefault="true" ClrType="Spectre.Console.Tests.Data.HiddenOptionsCommand" Settings="Spectre.Console.Tests.Data.HiddenOptionSettings">
<Parameters>
<Argument Name="FOO" Position="0" Required="true" Kind="scalar" ClrType="System.Int32">
<Description>Dummy argument FOO</Description>
</Argument>
<Option Short="" Long="baz" Value="NULL" Required="false" Kind="scalar" ClrType="System.Int32">
<Description>Dummy option BAZ</Description>
</Option>
</Parameters>
</Command>
</Model>

View File

@ -193,5 +193,25 @@ namespace Spectre.Console.Tests.Unit.Cli.Annotations
result.ShortNames.ShouldContain("f");
result.ValueName.ShouldBe("BAR");
}
[Fact]
public void Is_Not_Hidden_From_Help_By_Default()
{
// Given, When
var result = new CommandOptionAttribute("--foo");
// Then
result.IsHidden.ShouldBeFalse();
}
[Fact]
public void Can_Indicate_That_It_Must_Be_Hidden_From_Help_Text()
{
// Given, When
var result = new CommandOptionAttribute("--foo") { IsHidden = true };
// Then
result.IsHidden.ShouldBeTrue();
}
}
}

View File

@ -278,6 +278,25 @@ namespace Spectre.Console.Tests.Unit.Cli
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Hidden_Command_Options")]
public Task Should_Not_Show_Hidden_Command_Options()
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<GenericCommand<HiddenOptionSettings>>();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
});
// When
var result = fixture.Run("--help");
// Then
return Verifier.Verify(result.Output);
}
}
}
}

View File

@ -137,6 +137,21 @@ namespace Spectre.Console.Tests.Unit.Cli
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Hidden_Command_Options")]
public Task Should_Not_Dump_Hidden_Options_On_A_Command()
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<HiddenOptionsCommand>();
// When
var result = fixture.Run(Constants.XmlDocCommand);
// Then
return Verifier.Verify(result.Output);
}
}
}
}