mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 08:52:50 +08:00
Make HelpProvider colors configurable (#1408)
This commit is contained in:
parent
d5b4621233
commit
9cc888e5ad
@ -15,6 +15,34 @@ The help is also context aware and tailored depending on what has been specified
|
|||||||
|
|
||||||
`HelpProvider` is the `Spectre.Console` class responsible for determining context and preparing the help text to write to the console. It is an implementation of the public interface `IHelpProvider`.
|
`HelpProvider` is the `Spectre.Console` class responsible for determining context and preparing the help text to write to the console. It is an implementation of the public interface `IHelpProvider`.
|
||||||
|
|
||||||
|
## Styling the help text
|
||||||
|
|
||||||
|
Basic styling is applied to the generated help text by default, however this is configurable.
|
||||||
|
|
||||||
|
`HelpProviderStyle` is the `Spectre.Console` class that holds the style information for the help text.
|
||||||
|
|
||||||
|
The default theme shipped with Spectre.Console is provided by a factory method, `HelpProviderStyle.Default`.
|
||||||
|
|
||||||
|
However, you can explicitly set a custom theme when configuring a CommandApp, for example:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
config.Settings.HelpProviderStyles = new HelpProviderStyle()
|
||||||
|
{
|
||||||
|
Description = new DescriptionStyle()
|
||||||
|
{
|
||||||
|
Header = "bold",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Removing all styling from help text is also possible, a good choice for ensuring maximum accessibility. This is configured by clearing the style provider entirely:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
config.Settings.HelpProviderStyles = null;
|
||||||
|
```
|
||||||
|
|
||||||
|
See [Markup](../markup) for information about the use of markup in Spectre.Console, and [Styles](xref:styles) for a listing of supported styles.
|
||||||
|
|
||||||
## Custom help providers
|
## Custom help providers
|
||||||
|
|
||||||
Whilst it shouldn't be common place to implement your own help provider, it is however possible.
|
Whilst it shouldn't be common place to implement your own help provider, it is however possible.
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Spectre.Console.Cli;
|
using Spectre.Console.Cli;
|
||||||
|
using Spectre.Console.Cli.Help;
|
||||||
|
|
||||||
namespace Help;
|
namespace Help;
|
||||||
|
|
||||||
@ -12,6 +13,9 @@ public static class Program
|
|||||||
{
|
{
|
||||||
// Register the custom help provider
|
// Register the custom help provider
|
||||||
config.SetHelpProvider(new CustomHelpProvider(config.Settings));
|
config.SetHelpProvider(new CustomHelpProvider(config.Settings));
|
||||||
|
|
||||||
|
// Render an unstyled help text for maximum accessibility
|
||||||
|
config.Settings.HelpProviderStyles = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
return app.Run(args);
|
return app.Run(args);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
using Spectre.Console.Cli.Resources;
|
|
||||||
|
|
||||||
namespace Spectre.Console.Cli.Help;
|
namespace Spectre.Console.Cli.Help;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -10,7 +8,8 @@ namespace Spectre.Console.Cli.Help;
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class HelpProvider : IHelpProvider
|
public class HelpProvider : IHelpProvider
|
||||||
{
|
{
|
||||||
private HelpProviderResources resources;
|
private readonly HelpProviderResources resources;
|
||||||
|
private readonly HelpProviderStyle? helpStyles;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating how many examples from direct children to show in the help text.
|
/// Gets a value indicating how many examples from direct children to show in the help text.
|
||||||
@ -27,6 +26,14 @@ public class HelpProvider : IHelpProvider
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual bool TrimTrailingPeriod { get; }
|
protected virtual bool TrimTrailingPeriod { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether to emit the markup styles, inline, when rendering the help text.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Useful for unit testing different styling of the same help text.
|
||||||
|
/// </remarks>
|
||||||
|
protected virtual bool RenderMarkupInline { get; } = false;
|
||||||
|
|
||||||
private sealed class HelpArgument
|
private sealed class HelpArgument
|
||||||
{
|
{
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
@ -94,6 +101,11 @@ public class HelpProvider : IHelpProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal Composer NewComposer()
|
||||||
|
{
|
||||||
|
return new Composer(RenderMarkupInline);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="HelpProvider"/> class.
|
/// Initializes a new instance of the <see cref="HelpProvider"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -104,6 +116,10 @@ public class HelpProvider : IHelpProvider
|
|||||||
this.MaximumIndirectExamples = settings.MaximumIndirectExamples;
|
this.MaximumIndirectExamples = settings.MaximumIndirectExamples;
|
||||||
this.TrimTrailingPeriod = settings.TrimTrailingPeriod;
|
this.TrimTrailingPeriod = settings.TrimTrailingPeriod;
|
||||||
|
|
||||||
|
// Don't provide a default style if HelpProviderStyles is null,
|
||||||
|
// as the user will have explicitly done this to output unstyled help text
|
||||||
|
this.helpStyles = settings.HelpProviderStyles;
|
||||||
|
|
||||||
resources = new HelpProviderResources(settings.Culture);
|
resources = new HelpProviderResources(settings.Culture);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,8 +164,8 @@ public class HelpProvider : IHelpProvider
|
|||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var composer = new Composer();
|
var composer = NewComposer();
|
||||||
composer.Style("yellow", $"{resources.Description}:").LineBreak();
|
composer.Style(helpStyles?.Description?.Header ?? Style.Plain, $"{resources.Description}:").LineBreak();
|
||||||
composer.Text(command.Description).LineBreak();
|
composer.Text(command.Description).LineBreak();
|
||||||
yield return composer.LineBreak();
|
yield return composer.LineBreak();
|
||||||
}
|
}
|
||||||
@ -162,16 +178,16 @@ public class HelpProvider : IHelpProvider
|
|||||||
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
||||||
public virtual IEnumerable<IRenderable> GetUsage(ICommandModel model, ICommandInfo? command)
|
public virtual IEnumerable<IRenderable> GetUsage(ICommandModel model, ICommandInfo? command)
|
||||||
{
|
{
|
||||||
var composer = new Composer();
|
var composer = NewComposer();
|
||||||
composer.Style("yellow", $"{resources.Usage}:").LineBreak();
|
composer.Style(helpStyles?.Usage?.Header ?? Style.Plain, $"{resources.Usage}:").LineBreak();
|
||||||
composer.Tab().Text(model.ApplicationName);
|
composer.Tab().Text(model.ApplicationName);
|
||||||
|
|
||||||
var parameters = new List<string>();
|
var parameters = new List<Composer>();
|
||||||
|
|
||||||
if (command == null)
|
if (command == null)
|
||||||
{
|
{
|
||||||
parameters.Add($"[grey][[{resources.Options}]][/]");
|
parameters.Add(NewComposer().Style(helpStyles?.Usage?.Options ?? Style.Plain, $"[{resources.Options}]"));
|
||||||
parameters.Add($"[aqua]<{resources.Command}>[/]");
|
parameters.Add(NewComposer().Style(helpStyles?.Usage?.Command ?? Style.Plain, $"<{resources.Command}>"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -183,11 +199,11 @@ public class HelpProvider : IHelpProvider
|
|||||||
{
|
{
|
||||||
if (isCurrent)
|
if (isCurrent)
|
||||||
{
|
{
|
||||||
parameters.Add($"[underline]{current.Name.EscapeMarkup()}[/]");
|
parameters.Add(NewComposer().Style(helpStyles?.Usage?.CurrentCommand ?? Style.Plain, $"{current.Name}"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
parameters.Add($"{current.Name.EscapeMarkup()}");
|
parameters.Add(NewComposer().Text(current.Name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +214,7 @@ public class HelpProvider : IHelpProvider
|
|||||||
foreach (var argument in current.Parameters.OfType<ICommandArgument>()
|
foreach (var argument in current.Parameters.OfType<ICommandArgument>()
|
||||||
.Where(a => a.Required).OrderBy(a => a.Position).ToArray())
|
.Where(a => a.Required).OrderBy(a => a.Position).ToArray())
|
||||||
{
|
{
|
||||||
parameters.Add($"[aqua]<{argument.Value.EscapeMarkup()}>[/]");
|
parameters.Add(NewComposer().Style(helpStyles?.Usage?.RequiredArgument ?? Style.Plain, $"<{argument.Value}>"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,27 +223,27 @@ public class HelpProvider : IHelpProvider
|
|||||||
{
|
{
|
||||||
foreach (var optionalArgument in optionalArguments)
|
foreach (var optionalArgument in optionalArguments)
|
||||||
{
|
{
|
||||||
parameters.Add($"[silver][[{optionalArgument.Value.EscapeMarkup()}]][/]");
|
parameters.Add(NewComposer().Style(helpStyles?.Usage?.OptionalArgument ?? Style.Plain, $"[{optionalArgument.Value}]"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCurrent)
|
if (isCurrent)
|
||||||
{
|
{
|
||||||
parameters.Add($"[grey][[{resources.Options}]][/]");
|
parameters.Add(NewComposer().Style(helpStyles?.Usage?.Options ?? Style.Plain, $"[{resources.Options}]"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.IsBranch && command.DefaultCommand == null)
|
if (command.IsBranch && command.DefaultCommand == null)
|
||||||
{
|
{
|
||||||
// The user must specify the command
|
// The user must specify the command
|
||||||
parameters.Add($"[aqua]<{resources.Command}>[/]");
|
parameters.Add(NewComposer().Style(helpStyles?.Usage?.Command ?? Style.Plain, $"<{resources.Command}>"));
|
||||||
}
|
}
|
||||||
else if (command.IsBranch && command.DefaultCommand != null && command.Commands.Count > 0)
|
else if (command.IsBranch && command.DefaultCommand != null && command.Commands.Count > 0)
|
||||||
{
|
{
|
||||||
// We are on a branch with a default command
|
// We are on a branch with a default command
|
||||||
// The user can optionally specify the command
|
// The user can optionally specify the command
|
||||||
parameters.Add($"[aqua][[{resources.Command}]][/]");
|
parameters.Add(NewComposer().Style(helpStyles?.Usage?.Command ?? Style.Plain, $"[{resources.Command}]"));
|
||||||
}
|
}
|
||||||
else if (command.IsDefaultCommand)
|
else if (command.IsDefaultCommand)
|
||||||
{
|
{
|
||||||
@ -237,7 +253,7 @@ public class HelpProvider : IHelpProvider
|
|||||||
{
|
{
|
||||||
// Commands other than the default are present
|
// Commands other than the default are present
|
||||||
// So make these optional in the usage statement
|
// So make these optional in the usage statement
|
||||||
parameters.Add($"[aqua][[{resources.Command}]][/]");
|
parameters.Add(NewComposer().Style(helpStyles?.Usage?.Command ?? Style.Plain, $"[{resources.Command}]"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,10 +261,7 @@ public class HelpProvider : IHelpProvider
|
|||||||
composer.Join(" ", parameters);
|
composer.Join(" ", parameters);
|
||||||
composer.LineBreak();
|
composer.LineBreak();
|
||||||
|
|
||||||
return new[]
|
return new[] { composer };
|
||||||
{
|
|
||||||
composer,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -302,14 +315,14 @@ public class HelpProvider : IHelpProvider
|
|||||||
|
|
||||||
if (Math.Min(maxExamples, examples.Count) > 0)
|
if (Math.Min(maxExamples, examples.Count) > 0)
|
||||||
{
|
{
|
||||||
var composer = new Composer();
|
var composer = NewComposer();
|
||||||
composer.LineBreak();
|
composer.LineBreak();
|
||||||
composer.Style("yellow", $"{resources.Examples}:").LineBreak();
|
composer.Style(helpStyles?.Examples?.Header ?? Style.Plain, $"{resources.Examples}:").LineBreak();
|
||||||
|
|
||||||
for (var index = 0; index < Math.Min(maxExamples, examples.Count); index++)
|
for (var index = 0; index < Math.Min(maxExamples, examples.Count); index++)
|
||||||
{
|
{
|
||||||
var args = string.Join(" ", examples[index]);
|
var args = string.Join(" ", examples[index]);
|
||||||
composer.Tab().Text(model.ApplicationName).Space().Style("grey", args);
|
composer.Tab().Text(model.ApplicationName).Space().Style(helpStyles?.Examples?.Arguments ?? Style.Plain, args);
|
||||||
composer.LineBreak();
|
composer.LineBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,11 +347,9 @@ public class HelpProvider : IHelpProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
var result = new List<IRenderable>
|
var result = new List<IRenderable>
|
||||||
{
|
{
|
||||||
new Markup(Environment.NewLine),
|
NewComposer().LineBreak().Style(helpStyles?.Arguments?.Header ?? Style.Plain, $"{resources.Arguments}:").LineBreak(),
|
||||||
new Markup($"[yellow]{resources.Arguments}:[/]"),
|
};
|
||||||
new Markup(Environment.NewLine),
|
|
||||||
};
|
|
||||||
|
|
||||||
var grid = new Grid();
|
var grid = new Grid();
|
||||||
grid.AddColumn(new GridColumn { Padding = new Padding(4, 4), NoWrap = true });
|
grid.AddColumn(new GridColumn { Padding = new Padding(4, 4), NoWrap = true });
|
||||||
@ -347,15 +358,15 @@ public class HelpProvider : IHelpProvider
|
|||||||
foreach (var argument in arguments.Where(x => x.Required).OrderBy(x => x.Position))
|
foreach (var argument in arguments.Where(x => x.Required).OrderBy(x => x.Position))
|
||||||
{
|
{
|
||||||
grid.AddRow(
|
grid.AddRow(
|
||||||
$"[silver]<{argument.Name.EscapeMarkup()}>[/]",
|
NewComposer().Style(helpStyles?.Arguments?.RequiredArgument ?? Style.Plain, $"<{argument.Name}>"),
|
||||||
argument.Description?.TrimEnd('.') ?? " ");
|
NewComposer().Text(argument.Description?.TrimEnd('.') ?? " "));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var argument in arguments.Where(x => !x.Required).OrderBy(x => x.Position))
|
foreach (var argument in arguments.Where(x => !x.Required).OrderBy(x => x.Position))
|
||||||
{
|
{
|
||||||
grid.AddRow(
|
grid.AddRow(
|
||||||
$"[grey][[{argument.Name.EscapeMarkup()}]][/]",
|
NewComposer().Style(helpStyles?.Arguments?.OptionalArgument ?? Style.Plain, $"[{argument.Name}]"),
|
||||||
argument.Description?.TrimEnd('.') ?? " ");
|
NewComposer().Text(argument.Description?.TrimEnd('.') ?? " "));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Add(grid);
|
result.Add(grid);
|
||||||
@ -379,11 +390,9 @@ public class HelpProvider : IHelpProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
var result = new List<IRenderable>
|
var result = new List<IRenderable>
|
||||||
{
|
{
|
||||||
new Markup(Environment.NewLine),
|
NewComposer().LineBreak().Style(helpStyles?.Options?.Header ?? Style.Plain, $"{resources.Options}:").LineBreak(),
|
||||||
new Markup($"[yellow]{resources.Options}:[/]"),
|
};
|
||||||
new Markup(Environment.NewLine),
|
|
||||||
};
|
|
||||||
|
|
||||||
var helpOptions = parameters.ToArray();
|
var helpOptions = parameters.ToArray();
|
||||||
var defaultValueColumn = ShowOptionDefaultValues && helpOptions.Any(e => e.DefaultValue != null);
|
var defaultValueColumn = ShowOptionDefaultValues && helpOptions.Any(e => e.DefaultValue != null);
|
||||||
@ -397,71 +406,24 @@ public class HelpProvider : IHelpProvider
|
|||||||
|
|
||||||
grid.AddColumn(new GridColumn { Padding = new Padding(0, 0) });
|
grid.AddColumn(new GridColumn { Padding = new Padding(0, 0) });
|
||||||
|
|
||||||
static string GetOptionParts(HelpOption option)
|
|
||||||
{
|
|
||||||
var builder = new StringBuilder();
|
|
||||||
if (option.Short != null)
|
|
||||||
{
|
|
||||||
builder.Append('-').Append(option.Short.EscapeMarkup());
|
|
||||||
if (option.Long != null)
|
|
||||||
{
|
|
||||||
builder.Append(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
builder.Append(" ");
|
|
||||||
if (option.Long != null)
|
|
||||||
{
|
|
||||||
builder.Append(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.Long != null)
|
|
||||||
{
|
|
||||||
builder.Append("--").Append(option.Long.EscapeMarkup());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.Value != null)
|
|
||||||
{
|
|
||||||
builder.Append(' ');
|
|
||||||
if (option.ValueIsOptional ?? false)
|
|
||||||
{
|
|
||||||
builder.Append("[grey][[").Append(option.Value.EscapeMarkup()).Append("]][/]");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
builder.Append("[silver]<").Append(option.Value.EscapeMarkup()).Append(">[/]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultValueColumn)
|
if (defaultValueColumn)
|
||||||
{
|
{
|
||||||
grid.AddRow(" ", $"[lime]{resources.Default}[/]", " ");
|
grid.AddRow(
|
||||||
|
NewComposer().Space(),
|
||||||
|
NewComposer().Style(helpStyles?.Options?.DefaultValueHeader ?? Style.Plain, resources.Default),
|
||||||
|
NewComposer().Space());
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var option in helpOptions)
|
foreach (var option in helpOptions)
|
||||||
{
|
{
|
||||||
var columns = new List<string> { GetOptionParts(option) };
|
var columns = new List<IRenderable>() { GetOptionParts(option) };
|
||||||
|
|
||||||
if (defaultValueColumn)
|
if (defaultValueColumn)
|
||||||
{
|
{
|
||||||
static string Bold(object obj) => $"[bold]{obj.ToString().EscapeMarkup()}[/]";
|
columns.Add(GetOptionDefaultValue(option.DefaultValue));
|
||||||
|
|
||||||
var defaultValue = option.DefaultValue switch
|
|
||||||
{
|
|
||||||
null => " ",
|
|
||||||
"" => " ",
|
|
||||||
Array { Length: 0 } => " ",
|
|
||||||
Array array => string.Join(", ", array.Cast<object>().Select(Bold)),
|
|
||||||
_ => Bold(option.DefaultValue),
|
|
||||||
};
|
|
||||||
columns.Add(defaultValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
columns.Add(option.Description?.TrimEnd('.') ?? " ");
|
columns.Add(NewComposer().Text(option.Description?.TrimEnd('.') ?? " "));
|
||||||
|
|
||||||
grid.AddRow(columns.ToArray());
|
grid.AddRow(columns.ToArray());
|
||||||
}
|
}
|
||||||
@ -471,6 +433,60 @@ public class HelpProvider : IHelpProvider
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IRenderable GetOptionParts(HelpOption option)
|
||||||
|
{
|
||||||
|
var composer = NewComposer();
|
||||||
|
|
||||||
|
if (option.Short != null)
|
||||||
|
{
|
||||||
|
composer.Text("-").Text(option.Short);
|
||||||
|
if (option.Long != null)
|
||||||
|
{
|
||||||
|
composer.Text(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
composer.Text(" ");
|
||||||
|
if (option.Long != null)
|
||||||
|
{
|
||||||
|
composer.Text(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option.Long != null)
|
||||||
|
{
|
||||||
|
composer.Text("--").Text(option.Long);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option.Value != null)
|
||||||
|
{
|
||||||
|
composer.Text(" ");
|
||||||
|
if (option.ValueIsOptional ?? false)
|
||||||
|
{
|
||||||
|
composer.Style(helpStyles?.Options?.OptionalOption ?? Style.Plain, $"[{option.Value}]");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
composer.Style(helpStyles?.Options?.RequiredOption ?? Style.Plain, $"<{option.Value}>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IRenderable GetOptionDefaultValue(object? defaultValue)
|
||||||
|
{
|
||||||
|
return defaultValue switch
|
||||||
|
{
|
||||||
|
null => NewComposer().Text(" "),
|
||||||
|
"" => NewComposer().Text(" "),
|
||||||
|
Array { Length: 0 } => NewComposer().Text(" "),
|
||||||
|
Array array => NewComposer().Join(", ", array.Cast<object>().Select(o => NewComposer().Style(helpStyles?.Options?.DefaultValue ?? Style.Plain, o.ToString() ?? string.Empty))),
|
||||||
|
_ => NewComposer().Style(helpStyles?.Options?.DefaultValue ?? Style.Plain, defaultValue?.ToString() ?? string.Empty),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the commands section of the help information.
|
/// Gets the commands section of the help information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -491,11 +507,9 @@ public class HelpProvider : IHelpProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
var result = new List<IRenderable>
|
var result = new List<IRenderable>
|
||||||
{
|
{
|
||||||
new Markup(Environment.NewLine),
|
NewComposer().LineBreak().Style(helpStyles?.Commands?.Header ?? Style.Plain, $"{resources.Commands}:").LineBreak(),
|
||||||
new Markup($"[yellow]{resources.Commands}:[/]"),
|
};
|
||||||
new Markup(Environment.NewLine),
|
|
||||||
};
|
|
||||||
|
|
||||||
var grid = new Grid();
|
var grid = new Grid();
|
||||||
grid.AddColumn(new GridColumn { Padding = new Padding(4, 4), NoWrap = true });
|
grid.AddColumn(new GridColumn { Padding = new Padding(4, 4), NoWrap = true });
|
||||||
@ -503,27 +517,27 @@ public class HelpProvider : IHelpProvider
|
|||||||
|
|
||||||
foreach (var child in commands)
|
foreach (var child in commands)
|
||||||
{
|
{
|
||||||
var arguments = new Composer();
|
var arguments = NewComposer();
|
||||||
arguments.Style("silver", child.Name.EscapeMarkup());
|
arguments.Style(helpStyles?.Commands?.ChildCommand ?? Style.Plain, child.Name);
|
||||||
arguments.Space();
|
arguments.Space();
|
||||||
|
|
||||||
foreach (var argument in HelpArgument.Get(child).Where(a => a.Required))
|
foreach (var argument in HelpArgument.Get(child).Where(a => a.Required))
|
||||||
{
|
{
|
||||||
arguments.Style("silver", $"<{argument.Name.EscapeMarkup()}>");
|
arguments.Style(helpStyles?.Commands?.RequiredArgument ?? Style.Plain, $"<{argument.Name}>");
|
||||||
arguments.Space();
|
arguments.Space();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TrimTrailingPeriod)
|
if (TrimTrailingPeriod)
|
||||||
{
|
{
|
||||||
grid.AddRow(
|
grid.AddRow(
|
||||||
arguments.ToString().TrimEnd(),
|
NewComposer().Text(arguments.ToString().TrimEnd()),
|
||||||
child.Description?.TrimEnd('.') ?? " ");
|
NewComposer().Text(child.Description?.TrimEnd('.') ?? " "));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
grid.AddRow(
|
grid.AddRow(
|
||||||
arguments.ToString().TrimEnd(),
|
NewComposer().Text(arguments.ToString().TrimEnd()),
|
||||||
child.Description ?? " ");
|
NewComposer().Text(child.Description ?? " "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
219
src/Spectre.Console.Cli/Help/HelpProviderStyles.cs
Normal file
219
src/Spectre.Console.Cli/Help/HelpProviderStyles.cs
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
namespace Spectre.Console.Cli.Help;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Styles for the HelpProvider to use when rendering help text.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class HelpProviderStyle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for describing the purpose or details of a command.
|
||||||
|
/// </summary>
|
||||||
|
public DescriptionStyle? Description { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for specifying the usage format of a command.
|
||||||
|
/// </summary>
|
||||||
|
public UsageStyle? Usage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for providing examples of command usage.
|
||||||
|
/// </summary>
|
||||||
|
public ExampleStyle? Examples { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for specifying arguments in a command.
|
||||||
|
/// </summary>
|
||||||
|
public ArgumentStyle? Arguments { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for specifying options or flags in a command.
|
||||||
|
/// </summary>
|
||||||
|
public OptionStyle? Options { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for specifying subcommands or nested commands.
|
||||||
|
/// </summary>
|
||||||
|
public CommandStyle? Commands { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the default HelpProvider styles.
|
||||||
|
/// </summary>
|
||||||
|
public static HelpProviderStyle Default { get; } =
|
||||||
|
new HelpProviderStyle()
|
||||||
|
{
|
||||||
|
Description = new DescriptionStyle()
|
||||||
|
{
|
||||||
|
Header = "yellow",
|
||||||
|
},
|
||||||
|
Usage = new UsageStyle()
|
||||||
|
{
|
||||||
|
Header = "yellow",
|
||||||
|
CurrentCommand = "underline",
|
||||||
|
Command = "aqua",
|
||||||
|
Options = "grey",
|
||||||
|
RequiredArgument = "aqua",
|
||||||
|
OptionalArgument = "silver",
|
||||||
|
},
|
||||||
|
Examples = new ExampleStyle()
|
||||||
|
{
|
||||||
|
Header = "yellow",
|
||||||
|
Arguments = "grey",
|
||||||
|
},
|
||||||
|
Arguments = new ArgumentStyle()
|
||||||
|
{
|
||||||
|
Header = "yellow",
|
||||||
|
RequiredArgument = "silver",
|
||||||
|
OptionalArgument = "silver",
|
||||||
|
},
|
||||||
|
Commands = new CommandStyle()
|
||||||
|
{
|
||||||
|
Header = "yellow",
|
||||||
|
ChildCommand = "silver",
|
||||||
|
RequiredArgument = "silver",
|
||||||
|
},
|
||||||
|
Options = new OptionStyle()
|
||||||
|
{
|
||||||
|
Header = "yellow",
|
||||||
|
DefaultValueHeader = "lime",
|
||||||
|
DefaultValue = "bold",
|
||||||
|
RequiredOption = "silver",
|
||||||
|
OptionalOption = "grey",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines styles for describing the purpose or details of a command.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DescriptionStyle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for the header in the description.
|
||||||
|
/// </summary>
|
||||||
|
public Style? Header { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines styles for specifying the usage format of a command.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class UsageStyle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for the header in the usage.
|
||||||
|
/// </summary>
|
||||||
|
public Style? Header { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for the current command in the usage.
|
||||||
|
/// </summary>
|
||||||
|
public Style? CurrentCommand { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for general commands in the usage.
|
||||||
|
/// </summary>
|
||||||
|
public Style? Command { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for options in the usage.
|
||||||
|
/// </summary>
|
||||||
|
public Style? Options { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for required arguments in the usage.
|
||||||
|
/// </summary>
|
||||||
|
public Style? RequiredArgument { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for optional arguments in the usage.
|
||||||
|
/// </summary>
|
||||||
|
public Style? OptionalArgument { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines styles for providing examples of command usage.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ExampleStyle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for the header in the examples.
|
||||||
|
/// </summary>
|
||||||
|
public Style? Header { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for arguments in the examples.
|
||||||
|
/// </summary>
|
||||||
|
public Style? Arguments { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines styles for specifying arguments in a command.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ArgumentStyle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for the header in the arguments.
|
||||||
|
/// </summary>
|
||||||
|
public Style? Header { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for required arguments.
|
||||||
|
/// </summary>
|
||||||
|
public Style? RequiredArgument { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for optional arguments.
|
||||||
|
/// </summary>
|
||||||
|
public Style? OptionalArgument { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines styles for specifying subcommands or nested commands.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class CommandStyle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for the header in the command section.
|
||||||
|
/// </summary>
|
||||||
|
public Style? Header { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for child commands in the command section.
|
||||||
|
/// </summary>
|
||||||
|
public Style? ChildCommand { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for required arguments in the command section.
|
||||||
|
/// </summary>
|
||||||
|
public Style? RequiredArgument { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines styles for specifying options or flags in a command.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class OptionStyle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for the header in the options.
|
||||||
|
/// </summary>
|
||||||
|
public Style? Header { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for the header of default values in the options.
|
||||||
|
/// </summary>
|
||||||
|
public Style? DefaultValueHeader { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for default values in the options.
|
||||||
|
/// </summary>
|
||||||
|
public Style? DefaultValue { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for required options.
|
||||||
|
/// </summary>
|
||||||
|
public Style? RequiredOption { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the style for optional options.
|
||||||
|
/// </summary>
|
||||||
|
public Style? OptionalOption { get; set; }
|
||||||
|
}
|
@ -41,6 +41,11 @@ public interface ICommandAppSettings
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
bool TrimTrailingPeriod { get; set; }
|
bool TrimTrailingPeriod { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the styles to used when rendering the help text.
|
||||||
|
/// </summary>
|
||||||
|
HelpProviderStyle? HelpProviderStyles { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="IAnsiConsole"/>.
|
/// Gets or sets the <see cref="IAnsiConsole"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -4,22 +4,43 @@ internal sealed class Composer : IRenderable
|
|||||||
{
|
{
|
||||||
private readonly StringBuilder _content;
|
private readonly StringBuilder _content;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to emit the markup styles, inline, when rendering the content.
|
||||||
|
/// </summary>
|
||||||
|
private readonly bool _renderMarkup = false;
|
||||||
|
|
||||||
public Composer()
|
public Composer()
|
||||||
{
|
{
|
||||||
_content = new StringBuilder();
|
_content = new StringBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Composer(bool renderMarkup)
|
||||||
|
: this()
|
||||||
|
{
|
||||||
|
_renderMarkup = renderMarkup;
|
||||||
|
}
|
||||||
|
|
||||||
public Composer Text(string text)
|
public Composer Text(string text)
|
||||||
{
|
{
|
||||||
_content.Append(text);
|
_content.Append(text);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Composer Style(Style style, string text)
|
||||||
|
{
|
||||||
|
_content.Append('[').Append(style.ToMarkup()).Append(']');
|
||||||
|
_content.Append(text.EscapeMarkup());
|
||||||
|
_content.Append("[/]");
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Composer Style(string style, string text)
|
public Composer Style(string style, string text)
|
||||||
{
|
{
|
||||||
_content.Append('[').Append(style).Append(']');
|
_content.Append('[').Append(style).Append(']');
|
||||||
_content.Append(text.EscapeMarkup());
|
_content.Append(text.EscapeMarkup());
|
||||||
_content.Append("[/]");
|
_content.Append("[/]");
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,6 +49,7 @@ internal sealed class Composer : IRenderable
|
|||||||
_content.Append('[').Append(style).Append(']');
|
_content.Append('[').Append(style).Append(']');
|
||||||
action(this);
|
action(this);
|
||||||
_content.Append("[/]");
|
_content.Append("[/]");
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,12 +94,19 @@ internal sealed class Composer : IRenderable
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Composer Join(string separator, IEnumerable<string> composers)
|
public Composer Join(string separator, IEnumerable<Composer> composers)
|
||||||
{
|
{
|
||||||
if (composers != null)
|
if (composers != null)
|
||||||
{
|
{
|
||||||
Space();
|
foreach (var composer in composers)
|
||||||
Text(string.Join(separator, composers));
|
{
|
||||||
|
if (_content.ToString().Length > 0)
|
||||||
|
{
|
||||||
|
Text(separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(composer.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -85,12 +114,26 @@ internal sealed class Composer : IRenderable
|
|||||||
|
|
||||||
public Measurement Measure(RenderOptions options, int maxWidth)
|
public Measurement Measure(RenderOptions options, int maxWidth)
|
||||||
{
|
{
|
||||||
return ((IRenderable)new Markup(_content.ToString())).Measure(options, maxWidth);
|
if (_renderMarkup)
|
||||||
|
{
|
||||||
|
return ((IRenderable)new Paragraph(_content.ToString())).Measure(options, maxWidth);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ((IRenderable)new Markup(_content.ToString())).Measure(options, maxWidth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Segment> Render(RenderOptions options, int maxWidth)
|
public IEnumerable<Segment> Render(RenderOptions options, int maxWidth)
|
||||||
{
|
{
|
||||||
return ((IRenderable)new Markup(_content.ToString())).Render(options, maxWidth);
|
if (_renderMarkup)
|
||||||
|
{
|
||||||
|
return ((IRenderable)new Paragraph(_content.ToString())).Render(options, maxWidth);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ((IRenderable)new Markup(_content.ToString())).Render(options, maxWidth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
@ -14,9 +14,10 @@ internal sealed class CommandAppSettings : ICommandAppSettings
|
|||||||
public CaseSensitivity CaseSensitivity { get; set; }
|
public CaseSensitivity CaseSensitivity { get; set; }
|
||||||
public bool PropagateExceptions { get; set; }
|
public bool PropagateExceptions { get; set; }
|
||||||
public bool ValidateExamples { get; set; }
|
public bool ValidateExamples { get; set; }
|
||||||
public bool TrimTrailingPeriod { get; set; } = true;
|
public bool TrimTrailingPeriod { get; set; }
|
||||||
|
public HelpProviderStyle? HelpProviderStyles { get; set; }
|
||||||
public bool StrictParsing { get; set; }
|
public bool StrictParsing { get; set; }
|
||||||
public bool ConvertFlagsToRemainingArguments { get; set; } = false;
|
public bool ConvertFlagsToRemainingArguments { get; set; }
|
||||||
|
|
||||||
public ParsingMode ParsingMode =>
|
public ParsingMode ParsingMode =>
|
||||||
StrictParsing ? ParsingMode.Strict : ParsingMode.Relaxed;
|
StrictParsing ? ParsingMode.Strict : ParsingMode.Relaxed;
|
||||||
@ -29,6 +30,9 @@ internal sealed class CommandAppSettings : ICommandAppSettings
|
|||||||
CaseSensitivity = CaseSensitivity.All;
|
CaseSensitivity = CaseSensitivity.All;
|
||||||
ShowOptionDefaultValues = true;
|
ShowOptionDefaultValues = true;
|
||||||
MaximumIndirectExamples = 5;
|
MaximumIndirectExamples = 5;
|
||||||
|
TrimTrailingPeriod = true;
|
||||||
|
HelpProviderStyles = HelpProviderStyle.Default;
|
||||||
|
ConvertFlagsToRemainingArguments = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsTrue(Func<CommandAppSettings, bool> func, string environmentVariableName)
|
public bool IsTrue(Func<CommandAppSettings, bool> func, string environmentVariableName)
|
||||||
|
@ -26,7 +26,7 @@ internal static class MarkupParser
|
|||||||
|
|
||||||
if (token.Kind == MarkupTokenKind.Open)
|
if (token.Kind == MarkupTokenKind.Open)
|
||||||
{
|
{
|
||||||
var parsedStyle = StyleParser.Parse(token.Value);
|
var parsedStyle = string.IsNullOrEmpty(token.Value) ? Style.Plain : StyleParser.Parse(token.Value);
|
||||||
stack.Push(parsedStyle);
|
stack.Push(parsedStyle);
|
||||||
}
|
}
|
||||||
else if (token.Kind == MarkupTokenKind.Close)
|
else if (token.Kind == MarkupTokenKind.Close)
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
namespace Spectre.Console.Cli.Tests.Data.Help;
|
||||||
|
|
||||||
|
internal class RenderMarkupHelpProvider : HelpProvider
|
||||||
|
{
|
||||||
|
protected override bool RenderMarkupInline { get; } = true;
|
||||||
|
|
||||||
|
public RenderMarkupHelpProvider(ICommandAppSettings settings)
|
||||||
|
: base(settings)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -14,4 +14,8 @@ public class LionSettings : CatSettings
|
|||||||
[Description("The days the lion goes hunting.")]
|
[Description("The days the lion goes hunting.")]
|
||||||
[DefaultValue(new[] { DayOfWeek.Monday, DayOfWeek.Thursday })]
|
[DefaultValue(new[] { DayOfWeek.Monday, DayOfWeek.Thursday })]
|
||||||
public DayOfWeek[] HuntDays { get; set; }
|
public DayOfWeek[] HuntDays { get; set; }
|
||||||
|
|
||||||
|
[CommandOption("-w|--weight [WEIGHT]")]
|
||||||
|
[Description("The weight of the lion, in kgs.")]
|
||||||
|
public FlagValue<int?> Weight { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -17,3 +17,4 @@ OPTIONS:
|
|||||||
--agility <VALUE> 10 The agility between 0 and 100
|
--agility <VALUE> 10 The agility between 0 and 100
|
||||||
-c <CHILDREN> The number of children the lion has
|
-c <CHILDREN> The number of children the lion has
|
||||||
-d <DAY> Monday, Thursday The days the lion goes hunting
|
-d <DAY> Monday, Thursday The days the lion goes hunting
|
||||||
|
-w, --weight [WEIGHT] The weight of the lion, in kgs
|
@ -17,3 +17,4 @@ OPTIONS:
|
|||||||
--agility <VALUE> 10 The agility between 0 and 100
|
--agility <VALUE> 10 The agility between 0 and 100
|
||||||
-c <CHILDREN> The number of children the lion has
|
-c <CHILDREN> The number of children the lion has
|
||||||
-d <DAY> Monday, Thursday The days the lion goes hunting
|
-d <DAY> Monday, Thursday The days the lion goes hunting
|
||||||
|
-w, --weight [WEIGHT] The weight of the lion, in kgs
|
@ -20,6 +20,7 @@ OPTIONEN:
|
|||||||
--agility <VALUE> 10 The agility between 0 and 100
|
--agility <VALUE> 10 The agility between 0 and 100
|
||||||
-c <CHILDREN> The number of children the lion has
|
-c <CHILDREN> The number of children the lion has
|
||||||
-d <DAY> Monday, Thursday The days the lion goes hunting
|
-d <DAY> Monday, Thursday The days the lion goes hunting
|
||||||
|
-w, --weight [WEIGHT] The weight of the lion, in kgs
|
||||||
|
|
||||||
KOMMANDOS:
|
KOMMANDOS:
|
||||||
giraffe <LENGTH> The giraffe command
|
giraffe <LENGTH> The giraffe command
|
@ -20,6 +20,7 @@ OPTIONS:
|
|||||||
--agility <VALUE> 10 The agility between 0 and 100
|
--agility <VALUE> 10 The agility between 0 and 100
|
||||||
-c <CHILDREN> The number of children the lion has
|
-c <CHILDREN> The number of children the lion has
|
||||||
-d <DAY> Monday, Thursday The days the lion goes hunting
|
-d <DAY> Monday, Thursday The days the lion goes hunting
|
||||||
|
-w, --weight [WEIGHT] The weight of the lion, in kgs
|
||||||
|
|
||||||
COMMANDS:
|
COMMANDS:
|
||||||
giraffe <LENGTH> The giraffe command
|
giraffe <LENGTH> The giraffe command
|
@ -20,6 +20,7 @@ OPTIONS:
|
|||||||
--agility <VALUE> 10 The agility between 0 and 100
|
--agility <VALUE> 10 The agility between 0 and 100
|
||||||
-c <CHILDREN> The number of children the lion has
|
-c <CHILDREN> The number of children the lion has
|
||||||
-d <DAY> Monday, Thursday The days the lion goes hunting
|
-d <DAY> Monday, Thursday The days the lion goes hunting
|
||||||
|
-w, --weight [WEIGHT] The weight of the lion, in kgs
|
||||||
|
|
||||||
COMMANDES:
|
COMMANDES:
|
||||||
giraffe <LENGTH> The giraffe command
|
giraffe <LENGTH> The giraffe command
|
@ -20,6 +20,7 @@ VAL:
|
|||||||
--agility <VALUE> 10 The agility between 0 and 100
|
--agility <VALUE> 10 The agility between 0 and 100
|
||||||
-c <CHILDREN> The number of children the lion has
|
-c <CHILDREN> The number of children the lion has
|
||||||
-d <DAY> Monday, Thursday The days the lion goes hunting
|
-d <DAY> Monday, Thursday The days the lion goes hunting
|
||||||
|
-w, --weight [WEIGHT] The weight of the lion, in kgs
|
||||||
|
|
||||||
KOMMANDON:
|
KOMMANDON:
|
||||||
giraffe <LENGTH> The giraffe command
|
giraffe <LENGTH> The giraffe command
|
@ -0,0 +1,26 @@
|
|||||||
|
[bold]DESCRIPTION:[/]
|
||||||
|
The lion command.
|
||||||
|
|
||||||
|
[bold]USAGE:[/]
|
||||||
|
myapp []<TEETH>[/] [][[LEGS]][/] [][[OPTIONS]][/] [][[COMMAND]][/]
|
||||||
|
|
||||||
|
[bold]EXAMPLES:[/]
|
||||||
|
myapp []20 --alive[/]
|
||||||
|
|
||||||
|
[bold]ARGUMENTS:[/]
|
||||||
|
[]<TEETH>[/] The number of teeth the lion has
|
||||||
|
[][[LEGS]][/] The number of legs
|
||||||
|
|
||||||
|
[]OPTIONS:[/]
|
||||||
|
[]DEFAULT[/]
|
||||||
|
-h, --help Prints help information
|
||||||
|
-v, --version Prints version information
|
||||||
|
-a, --alive Indicates whether or not the animal is alive
|
||||||
|
-n, --name []<VALUE>[/]
|
||||||
|
--agility []<VALUE>[/] []10[/] The agility between 0 and 100
|
||||||
|
-c []<CHILDREN>[/] The number of children the lion has
|
||||||
|
-d []<DAY>[/] []Monday[/], []Thursday[/] The days the lion goes hunting
|
||||||
|
-w, --weight [][[WEIGHT]][/] The weight of the lion, in kgs
|
||||||
|
|
||||||
|
[bold]COMMANDS:[/]
|
||||||
|
[]giraffe[/] []<LENGTH>[/] The giraffe command
|
@ -0,0 +1,26 @@
|
|||||||
|
[yellow]DESCRIPTION:[/]
|
||||||
|
The lion command.
|
||||||
|
|
||||||
|
[yellow]USAGE:[/]
|
||||||
|
myapp [aqua]<TEETH>[/] [silver][[LEGS]][/] [grey][[OPTIONS]][/] [aqua][[COMMAND]][/]
|
||||||
|
|
||||||
|
[yellow]EXAMPLES:[/]
|
||||||
|
myapp [grey]20 --alive[/]
|
||||||
|
|
||||||
|
[yellow]ARGUMENTS:[/]
|
||||||
|
[silver]<TEETH>[/] The number of teeth the lion has
|
||||||
|
[silver][[LEGS]][/] The number of legs
|
||||||
|
|
||||||
|
[yellow]OPTIONS:[/]
|
||||||
|
[lime]DEFAULT[/]
|
||||||
|
-h, --help Prints help information
|
||||||
|
-v, --version Prints version information
|
||||||
|
-a, --alive Indicates whether or not the animal is alive
|
||||||
|
-n, --name [silver]<VALUE>[/]
|
||||||
|
--agility [silver]<VALUE>[/] [bold]10[/] The agility between 0 and 100
|
||||||
|
-c [silver]<CHILDREN>[/] The number of children the lion has
|
||||||
|
-d [silver]<DAY>[/] [bold]Monday[/], [bold]Thursday[/] The days the lion goes hunting
|
||||||
|
-w, --weight [grey][[WEIGHT]][/] The weight of the lion, in kgs
|
||||||
|
|
||||||
|
[yellow]COMMANDS:[/]
|
||||||
|
[silver]giraffe[/] [silver]<LENGTH>[/] The giraffe command
|
@ -0,0 +1,26 @@
|
|||||||
|
[]DESCRIPTION:[/]
|
||||||
|
The lion command.
|
||||||
|
|
||||||
|
[]USAGE:[/]
|
||||||
|
myapp []<TEETH>[/] [][[LEGS]][/] [][[OPTIONS]][/] [][[COMMAND]][/]
|
||||||
|
|
||||||
|
[]EXAMPLES:[/]
|
||||||
|
myapp []20 --alive[/]
|
||||||
|
|
||||||
|
[]ARGUMENTS:[/]
|
||||||
|
[]<TEETH>[/] The number of teeth the lion has
|
||||||
|
[][[LEGS]][/] The number of legs
|
||||||
|
|
||||||
|
[]OPTIONS:[/]
|
||||||
|
[]DEFAULT[/]
|
||||||
|
-h, --help Prints help information
|
||||||
|
-v, --version Prints version information
|
||||||
|
-a, --alive Indicates whether or not the animal is alive
|
||||||
|
-n, --name []<VALUE>[/]
|
||||||
|
--agility []<VALUE>[/] []10[/] The agility between 0 and 100
|
||||||
|
-c []<CHILDREN>[/] The number of children the lion has
|
||||||
|
-d []<DAY>[/] []Monday[/], []Thursday[/] The days the lion goes hunting
|
||||||
|
-w, --weight [][[WEIGHT]][/] The weight of the lion, in kgs
|
||||||
|
|
||||||
|
[]COMMANDS:[/]
|
||||||
|
[]giraffe[/] []<LENGTH>[/] The giraffe command
|
@ -1,4 +1,4 @@
|
|||||||
DESCRIPTION:
|
DESCRIPTION:
|
||||||
The lion command.
|
The lion command.
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -8,7 +8,8 @@ ARGUMENTS:
|
|||||||
<TEETH> The number of teeth the lion has
|
<TEETH> The number of teeth the lion has
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
DEFAULT
|
DEFAULT
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
-c <CHILDREN> The number of children the lion has
|
-c <CHILDREN> The number of children the lion has
|
||||||
-d <DAY> Monday, Thursday The days the lion goes hunting
|
-d <DAY> Monday, Thursday The days the lion goes hunting
|
||||||
|
-w, --weight [WEIGHT] The weight of the lion, in kgs
|
@ -264,6 +264,101 @@ public sealed partial class CommandAppTests
|
|||||||
return Verifier.Verify(result.Output, settings).UseTextForParameters(expectationPrefix);
|
return Verifier.Verify(result.Output, settings).UseTextForParameters(expectationPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Expectation("Default_Without_Args_Additional_Style_Default")]
|
||||||
|
public Task Should_Output_Default_Command_And_Additional_Commands_When_Default_Command_Has_Required_Parameters_And_Is_Called_Without_Args_Style_Default()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var fixture = new CommandAppTester();
|
||||||
|
fixture.SetDefaultCommand<LionCommand>();
|
||||||
|
fixture.Configure(configurator =>
|
||||||
|
{
|
||||||
|
configurator.SetApplicationName("myapp");
|
||||||
|
configurator.AddExample("20", "--alive");
|
||||||
|
configurator.AddCommand<GiraffeCommand>("giraffe");
|
||||||
|
configurator.SetHelpProvider(new RenderMarkupHelpProvider(configurator.Settings));
|
||||||
|
});
|
||||||
|
|
||||||
|
// When
|
||||||
|
var result = fixture.Run();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
return Verifier.Verify(result.Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Expectation("Default_Without_Args_Additional_Style_BoldHeadings")]
|
||||||
|
public Task Should_Output_Default_Command_And_Additional_Commands_When_Default_Command_Has_Required_Parameters_And_Is_Called_Without_Args_Style_BoldHeadings()
|
||||||
|
{
|
||||||
|
// Bold headings in the help text
|
||||||
|
var styles = new HelpProviderStyle()
|
||||||
|
{
|
||||||
|
Description = new DescriptionStyle()
|
||||||
|
{
|
||||||
|
Header = "bold",
|
||||||
|
},
|
||||||
|
Usage = new UsageStyle()
|
||||||
|
{
|
||||||
|
Header = "bold",
|
||||||
|
},
|
||||||
|
Examples = new ExampleStyle()
|
||||||
|
{
|
||||||
|
Header = "bold",
|
||||||
|
},
|
||||||
|
Arguments = new ArgumentStyle()
|
||||||
|
{
|
||||||
|
Header = "bold",
|
||||||
|
},
|
||||||
|
Commands = new CommandStyle()
|
||||||
|
{
|
||||||
|
Header = "bold",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Omit OptionStyle to ensure coverage of at least one null style class
|
||||||
|
};
|
||||||
|
|
||||||
|
// Given
|
||||||
|
var fixture = new CommandAppTester();
|
||||||
|
fixture.SetDefaultCommand<LionCommand>();
|
||||||
|
fixture.Configure(configurator =>
|
||||||
|
{
|
||||||
|
configurator.SetApplicationName("myapp");
|
||||||
|
configurator.AddExample("20", "--alive");
|
||||||
|
configurator.AddCommand<GiraffeCommand>("giraffe");
|
||||||
|
configurator.Settings.HelpProviderStyles = styles;
|
||||||
|
configurator.SetHelpProvider(new RenderMarkupHelpProvider(configurator.Settings));
|
||||||
|
});
|
||||||
|
|
||||||
|
// When
|
||||||
|
var result = fixture.Run();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
return Verifier.Verify(result.Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Expectation("Default_Without_Args_Additional_Style_None")]
|
||||||
|
public Task Should_Output_Default_Command_And_Additional_Commands_When_Default_Command_Has_Required_Parameters_And_Is_Called_Without_Args_Style_None()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var fixture = new CommandAppTester();
|
||||||
|
fixture.SetDefaultCommand<LionCommand>();
|
||||||
|
fixture.Configure(configurator =>
|
||||||
|
{
|
||||||
|
configurator.SetApplicationName("myapp");
|
||||||
|
configurator.AddExample("20", "--alive");
|
||||||
|
configurator.AddCommand<GiraffeCommand>("giraffe");
|
||||||
|
configurator.Settings.HelpProviderStyles = null;
|
||||||
|
configurator.SetHelpProvider(new RenderMarkupHelpProvider(configurator.Settings));
|
||||||
|
});
|
||||||
|
|
||||||
|
// When
|
||||||
|
var result = fixture.Run();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
return Verifier.Verify(result.Output);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Default_Greeter")]
|
[Expectation("Default_Greeter")]
|
||||||
public Task Should_Not_Output_Default_Command_When_Command_Has_No_Required_Parameters_And_Is_Called_Without_Args()
|
public Task Should_Not_Output_Default_Command_When_Command_Has_No_Required_Parameters_And_Is_Called_Without_Args()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user