mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-15 00:12:50 +08:00
fixed line-endings
This commit is contained in:
parent
989c0b9904
commit
44300c871f
154
docs/Program.cs
154
docs/Program.cs
@ -1,77 +1,77 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Docs.Extensions;
|
using Docs.Extensions;
|
||||||
using Docs.Shortcodes;
|
using Docs.Shortcodes;
|
||||||
using Docs.Utilities;
|
using Docs.Utilities;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Statiq.App;
|
using Statiq.App;
|
||||||
using Statiq.Common;
|
using Statiq.Common;
|
||||||
using Statiq.Core;
|
using Statiq.Core;
|
||||||
using Statiq.Web;
|
using Statiq.Web;
|
||||||
|
|
||||||
namespace Docs
|
namespace Docs
|
||||||
{
|
{
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
public static async Task<int> Main(string[] args) =>
|
public static async Task<int> Main(string[] args) =>
|
||||||
await Bootstrapper.Factory
|
await Bootstrapper.Factory
|
||||||
.CreateWeb(args)
|
.CreateWeb(args)
|
||||||
.AddSetting(Keys.Host, "spectreconsole.net")
|
.AddSetting(Keys.Host, "spectreconsole.net")
|
||||||
.AddSetting(Keys.LinksUseHttps, true)
|
.AddSetting(Keys.LinksUseHttps, true)
|
||||||
.AddSetting(Constants.EditLink, ConfigureEditLink())
|
.AddSetting(Constants.EditLink, ConfigureEditLink())
|
||||||
.AddSetting(Constants.SourceFiles, new List<string>
|
.AddSetting(Constants.SourceFiles, new List<string>
|
||||||
{
|
{
|
||||||
"../../src/Spectre.Console/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
|
"../../src/Spectre.Console/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
|
||||||
"../../src/Spectre.Console.Cli/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
|
"../../src/Spectre.Console.Cli/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
|
||||||
"../../src/Spectre.Console.ImageSharp/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
|
"../../src/Spectre.Console.ImageSharp/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
|
||||||
"../../src/Spectre.Console.Json/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs"
|
"../../src/Spectre.Console.Json/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs"
|
||||||
})
|
})
|
||||||
.AddSetting(Constants.ExampleSourceFiles, new List<string>
|
.AddSetting(Constants.ExampleSourceFiles, new List<string>
|
||||||
{
|
{
|
||||||
"../../examples/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
|
"../../examples/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.ConfigureServices(i =>
|
.ConfigureServices(i =>
|
||||||
{
|
{
|
||||||
i.AddSingleton(new TypeNameLinks());
|
i.AddSingleton(new TypeNameLinks());
|
||||||
})
|
})
|
||||||
.ConfigureSite("spectreconsole", "spectre.console", "main")
|
.ConfigureSite("spectreconsole", "spectre.console", "main")
|
||||||
.AddShortcode("Children", typeof(ChildrenShortcode))
|
.AddShortcode("Children", typeof(ChildrenShortcode))
|
||||||
.AddShortcode("ColorTable", typeof(ColorTableShortcode))
|
.AddShortcode("ColorTable", typeof(ColorTableShortcode))
|
||||||
.AddShortcode("EmojiTable", typeof(EmojiTableShortcode))
|
.AddShortcode("EmojiTable", typeof(EmojiTableShortcode))
|
||||||
.AddShortcode("Alert", typeof(AlertShortcode))
|
.AddShortcode("Alert", typeof(AlertShortcode))
|
||||||
.AddShortcode("Info", typeof(InfoShortcode))
|
.AddShortcode("Info", typeof(InfoShortcode))
|
||||||
.AddShortcode("AsciiCast", typeof(AsciiCastShortcode))
|
.AddShortcode("AsciiCast", typeof(AsciiCastShortcode))
|
||||||
.AddShortcode("Example", typeof(ExampleSnippet))
|
.AddShortcode("Example", typeof(ExampleSnippet))
|
||||||
.AddPipelines()
|
.AddPipelines()
|
||||||
.BuildPipeline(
|
.BuildPipeline(
|
||||||
"Bootstrap",
|
"Bootstrap",
|
||||||
builder => builder
|
builder => builder
|
||||||
.WithInputReadFiles("../node_modules/asciinema-player/dist/bundle/asciinema-player.js")
|
.WithInputReadFiles("../node_modules/asciinema-player/dist/bundle/asciinema-player.js")
|
||||||
.WithProcessModules(new SetDestination(Config.FromDocument(doc => new NormalizedPath($"./assets/{doc.Source.FileName}")), true))
|
.WithProcessModules(new SetDestination(Config.FromDocument(doc => new NormalizedPath($"./assets/{doc.Source.FileName}")), true))
|
||||||
.WithOutputWriteFiles()
|
.WithOutputWriteFiles()
|
||||||
)
|
)
|
||||||
.AddProcess(ProcessTiming.Initialization, _ => new ProcessLauncher("npm", "install --audit false --fund false --progress false")
|
.AddProcess(ProcessTiming.Initialization, _ => new ProcessLauncher("npm", "install --audit false --fund false --progress false")
|
||||||
{
|
{
|
||||||
LogErrors = false
|
LogErrors = false
|
||||||
})
|
})
|
||||||
.AddProcess(ProcessTiming.Initialization, _ => new ProcessLauncher("dotnet", "playwright install chromium"))
|
.AddProcess(ProcessTiming.Initialization, _ => new ProcessLauncher("dotnet", "playwright install chromium"))
|
||||||
.AddProcess(ProcessTiming.BeforeDeployment, _ => new ProcessLauncher("npm", "run build:tailwind")
|
.AddProcess(ProcessTiming.BeforeDeployment, _ => new ProcessLauncher("npm", "run build:tailwind")
|
||||||
{
|
{
|
||||||
LogErrors = false
|
LogErrors = false
|
||||||
})
|
})
|
||||||
.RunAsync();
|
.RunAsync();
|
||||||
|
|
||||||
private static Config<string> ConfigureEditLink()
|
private static Config<string> ConfigureEditLink()
|
||||||
{
|
{
|
||||||
return Config.FromDocument((doc, ctx) =>
|
return Config.FromDocument((doc, ctx) =>
|
||||||
{
|
{
|
||||||
return string.Format("https://github.com/{0}/{1}/edit/{2}/docs/input/{3}",
|
return string.Format("https://github.com/{0}/{1}/edit/{2}/docs/input/{3}",
|
||||||
ctx.GetString(Constants.Site.Owner),
|
ctx.GetString(Constants.Site.Owner),
|
||||||
ctx.GetString(Constants.Site.Repository),
|
ctx.GetString(Constants.Site.Repository),
|
||||||
ctx.GetString(Constants.Site.Branch),
|
ctx.GetString(Constants.Site.Branch),
|
||||||
doc.Source.GetRelativeInputPath());
|
doc.Source.GetRelativeInputPath());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ Description: "*Spectre.Console* makes it easy to write text with different style
|
|||||||
Highlights:
|
Highlights:
|
||||||
- Bold, Italic, Underline, strikethrough
|
- Bold, Italic, Underline, strikethrough
|
||||||
- Dim, Invert
|
- Dim, Invert
|
||||||
- Conceal, slowblink, rapidblink
|
- Conceal, slowblink, rapidblink
|
||||||
- Links
|
- Links
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -46,9 +46,9 @@ Note that what styles that can be used is defined by the system or your terminal
|
|||||||
<tr>
|
<tr>
|
||||||
<td><code>strikethrough</code></td>
|
<td><code>strikethrough</code></td>
|
||||||
<td>Shows text with a horizontal line through the center</td>
|
<td>Shows text with a horizontal line through the center</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>link</link></td>
|
<td><code>link</link></td>
|
||||||
<td>Creates a clickable link within text</td>
|
<td>Creates a clickable link within text</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
@ -1,47 +1,47 @@
|
|||||||
Title: Command Help
|
Title: Command Help
|
||||||
Order: 13
|
Order: 13
|
||||||
Description: "Console applications built with *Spectre.Console.Cli* include automatically generated help command line help."
|
Description: "Console applications built with *Spectre.Console.Cli* include automatically generated help command line help."
|
||||||
---
|
---
|
||||||
|
|
||||||
Console applications built with `Spectre.Console.Cli` include automatically generated help which is displayed when `-h` or `--help` has been specified on the command line.
|
Console applications built with `Spectre.Console.Cli` include automatically generated help which is displayed when `-h` or `--help` has been specified on the command line.
|
||||||
|
|
||||||
The automatically generated help is derived from the configured commands and their command settings.
|
The automatically generated help is derived from the configured commands and their command settings.
|
||||||
|
|
||||||
The help is also context aware and tailored depending on what has been specified on the command line before it. For example,
|
The help is also context aware and tailored depending on what has been specified on the command line before it. For example,
|
||||||
|
|
||||||
1. When `-h` or `--help` appears immediately after the application name (eg. `application.exe --help`), then the help displayed is a high-level summary of the application, including any command line examples and a listing of all possible commands the user can execute.
|
1. When `-h` or `--help` appears immediately after the application name (eg. `application.exe --help`), then the help displayed is a high-level summary of the application, including any command line examples and a listing of all possible commands the user can execute.
|
||||||
|
|
||||||
2. When `-h` or `--help` appears immediately after a command has been specified (eg. `application.exe command --help`), then the help displayed is specific to the command and includes information about command specific switches and any default values.
|
2. When `-h` or `--help` appears immediately after a command has been specified (eg. `application.exe command --help`), then the help displayed is specific to the command and includes information about command specific switches and any default values.
|
||||||
|
|
||||||
`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`.
|
||||||
|
|
||||||
## 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.
|
||||||
|
|
||||||
You are able to implement your own `IHelpProvider` and configure a `CommandApp` to use that instead of the Spectre.Console help provider.
|
You are able to implement your own `IHelpProvider` and configure a `CommandApp` to use that instead of the Spectre.Console help provider.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
using Spectre.Console.Cli;
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
namespace Help;
|
namespace Help;
|
||||||
|
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
var app = new CommandApp<DefaultCommand>();
|
var app = new CommandApp<DefaultCommand>();
|
||||||
|
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
// Register the custom help provider
|
// Register the custom help provider
|
||||||
config.SetHelpProvider(new CustomHelpProvider(config.Settings));
|
config.SetHelpProvider(new CustomHelpProvider(config.Settings));
|
||||||
});
|
});
|
||||||
|
|
||||||
return app.Run(args);
|
return app.Run(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
There is a working [example of a custom help provider](https://github.com/spectreconsole/spectre.console/tree/main/examples/Cli/Help) demonstrating this.
|
There is a working [example of a custom help provider](https://github.com/spectreconsole/spectre.console/tree/main/examples/Cli/Help) demonstrating this.
|
||||||
|
|
||||||
|
@ -1,119 +1,119 @@
|
|||||||
Title: Markup
|
Title: Markup
|
||||||
Order: 30
|
Order: 30
|
||||||
Description: The Markup class allows you to output rich text to the console.
|
Description: The Markup class allows you to output rich text to the console.
|
||||||
Highlights:
|
Highlights:
|
||||||
- Easily add *color*.
|
- Easily add *color*.
|
||||||
- Add hyperlinks to for supported terminals.
|
- Add hyperlinks to for supported terminals.
|
||||||
- Emoji 🚀 parsing.
|
- Emoji 🚀 parsing.
|
||||||
Reference:
|
Reference:
|
||||||
- M:Spectre.Console.AnsiConsole.Markup(System.String)
|
- M:Spectre.Console.AnsiConsole.Markup(System.String)
|
||||||
- M:Spectre.Console.AnsiConsole.MarkupLine(System.String)
|
- M:Spectre.Console.AnsiConsole.MarkupLine(System.String)
|
||||||
- T:Spectre.Console.Markup
|
- T:Spectre.Console.Markup
|
||||||
---
|
---
|
||||||
|
|
||||||
The `Markup` class allows you to output rich text to the console.
|
The `Markup` class allows you to output rich text to the console.
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
Console markup uses a syntax inspired by bbcode. If you write the style (see [Styles](xref:styles))
|
Console markup uses a syntax inspired by bbcode. If you write the style (see [Styles](xref:styles))
|
||||||
in square brackets, e.g. `[bold red]`, that style will apply until it is closed with a `[/]`.
|
in square brackets, e.g. `[bold red]`, that style will apply until it is closed with a `[/]`.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
AnsiConsole.Write(new Markup("[bold yellow]Hello[/] [red]World![/]"));
|
AnsiConsole.Write(new Markup("[bold yellow]Hello[/] [red]World![/]"));
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Markup` class implements `IRenderable` which means that you
|
The `Markup` class implements `IRenderable` which means that you
|
||||||
can use this in tables, grids, and panels. Most classes that support
|
can use this in tables, grids, and panels. Most classes that support
|
||||||
rendering of `IRenderable` also have overloads for rendering rich text.
|
rendering of `IRenderable` also have overloads for rendering rich text.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var table = new Table();
|
var table = new Table();
|
||||||
table.AddColumn(new TableColumn(new Markup("[yellow]Foo[/]")));
|
table.AddColumn(new TableColumn(new Markup("[yellow]Foo[/]")));
|
||||||
table.AddColumn(new TableColumn("[blue]Bar[/]"));
|
table.AddColumn(new TableColumn("[blue]Bar[/]"));
|
||||||
AnsiConsole.Write(table);
|
AnsiConsole.Write(table);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Convenience methods
|
## Convenience methods
|
||||||
|
|
||||||
There are also convenience methods on `AnsiConsole` that can be used
|
There are also convenience methods on `AnsiConsole` that can be used
|
||||||
to write markup text to the console without instantiating a new `Markup`
|
to write markup text to the console without instantiating a new `Markup`
|
||||||
instance.
|
instance.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
AnsiConsole.Markup("[underline green]Hello[/] ");
|
AnsiConsole.Markup("[underline green]Hello[/] ");
|
||||||
AnsiConsole.MarkupLine("[bold]World[/]");
|
AnsiConsole.MarkupLine("[bold]World[/]");
|
||||||
```
|
```
|
||||||
|
|
||||||
## Escaping format characters
|
## Escaping format characters
|
||||||
|
|
||||||
To output a `[` you use `[[`, and to output a `]` you use `]]`.
|
To output a `[` you use `[[`, and to output a `]` you use `]]`.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
AnsiConsole.Markup("[[Hello]] "); // [Hello]
|
AnsiConsole.Markup("[[Hello]] "); // [Hello]
|
||||||
AnsiConsole.Markup("[red][[World]][/]"); // [World]
|
AnsiConsole.Markup("[red][[World]][/]"); // [World]
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use the `EscapeMarkup` extension method.
|
You can also use the `EscapeMarkup` extension method.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
AnsiConsole.Markup("[red]{0}[/]", "Hello [World]".EscapeMarkup());
|
AnsiConsole.Markup("[red]{0}[/]", "Hello [World]".EscapeMarkup());
|
||||||
```
|
```
|
||||||
You can also use the `Markup.Escape` method.
|
You can also use the `Markup.Escape` method.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
AnsiConsole.Markup("[red]{0}[/]", Markup.Escape("Hello [World]"));
|
AnsiConsole.Markup("[red]{0}[/]", Markup.Escape("Hello [World]"));
|
||||||
```
|
```
|
||||||
|
|
||||||
## Escaping Interpolated Strings
|
## Escaping Interpolated Strings
|
||||||
|
|
||||||
When working with interpolated strings, you can use the `MarkupInterpolated` and `MarkupLineInterpolated` methods to automatically escape the values in the interpolated string "holes".
|
When working with interpolated strings, you can use the `MarkupInterpolated` and `MarkupLineInterpolated` methods to automatically escape the values in the interpolated string "holes".
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
string hello = "Hello [World]";
|
string hello = "Hello [World]";
|
||||||
AnsiConsole.MarkupInterpolated($"[red]{hello}[/]");
|
AnsiConsole.MarkupInterpolated($"[red]{hello}[/]");
|
||||||
```
|
```
|
||||||
|
|
||||||
## Setting background color
|
## Setting background color
|
||||||
|
|
||||||
You can set the background color in markup by prefixing the color with `on`.
|
You can set the background color in markup by prefixing the color with `on`.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
AnsiConsole.Markup("[bold yellow on blue]Hello[/]");
|
AnsiConsole.Markup("[bold yellow on blue]Hello[/]");
|
||||||
AnsiConsole.Markup("[default on blue]World[/]");
|
AnsiConsole.Markup("[default on blue]World[/]");
|
||||||
```
|
```
|
||||||
|
|
||||||
## Rendering emojis
|
## Rendering emojis
|
||||||
|
|
||||||
To output an emoji as part of markup, you can use emoji shortcodes.
|
To output an emoji as part of markup, you can use emoji shortcodes.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
AnsiConsole.Markup("Hello :globe_showing_europe_africa:!");
|
AnsiConsole.Markup("Hello :globe_showing_europe_africa:!");
|
||||||
```
|
```
|
||||||
|
|
||||||
For a list of emoji, see the [Emojis](xref:emojis) appendix section.
|
For a list of emoji, see the [Emojis](xref:emojis) appendix section.
|
||||||
|
|
||||||
## Colors
|
## Colors
|
||||||
|
|
||||||
In the examples above, all colors were referenced by their name,
|
In the examples above, all colors were referenced by their name,
|
||||||
but you can also use the hex or rgb representation for colors in markdown.
|
but you can also use the hex or rgb representation for colors in markdown.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
AnsiConsole.Markup("[red]Foo[/] ");
|
AnsiConsole.Markup("[red]Foo[/] ");
|
||||||
AnsiConsole.Markup("[#ff0000]Bar[/] ");
|
AnsiConsole.Markup("[#ff0000]Bar[/] ");
|
||||||
AnsiConsole.Markup("[rgb(255,0,0)]Baz[/] ");
|
AnsiConsole.Markup("[rgb(255,0,0)]Baz[/] ");
|
||||||
```
|
```
|
||||||
|
|
||||||
For a list of colors, see the [Colors](xref:colors) appendix section.
|
For a list of colors, see the [Colors](xref:colors) appendix section.
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
To output a clickable link, you can use the `[link]` style.
|
To output a clickable link, you can use the `[link]` style.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
AnsiConsole.Markup("[link]https://spectreconsole.net[/]");
|
AnsiConsole.Markup("[link]https://spectreconsole.net[/]");
|
||||||
AnsiConsole.Markup("[link=https://spectreconsole.net]Spectre Console Documentation[/]");
|
AnsiConsole.Markup("[link=https://spectreconsole.net]Spectre Console Documentation[/]");
|
||||||
```
|
```
|
||||||
|
|
||||||
## Styles
|
## Styles
|
||||||
|
|
||||||
For a list of styles, see the [Styles](xref:styles) appendix section.
|
For a list of styles, see the [Styles](xref:styles) appendix section.
|
||||||
|
@ -63,22 +63,22 @@ What's the secret number? _
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
Enter password: ************_
|
Enter password: ************_
|
||||||
```
|
```
|
||||||
|
|
||||||
## Masks
|
## Masks
|
||||||
|
|
||||||
<?# Example symbol="M:Prompt.Program.AskPasswordWithCustomMask" project="Prompt" /?>
|
<?# Example symbol="M:Prompt.Program.AskPasswordWithCustomMask" project="Prompt" /?>
|
||||||
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Enter password: ------------_
|
Enter password: ------------_
|
||||||
```
|
```
|
||||||
|
|
||||||
You can utilize a null character to completely hide input.
|
You can utilize a null character to completely hide input.
|
||||||
|
|
||||||
<?# Example symbol="M:Prompt.Program.AskPasswordWithNullMask" project="Prompt" /?>
|
<?# Example symbol="M:Prompt.Program.AskPasswordWithNullMask" project="Prompt" /?>
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Enter password: _
|
Enter password: _
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Title: Calendar
|
Title: Calendar
|
||||||
Order: 40
|
Order: 40
|
||||||
RedirectFrom: calendar
|
RedirectFrom: calendar
|
||||||
Description: "The **Calendar** is used to render a calendar to the terminal."
|
Description: "The **Calendar** is used to render a calendar to the terminal."
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Statiq.App;
|
using Statiq.App;
|
||||||
using Statiq.Common;
|
using Statiq.Common;
|
||||||
using Statiq.Web;
|
using Statiq.Web;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Docs.Extensions
|
namespace Docs.Extensions
|
||||||
{
|
{
|
||||||
public static class StringExtensions
|
public static class StringExtensions
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Docs.Models
|
namespace Docs.Models
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Docs.Utilities;
|
using Docs.Utilities;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Statiq.Common;
|
using Statiq.Common;
|
||||||
using Statiq.Web.GitHub;
|
using Statiq.Web.GitHub;
|
||||||
using Statiq.Web.Netlify;
|
using Statiq.Web.Netlify;
|
||||||
|
|
||||||
|
@ -1,119 +1,119 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.FileProviders;
|
using Microsoft.Extensions.FileProviders;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Playwright;
|
using Microsoft.Playwright;
|
||||||
using Statiq.Common;
|
using Statiq.Common;
|
||||||
using Statiq.Core;
|
using Statiq.Core;
|
||||||
using Statiq.Web;
|
using Statiq.Web;
|
||||||
using Statiq.Web.Modules;
|
using Statiq.Web.Modules;
|
||||||
using Statiq.Web.Pipelines;
|
using Statiq.Web.Pipelines;
|
||||||
|
|
||||||
namespace Docs.Pipelines
|
namespace Docs.Pipelines
|
||||||
{
|
{
|
||||||
public class SocialImages : Pipeline
|
public class SocialImages : Pipeline
|
||||||
{
|
{
|
||||||
public SocialImages()
|
public SocialImages()
|
||||||
{
|
{
|
||||||
Dependencies.AddRange(nameof(Inputs));
|
Dependencies.AddRange(nameof(Inputs));
|
||||||
|
|
||||||
ProcessModules = new ModuleList
|
ProcessModules = new ModuleList
|
||||||
{
|
{
|
||||||
new GetPipelineDocuments(ContentType.Content),
|
new GetPipelineDocuments(ContentType.Content),
|
||||||
|
|
||||||
// Filter to non-archive content
|
// Filter to non-archive content
|
||||||
new FilterDocuments(Config.FromDocument(doc => !Archives.IsArchive(doc))),
|
new FilterDocuments(Config.FromDocument(doc => !Archives.IsArchive(doc))),
|
||||||
|
|
||||||
// Process the content
|
// Process the content
|
||||||
new CacheDocuments
|
new CacheDocuments
|
||||||
{
|
{
|
||||||
new AddTitle(),
|
new AddTitle(),
|
||||||
new SetDestination(true),
|
new SetDestination(true),
|
||||||
new ExecuteIf(Config.FromSetting(WebKeys.OptimizeContentFileNames, true))
|
new ExecuteIf(Config.FromSetting(WebKeys.OptimizeContentFileNames, true))
|
||||||
{
|
{
|
||||||
new OptimizeFileName()
|
new OptimizeFileName()
|
||||||
},
|
},
|
||||||
new GenerateSocialImage(),
|
new GenerateSocialImage(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
OutputModules = new ModuleList { new WriteFiles() };
|
OutputModules = new ModuleList { new WriteFiles() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GenerateSocialImage : ParallelModule
|
class GenerateSocialImage : ParallelModule
|
||||||
{
|
{
|
||||||
private IPlaywright _playwright;
|
private IPlaywright _playwright;
|
||||||
private IBrowser _browser;
|
private IBrowser _browser;
|
||||||
private WebApplication _app;
|
private WebApplication _app;
|
||||||
private IBrowserContext _context;
|
private IBrowserContext _context;
|
||||||
|
|
||||||
protected override async Task BeforeExecutionAsync(IExecutionContext context)
|
protected override async Task BeforeExecutionAsync(IExecutionContext context)
|
||||||
{
|
{
|
||||||
var builder = WebApplication.CreateBuilder();
|
var builder = WebApplication.CreateBuilder();
|
||||||
builder.Logging.ClearProviders();
|
builder.Logging.ClearProviders();
|
||||||
|
|
||||||
builder.Services
|
builder.Services
|
||||||
.AddRazorPages()
|
.AddRazorPages()
|
||||||
.WithRazorPagesRoot("/src/SocialCards/");
|
.WithRazorPagesRoot("/src/SocialCards/");
|
||||||
|
|
||||||
_app = builder.Build();
|
_app = builder.Build();
|
||||||
_app.MapRazorPages();
|
_app.MapRazorPages();
|
||||||
_app.UseStaticFiles(new StaticFileOptions
|
_app.UseStaticFiles(new StaticFileOptions
|
||||||
{
|
{
|
||||||
FileProvider = new PhysicalFileProvider(
|
FileProvider = new PhysicalFileProvider(
|
||||||
Path.Combine(builder.Environment.ContentRootPath, "src/SocialCards")),
|
Path.Combine(builder.Environment.ContentRootPath, "src/SocialCards")),
|
||||||
RequestPath = "/static"
|
RequestPath = "/static"
|
||||||
});
|
});
|
||||||
|
|
||||||
await _app.StartAsync().ConfigureAwait(false);
|
await _app.StartAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
_playwright = await Playwright.CreateAsync().ConfigureAwait(false);
|
_playwright = await Playwright.CreateAsync().ConfigureAwait(false);
|
||||||
_browser = await _playwright.Chromium.LaunchAsync().ConfigureAwait(false);
|
_browser = await _playwright.Chromium.LaunchAsync().ConfigureAwait(false);
|
||||||
_context = await _browser.NewContextAsync(new BrowserNewContextOptions {
|
_context = await _browser.NewContextAsync(new BrowserNewContextOptions {
|
||||||
ViewportSize = new ViewportSize { Width = 1200, Height = 618 },
|
ViewportSize = new ViewportSize { Width = 1200, Height = 618 },
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task FinallyAsync(IExecutionContext context)
|
protected override async Task FinallyAsync(IExecutionContext context)
|
||||||
{
|
{
|
||||||
await _context.DisposeAsync().ConfigureAwait(false);
|
await _context.DisposeAsync().ConfigureAwait(false);
|
||||||
await _browser.DisposeAsync().ConfigureAwait(false);
|
await _browser.DisposeAsync().ConfigureAwait(false);
|
||||||
_playwright.Dispose();
|
_playwright.Dispose();
|
||||||
await _app.DisposeAsync().ConfigureAwait(false);
|
await _app.DisposeAsync().ConfigureAwait(false);
|
||||||
await base.FinallyAsync(context);
|
await base.FinallyAsync(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<IEnumerable<IDocument>> ExecuteInputAsync(IDocument input, IExecutionContext context)
|
protected override async Task<IEnumerable<IDocument>> ExecuteInputAsync(IDocument input, IExecutionContext context)
|
||||||
{
|
{
|
||||||
var url = _app.Urls.FirstOrDefault(u => u.StartsWith("http://"));
|
var url = _app.Urls.FirstOrDefault(u => u.StartsWith("http://"));
|
||||||
var page = await _context.NewPageAsync().ConfigureAwait(false);
|
var page = await _context.NewPageAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
var title = input.GetString("Title");
|
var title = input.GetString("Title");
|
||||||
var description = input.GetString("Description");
|
var description = input.GetString("Description");
|
||||||
var highlights = input.GetList<string>("Highlights") ?? Array.Empty<string>();
|
var highlights = input.GetList<string>("Highlights") ?? Array.Empty<string>();
|
||||||
|
|
||||||
await page.GotoAsync($"{url}/?title={title}&desc={description}&highlights={string.Join("||", highlights)}");
|
await page.GotoAsync($"{url}/?title={title}&desc={description}&highlights={string.Join("||", highlights)}");
|
||||||
|
|
||||||
// This will not just wait for the page to load over the network, but it'll also give
|
// This will not just wait for the page to load over the network, but it'll also give
|
||||||
// chrome a chance to complete rendering of the fonts while the wait timeout completes.
|
// chrome a chance to complete rendering of the fonts while the wait timeout completes.
|
||||||
await page.WaitForLoadStateAsync(LoadState.NetworkIdle).ConfigureAwait(false);
|
await page.WaitForLoadStateAsync(LoadState.NetworkIdle).ConfigureAwait(false);
|
||||||
var bytes = await page.ScreenshotAsync().ConfigureAwait(false);
|
var bytes = await page.ScreenshotAsync().ConfigureAwait(false);
|
||||||
await page.CloseAsync().ConfigureAwait(false);
|
await page.CloseAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
var destination = input.Destination.InsertSuffix("-social").ChangeExtension("png");
|
var destination = input.Destination.InsertSuffix("-social").ChangeExtension("png");
|
||||||
var doc = context.CreateDocument(
|
var doc = context.CreateDocument(
|
||||||
input.Source,
|
input.Source,
|
||||||
destination,
|
destination,
|
||||||
new MetadataItems { { "DocId", input.Id }},
|
new MetadataItems { { "DocId", input.Id }},
|
||||||
context.GetContentProvider(bytes));
|
context.GetContentProvider(bytes));
|
||||||
|
|
||||||
return new[] { doc };
|
return new[] { doc };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Docs.Extensions;
|
using Docs.Extensions;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -15,22 +15,22 @@ public static class Program
|
|||||||
{
|
{
|
||||||
config.SetApplicationName("fake-dotnet");
|
config.SetApplicationName("fake-dotnet");
|
||||||
config.ValidateExamples();
|
config.ValidateExamples();
|
||||||
config.AddExample("run", "--no-build");
|
config.AddExample("run", "--no-build");
|
||||||
|
|
||||||
// Run
|
// Run
|
||||||
config.AddCommand<RunCommand>("run");
|
config.AddCommand<RunCommand>("run");
|
||||||
|
|
||||||
// Add
|
// Add
|
||||||
config.AddBranch<AddSettings>("add", add =>
|
config.AddBranch<AddSettings>("add", add =>
|
||||||
{
|
{
|
||||||
add.SetDescription("Add a package or reference to a .NET project");
|
add.SetDescription("Add a package or reference to a .NET project");
|
||||||
add.AddCommand<AddPackageCommand>("package");
|
add.AddCommand<AddPackageCommand>("package");
|
||||||
add.AddCommand<AddReferenceCommand>("reference");
|
add.AddCommand<AddReferenceCommand>("reference");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Serve
|
// Serve
|
||||||
config.AddCommand<ServeCommand>("serve")
|
config.AddCommand<ServeCommand>("serve")
|
||||||
.WithExample("serve", "-o", "firefox")
|
.WithExample("serve", "-o", "firefox")
|
||||||
.WithExample("serve", "--port", "80", "-o", "firefox");
|
.WithExample("serve", "--port", "80", "-o", "firefox");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using Spectre.Console.Cli;
|
using Spectre.Console.Cli;
|
||||||
using Spectre.Console.Cli.Help;
|
using Spectre.Console.Cli.Help;
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
namespace Help;
|
namespace Help;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Example showing how to extend the built-in Spectre.Console help provider
|
/// Example showing how to extend the built-in Spectre.Console help provider
|
||||||
/// by rendering a custom banner at the top of the help information
|
/// by rendering a custom banner at the top of the help information
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class CustomHelpProvider : HelpProvider
|
internal class CustomHelpProvider : HelpProvider
|
||||||
{
|
{
|
||||||
public CustomHelpProvider(ICommandAppSettings settings)
|
public CustomHelpProvider(ICommandAppSettings settings)
|
||||||
: base(settings)
|
: base(settings)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<IRenderable> GetHeader(ICommandModel model, ICommandInfo? command)
|
public override IEnumerable<IRenderable> GetHeader(ICommandModel model, ICommandInfo? command)
|
||||||
{
|
{
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
new Text("--------------------------------------"), Text.NewLine,
|
new Text("--------------------------------------"), Text.NewLine,
|
||||||
new Text("--- CUSTOM HELP PROVIDER ---"), Text.NewLine,
|
new Text("--- CUSTOM HELP PROVIDER ---"), Text.NewLine,
|
||||||
new Text("--------------------------------------"), Text.NewLine,
|
new Text("--------------------------------------"), Text.NewLine,
|
||||||
Text.NewLine,
|
Text.NewLine,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,20 +1,20 @@
|
|||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using Spectre.Console.Cli;
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
namespace Help;
|
namespace Help;
|
||||||
|
|
||||||
public sealed class DefaultCommand : Command
|
public sealed class DefaultCommand : Command
|
||||||
{
|
{
|
||||||
private IAnsiConsole _console;
|
private IAnsiConsole _console;
|
||||||
|
|
||||||
public DefaultCommand(IAnsiConsole console)
|
public DefaultCommand(IAnsiConsole console)
|
||||||
{
|
{
|
||||||
_console = console;
|
_console = console;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int Execute(CommandContext context)
|
public override int Execute(CommandContext context)
|
||||||
{
|
{
|
||||||
_console.WriteLine("Hello world");
|
_console.WriteLine("Hello world");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,19 +1,19 @@
|
|||||||
using Spectre.Console.Cli;
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
namespace Help;
|
namespace Help;
|
||||||
|
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
var app = new CommandApp<DefaultCommand>();
|
var app = new CommandApp<DefaultCommand>();
|
||||||
|
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
// Register the custom help provider
|
// Register the custom help provider
|
||||||
config.SetHelpProvider(new CustomHelpProvider(config.Settings));
|
config.SetHelpProvider(new CustomHelpProvider(config.Settings));
|
||||||
});
|
});
|
||||||
|
|
||||||
return app.Run(args);
|
return app.Run(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,11 @@ namespace Prompt
|
|||||||
var age = AskAge();
|
var age = AskAge();
|
||||||
|
|
||||||
WriteDivider("Secrets");
|
WriteDivider("Secrets");
|
||||||
var password = AskPassword();
|
var password = AskPassword();
|
||||||
|
|
||||||
WriteDivider("Mask");
|
WriteDivider("Mask");
|
||||||
var mask = AskPasswordWithCustomMask();
|
var mask = AskPasswordWithCustomMask();
|
||||||
|
|
||||||
WriteDivider("Null Mask");
|
WriteDivider("Null Mask");
|
||||||
var nullMask = AskPasswordWithNullMask();
|
var nullMask = AskPasswordWithNullMask();
|
||||||
|
|
||||||
@ -54,8 +54,8 @@ namespace Prompt
|
|||||||
.AddRow("[grey]Favorite fruit[/]", fruit)
|
.AddRow("[grey]Favorite fruit[/]", fruit)
|
||||||
.AddRow("[grey]Favorite sport[/]", sport)
|
.AddRow("[grey]Favorite sport[/]", sport)
|
||||||
.AddRow("[grey]Age[/]", age.ToString())
|
.AddRow("[grey]Age[/]", age.ToString())
|
||||||
.AddRow("[grey]Password[/]", password)
|
.AddRow("[grey]Password[/]", password)
|
||||||
.AddRow("[grey]Mask[/]", mask)
|
.AddRow("[grey]Mask[/]", mask)
|
||||||
.AddRow("[grey]Null Mask[/]", nullMask)
|
.AddRow("[grey]Null Mask[/]", nullMask)
|
||||||
.AddRow("[grey]Favorite color[/]", string.IsNullOrEmpty(color) ? "Unknown" : color));
|
.AddRow("[grey]Favorite color[/]", string.IsNullOrEmpty(color) ? "Unknown" : color));
|
||||||
}
|
}
|
||||||
@ -153,22 +153,22 @@ namespace Prompt
|
|||||||
new TextPrompt<string>("Enter [green]password[/]?")
|
new TextPrompt<string>("Enter [green]password[/]?")
|
||||||
.PromptStyle("red")
|
.PromptStyle("red")
|
||||||
.Secret());
|
.Secret());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string AskPasswordWithCustomMask()
|
public static string AskPasswordWithCustomMask()
|
||||||
{
|
{
|
||||||
return AnsiConsole.Prompt(
|
return AnsiConsole.Prompt(
|
||||||
new TextPrompt<string>("Enter [green]password[/]?")
|
new TextPrompt<string>("Enter [green]password[/]?")
|
||||||
.PromptStyle("red")
|
.PromptStyle("red")
|
||||||
.Secret('-'));
|
.Secret('-'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string AskPasswordWithNullMask()
|
public static string AskPasswordWithNullMask()
|
||||||
{
|
{
|
||||||
return AnsiConsole.Prompt(
|
return AnsiConsole.Prompt(
|
||||||
new TextPrompt<string>("Enter [green]password[/]?")
|
new TextPrompt<string>("Enter [green]password[/]?")
|
||||||
.PromptStyle("red")
|
.PromptStyle("red")
|
||||||
.Secret(null));
|
.Secret(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string AskColor()
|
public static string AskColor()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
|
|
||||||
namespace Generator.Commands
|
namespace Generator.Commands
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Microsoft.CodeAnalysis.Editing;
|
using Microsoft.CodeAnalysis.Editing;
|
||||||
using Microsoft.CodeAnalysis.Simplification;
|
using Microsoft.CodeAnalysis.Simplification;
|
||||||
|
|
||||||
namespace Spectre.Console.Analyzer.CodeActions;
|
namespace Spectre.Console.Analyzer.CodeActions;
|
||||||
@ -32,171 +32,171 @@ public class SwitchToAnsiConsoleAction : CodeAction
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override async Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
|
protected override async Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var editor = await DocumentEditor.CreateAsync(_document, cancellationToken).ConfigureAwait(false);
|
var editor = await DocumentEditor.CreateAsync(_document, cancellationToken).ConfigureAwait(false);
|
||||||
var compilation = editor.SemanticModel.Compilation;
|
var compilation = editor.SemanticModel.Compilation;
|
||||||
|
|
||||||
var operation = editor.SemanticModel.GetOperation(_originalInvocation, cancellationToken) as IInvocationOperation;
|
var operation = editor.SemanticModel.GetOperation(_originalInvocation, cancellationToken) as IInvocationOperation;
|
||||||
if (operation == null)
|
if (operation == null)
|
||||||
{
|
{
|
||||||
return _document;
|
return _document;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is an IAnsiConsole passed into the method then we'll use it.
|
// If there is an IAnsiConsole passed into the method then we'll use it.
|
||||||
// otherwise we'll check for a field level instance.
|
// otherwise we'll check for a field level instance.
|
||||||
// if neither of those exist we'll fall back to the static param.
|
// if neither of those exist we'll fall back to the static param.
|
||||||
var spectreConsoleSymbol = compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole");
|
var spectreConsoleSymbol = compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole");
|
||||||
var iansiConsoleSymbol = compilation.GetTypeByMetadataName("Spectre.Console.IAnsiConsole");
|
var iansiConsoleSymbol = compilation.GetTypeByMetadataName("Spectre.Console.IAnsiConsole");
|
||||||
|
|
||||||
ISymbol? accessibleConsoleSymbol = spectreConsoleSymbol;
|
ISymbol? accessibleConsoleSymbol = spectreConsoleSymbol;
|
||||||
if (iansiConsoleSymbol != null)
|
if (iansiConsoleSymbol != null)
|
||||||
{
|
{
|
||||||
var isInStaticContext = IsInStaticContext(operation, cancellationToken, out var parentStaticMemberStartPosition);
|
var isInStaticContext = IsInStaticContext(operation, cancellationToken, out var parentStaticMemberStartPosition);
|
||||||
|
|
||||||
foreach (var symbol in editor.SemanticModel.LookupSymbols(operation.Syntax.GetLocation().SourceSpan.Start))
|
foreach (var symbol in editor.SemanticModel.LookupSymbols(operation.Syntax.GetLocation().SourceSpan.Start))
|
||||||
{
|
{
|
||||||
// LookupSymbols check the accessibility of the symbol, but it can
|
// LookupSymbols check the accessibility of the symbol, but it can
|
||||||
// suggest instance members when the current context is static.
|
// suggest instance members when the current context is static.
|
||||||
var symbolType = symbol switch
|
var symbolType = symbol switch
|
||||||
{
|
{
|
||||||
IParameterSymbol parameter => parameter.Type,
|
IParameterSymbol parameter => parameter.Type,
|
||||||
IFieldSymbol field when !isInStaticContext || field.IsStatic => field.Type,
|
IFieldSymbol field when !isInStaticContext || field.IsStatic => field.Type,
|
||||||
IPropertySymbol { GetMethod: not null } property when !isInStaticContext || property.IsStatic => property.Type,
|
IPropertySymbol { GetMethod: not null } property when !isInStaticContext || property.IsStatic => property.Type,
|
||||||
ILocalSymbol local => local.Type,
|
ILocalSymbol local => local.Type,
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Locals can be returned even if there are not valid in the current context. For instance,
|
// Locals can be returned even if there are not valid in the current context. For instance,
|
||||||
// it can return locals declared after the current location. Or it can return locals that
|
// it can return locals declared after the current location. Or it can return locals that
|
||||||
// should not be accessible in a static local function.
|
// should not be accessible in a static local function.
|
||||||
//
|
//
|
||||||
// void Sample()
|
// void Sample()
|
||||||
// {
|
// {
|
||||||
// int local = 0;
|
// int local = 0;
|
||||||
// static void LocalFunction() => local; <-- local is invalid here but LookupSymbols suggests it
|
// static void LocalFunction() => local; <-- local is invalid here but LookupSymbols suggests it
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Parameters from the ancestor methods or local functions are also returned even if the operation is in a static local function.
|
// Parameters from the ancestor methods or local functions are also returned even if the operation is in a static local function.
|
||||||
if (symbol.Kind is SymbolKind.Local or SymbolKind.Parameter)
|
if (symbol.Kind is SymbolKind.Local or SymbolKind.Parameter)
|
||||||
{
|
{
|
||||||
var localPosition = symbol.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax(cancellationToken).GetLocation().SourceSpan.Start;
|
var localPosition = symbol.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax(cancellationToken).GetLocation().SourceSpan.Start;
|
||||||
|
|
||||||
// The local is not part of the source tree
|
// The local is not part of the source tree
|
||||||
if (localPosition == null)
|
if (localPosition == null)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The local is declared after the current expression
|
// The local is declared after the current expression
|
||||||
if (localPosition > _originalInvocation.Span.Start)
|
if (localPosition > _originalInvocation.Span.Start)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The local is declared outside the static local function
|
// The local is declared outside the static local function
|
||||||
if (isInStaticContext && localPosition < parentStaticMemberStartPosition)
|
if (isInStaticContext && localPosition < parentStaticMemberStartPosition)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsOrImplementSymbol(symbolType, iansiConsoleSymbol))
|
if (IsOrImplementSymbol(symbolType, iansiConsoleSymbol))
|
||||||
{
|
{
|
||||||
accessibleConsoleSymbol = symbol;
|
accessibleConsoleSymbol = symbol;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessibleConsoleSymbol == null)
|
if (accessibleConsoleSymbol == null)
|
||||||
{
|
{
|
||||||
return _document;
|
return _document;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the original invocation
|
// Replace the original invocation
|
||||||
var generator = editor.Generator;
|
var generator = editor.Generator;
|
||||||
var consoleExpression = accessibleConsoleSymbol switch
|
var consoleExpression = accessibleConsoleSymbol switch
|
||||||
{
|
{
|
||||||
ITypeSymbol typeSymbol => generator.TypeExpression(typeSymbol, addImport: true).WithAdditionalAnnotations(Simplifier.AddImportsAnnotation),
|
ITypeSymbol typeSymbol => generator.TypeExpression(typeSymbol, addImport: true).WithAdditionalAnnotations(Simplifier.AddImportsAnnotation),
|
||||||
_ => generator.IdentifierName(accessibleConsoleSymbol.Name),
|
_ => generator.IdentifierName(accessibleConsoleSymbol.Name),
|
||||||
};
|
};
|
||||||
|
|
||||||
var newExpression = generator.InvocationExpression(generator.MemberAccessExpression(consoleExpression, operation.TargetMethod.Name), _originalInvocation.ArgumentList.Arguments)
|
var newExpression = generator.InvocationExpression(generator.MemberAccessExpression(consoleExpression, operation.TargetMethod.Name), _originalInvocation.ArgumentList.Arguments)
|
||||||
.WithLeadingTrivia(_originalInvocation.GetLeadingTrivia())
|
.WithLeadingTrivia(_originalInvocation.GetLeadingTrivia())
|
||||||
.WithTrailingTrivia(_originalInvocation.GetTrailingTrivia());
|
.WithTrailingTrivia(_originalInvocation.GetTrailingTrivia());
|
||||||
|
|
||||||
editor.ReplaceNode(_originalInvocation, newExpression);
|
editor.ReplaceNode(_originalInvocation, newExpression);
|
||||||
|
|
||||||
return editor.GetChangedDocument();
|
return editor.GetChangedDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsOrImplementSymbol(ITypeSymbol? symbol, ITypeSymbol interfaceSymbol)
|
private static bool IsOrImplementSymbol(ITypeSymbol? symbol, ITypeSymbol interfaceSymbol)
|
||||||
{
|
{
|
||||||
if (symbol == null)
|
if (symbol == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SymbolEqualityComparer.Default.Equals(symbol, interfaceSymbol))
|
if (SymbolEqualityComparer.Default.Equals(symbol, interfaceSymbol))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var iface in symbol.AllInterfaces)
|
foreach (var iface in symbol.AllInterfaces)
|
||||||
{
|
{
|
||||||
if (SymbolEqualityComparer.Default.Equals(iface, interfaceSymbol))
|
if (SymbolEqualityComparer.Default.Equals(iface, interfaceSymbol))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsInStaticContext(IOperation operation, CancellationToken cancellationToken, out int parentStaticMemberStartPosition)
|
private static bool IsInStaticContext(IOperation operation, CancellationToken cancellationToken, out int parentStaticMemberStartPosition)
|
||||||
{
|
{
|
||||||
// Local functions can be nested, and an instance local function can be declared
|
// Local functions can be nested, and an instance local function can be declared
|
||||||
// in a static local function. So, you need to continue to check ancestors when a
|
// in a static local function. So, you need to continue to check ancestors when a
|
||||||
// local function is not static.
|
// local function is not static.
|
||||||
foreach (var member in operation.Syntax.Ancestors())
|
foreach (var member in operation.Syntax.Ancestors())
|
||||||
{
|
{
|
||||||
if (member is LocalFunctionStatementSyntax localFunction)
|
if (member is LocalFunctionStatementSyntax localFunction)
|
||||||
{
|
{
|
||||||
var symbol = operation.SemanticModel!.GetDeclaredSymbol(localFunction, cancellationToken);
|
var symbol = operation.SemanticModel!.GetDeclaredSymbol(localFunction, cancellationToken);
|
||||||
if (symbol != null && symbol.IsStatic)
|
if (symbol != null && symbol.IsStatic)
|
||||||
{
|
{
|
||||||
parentStaticMemberStartPosition = localFunction.GetLocation().SourceSpan.Start;
|
parentStaticMemberStartPosition = localFunction.GetLocation().SourceSpan.Start;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (member is LambdaExpressionSyntax lambdaExpression)
|
else if (member is LambdaExpressionSyntax lambdaExpression)
|
||||||
{
|
{
|
||||||
var symbol = operation.SemanticModel!.GetSymbolInfo(lambdaExpression, cancellationToken).Symbol;
|
var symbol = operation.SemanticModel!.GetSymbolInfo(lambdaExpression, cancellationToken).Symbol;
|
||||||
if (symbol != null && symbol.IsStatic)
|
if (symbol != null && symbol.IsStatic)
|
||||||
{
|
{
|
||||||
parentStaticMemberStartPosition = lambdaExpression.GetLocation().SourceSpan.Start;
|
parentStaticMemberStartPosition = lambdaExpression.GetLocation().SourceSpan.Start;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (member is AnonymousMethodExpressionSyntax anonymousMethod)
|
else if (member is AnonymousMethodExpressionSyntax anonymousMethod)
|
||||||
{
|
{
|
||||||
var symbol = operation.SemanticModel!.GetSymbolInfo(anonymousMethod, cancellationToken).Symbol;
|
var symbol = operation.SemanticModel!.GetSymbolInfo(anonymousMethod, cancellationToken).Symbol;
|
||||||
if (symbol != null && symbol.IsStatic)
|
if (symbol != null && symbol.IsStatic)
|
||||||
{
|
{
|
||||||
parentStaticMemberStartPosition = anonymousMethod.GetLocation().SourceSpan.Start;
|
parentStaticMemberStartPosition = anonymousMethod.GetLocation().SourceSpan.Start;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (member is MethodDeclarationSyntax methodDeclaration)
|
else if (member is MethodDeclarationSyntax methodDeclaration)
|
||||||
{
|
{
|
||||||
parentStaticMemberStartPosition = methodDeclaration.GetLocation().SourceSpan.Start;
|
parentStaticMemberStartPosition = methodDeclaration.GetLocation().SourceSpan.Start;
|
||||||
|
|
||||||
var symbol = operation.SemanticModel!.GetDeclaredSymbol(methodDeclaration, cancellationToken);
|
var symbol = operation.SemanticModel!.GetDeclaredSymbol(methodDeclaration, cancellationToken);
|
||||||
return symbol != null && symbol.IsStatic;
|
return symbol != null && symbol.IsStatic;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parentStaticMemberStartPosition = -1;
|
parentStaticMemberStartPosition = -1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
using Spectre.Console.Cli.Internal.Configuration;
|
using Spectre.Console.Cli.Internal.Configuration;
|
||||||
|
|
||||||
namespace Spectre.Console.Cli;
|
namespace Spectre.Console.Cli;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
using Spectre.Console.Cli.Internal.Configuration;
|
using Spectre.Console.Cli.Internal.Configuration;
|
||||||
|
|
||||||
namespace Spectre.Console.Cli;
|
namespace Spectre.Console.Cli;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -49,8 +49,8 @@ public sealed class CommandApp<TDefaultCommand> : ICommandApp
|
|||||||
public Task<int> RunAsync(IEnumerable<string> args)
|
public Task<int> RunAsync(IEnumerable<string> args)
|
||||||
{
|
{
|
||||||
return _app.RunAsync(args);
|
return _app.RunAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Configurator GetConfigurator()
|
internal Configurator GetConfigurator()
|
||||||
{
|
{
|
||||||
return _app.GetConfigurator();
|
return _app.GetConfigurator();
|
||||||
|
@ -5,40 +5,40 @@ namespace Spectre.Console.Cli;
|
|||||||
/// and <see cref="IConfigurator{TSettings}"/>.
|
/// and <see cref="IConfigurator{TSettings}"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ConfiguratorExtensions
|
public static class ConfiguratorExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the help provider for the application.
|
/// Sets the help provider for the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="configurator">The configurator.</param>
|
/// <param name="configurator">The configurator.</param>
|
||||||
/// <param name="helpProvider">The help provider to use.</param>
|
/// <param name="helpProvider">The help provider to use.</param>
|
||||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||||
public static IConfigurator SetHelpProvider(this IConfigurator configurator, IHelpProvider helpProvider)
|
public static IConfigurator SetHelpProvider(this IConfigurator configurator, IHelpProvider helpProvider)
|
||||||
{
|
{
|
||||||
if (configurator == null)
|
if (configurator == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(configurator));
|
throw new ArgumentNullException(nameof(configurator));
|
||||||
}
|
}
|
||||||
|
|
||||||
configurator.SetHelpProvider(helpProvider);
|
configurator.SetHelpProvider(helpProvider);
|
||||||
return configurator;
|
return configurator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the help provider for the application.
|
/// Sets the help provider for the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="configurator">The configurator.</param>
|
/// <param name="configurator">The configurator.</param>
|
||||||
/// <typeparam name="T">The type of the help provider to instantiate at runtime and use.</typeparam>
|
/// <typeparam name="T">The type of the help provider to instantiate at runtime and use.</typeparam>
|
||||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||||
public static IConfigurator SetHelpProvider<T>(this IConfigurator configurator)
|
public static IConfigurator SetHelpProvider<T>(this IConfigurator configurator)
|
||||||
where T : IHelpProvider
|
where T : IHelpProvider
|
||||||
{
|
{
|
||||||
if (configurator == null)
|
if (configurator == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(configurator));
|
throw new ArgumentNullException(nameof(configurator));
|
||||||
}
|
}
|
||||||
|
|
||||||
configurator.SetHelpProvider<T>();
|
configurator.SetHelpProvider<T>();
|
||||||
return configurator;
|
return configurator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -11,22 +11,22 @@ namespace Spectre.Console.Cli.Help;
|
|||||||
public class HelpProvider : IHelpProvider
|
public class HelpProvider : IHelpProvider
|
||||||
{
|
{
|
||||||
private HelpProviderResources resources;
|
private HelpProviderResources resources;
|
||||||
|
|
||||||
/// <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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual int MaximumIndirectExamples { get; }
|
protected virtual int MaximumIndirectExamples { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether any default values for command options are shown in the help text.
|
/// Gets a value indicating whether any default values for command options are shown in the help text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual bool ShowOptionDefaultValues { get; }
|
protected virtual bool ShowOptionDefaultValues { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether a trailing period of a command description is trimmed in the help text.
|
/// Gets a value indicating whether a trailing period of a command description is trimmed in the help text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual bool TrimTrailingPeriod { get; }
|
protected virtual bool TrimTrailingPeriod { get; }
|
||||||
|
|
||||||
private sealed class HelpArgument
|
private sealed class HelpArgument
|
||||||
{
|
{
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
@ -74,14 +74,14 @@ public class HelpProvider : IHelpProvider
|
|||||||
public static IReadOnlyList<HelpOption> Get(ICommandInfo? command, HelpProviderResources resources)
|
public static IReadOnlyList<HelpOption> Get(ICommandInfo? command, HelpProviderResources resources)
|
||||||
{
|
{
|
||||||
var parameters = new List<HelpOption>();
|
var parameters = new List<HelpOption>();
|
||||||
parameters.Add(new HelpOption("h", "help", null, null, resources.PrintHelpDescription, null));
|
parameters.Add(new HelpOption("h", "help", null, null, resources.PrintHelpDescription, null));
|
||||||
|
|
||||||
// Version information applies to the entire application
|
// Version information applies to the entire application
|
||||||
// Include the "-v" option in the help when at the root of the command line application
|
// Include the "-v" option in the help when at the root of the command line application
|
||||||
// Don't allow the "-v" option if users have specified one or more sub-commands
|
// Don't allow the "-v" option if users have specified one or more sub-commands
|
||||||
if ((command == null || command?.Parent == null) && !(command?.IsBranch ?? false))
|
if ((command == null || command?.Parent == null) && !(command?.IsBranch ?? false))
|
||||||
{
|
{
|
||||||
parameters.Add(new HelpOption("v", "version", null, null, resources.PrintVersionDescription, null));
|
parameters.Add(new HelpOption("v", "version", null, null, resources.PrintVersionDescription, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
parameters.AddRange(command?.Parameters.OfType<ICommandOption>().Where(o => !o.IsHidden).Select(o =>
|
parameters.AddRange(command?.Parameters.OfType<ICommandOption>().Where(o => !o.IsHidden).Select(o =>
|
||||||
@ -92,55 +92,55 @@ public class HelpProvider : IHelpProvider
|
|||||||
?? Array.Empty<HelpOption>());
|
?? Array.Empty<HelpOption>());
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="HelpProvider"/> class.
|
/// Initializes a new instance of the <see cref="HelpProvider"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="settings">The command line application settings used for configuration.</param>
|
/// <param name="settings">The command line application settings used for configuration.</param>
|
||||||
public HelpProvider(ICommandAppSettings settings)
|
public HelpProvider(ICommandAppSettings settings)
|
||||||
{
|
{
|
||||||
this.ShowOptionDefaultValues = settings.ShowOptionDefaultValues;
|
this.ShowOptionDefaultValues = settings.ShowOptionDefaultValues;
|
||||||
this.MaximumIndirectExamples = settings.MaximumIndirectExamples;
|
this.MaximumIndirectExamples = settings.MaximumIndirectExamples;
|
||||||
this.TrimTrailingPeriod = settings.TrimTrailingPeriod;
|
this.TrimTrailingPeriod = settings.TrimTrailingPeriod;
|
||||||
|
|
||||||
resources = new HelpProviderResources(settings.Culture);
|
resources = new HelpProviderResources(settings.Culture);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual IEnumerable<IRenderable> Write(ICommandModel model, ICommandInfo? command)
|
public virtual IEnumerable<IRenderable> Write(ICommandModel model, ICommandInfo? command)
|
||||||
{
|
{
|
||||||
var result = new List<IRenderable>();
|
var result = new List<IRenderable>();
|
||||||
|
|
||||||
result.AddRange(GetHeader(model, command));
|
result.AddRange(GetHeader(model, command));
|
||||||
result.AddRange(GetDescription(model, command));
|
result.AddRange(GetDescription(model, command));
|
||||||
result.AddRange(GetUsage(model, command));
|
result.AddRange(GetUsage(model, command));
|
||||||
result.AddRange(GetExamples(model, command));
|
result.AddRange(GetExamples(model, command));
|
||||||
result.AddRange(GetArguments(model, command));
|
result.AddRange(GetArguments(model, command));
|
||||||
result.AddRange(GetOptions(model, command));
|
result.AddRange(GetOptions(model, command));
|
||||||
result.AddRange(GetCommands(model, command));
|
result.AddRange(GetCommands(model, command));
|
||||||
result.AddRange(GetFooter(model, command));
|
result.AddRange(GetFooter(model, command));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the header for the help information.
|
/// Gets the header for the help information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">The command model to write help for.</param>
|
/// <param name="model">The command model to write help for.</param>
|
||||||
/// <param name="command">The command for which to write help information (optional).</param>
|
/// <param name="command">The command for which to write help information (optional).</param>
|
||||||
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
||||||
public virtual IEnumerable<IRenderable> GetHeader(ICommandModel model, ICommandInfo? command)
|
public virtual IEnumerable<IRenderable> GetHeader(ICommandModel model, ICommandInfo? command)
|
||||||
{
|
{
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the description section of the help information.
|
/// Gets the description section of the help information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">The command model to write help for.</param>
|
/// <param name="model">The command model to write help for.</param>
|
||||||
/// <param name="command">The command for which to write help information (optional).</param>
|
/// <param name="command">The command for which to write help information (optional).</param>
|
||||||
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
||||||
public virtual IEnumerable<IRenderable> GetDescription(ICommandModel model, ICommandInfo? command)
|
public virtual IEnumerable<IRenderable> GetDescription(ICommandModel model, ICommandInfo? command)
|
||||||
{
|
{
|
||||||
if (command?.Description == null)
|
if (command?.Description == null)
|
||||||
@ -152,14 +152,14 @@ public class HelpProvider : IHelpProvider
|
|||||||
composer.Style("yellow", $"{resources.Description}:").LineBreak();
|
composer.Style("yellow", $"{resources.Description}:").LineBreak();
|
||||||
composer.Text(command.Description).LineBreak();
|
composer.Text(command.Description).LineBreak();
|
||||||
yield return composer.LineBreak();
|
yield return composer.LineBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the usage section of the help information.
|
/// Gets the usage section of the help information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">The command model to write help for.</param>
|
/// <param name="model">The command model to write help for.</param>
|
||||||
/// <param name="command">The command for which to write help information (optional).</param>
|
/// <param name="command">The command for which to write help information (optional).</param>
|
||||||
/// <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 = new Composer();
|
||||||
@ -219,26 +219,26 @@ public class HelpProvider : IHelpProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
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($"[aqua]<{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($"[aqua][[{resources.Command}]][/]");
|
||||||
}
|
}
|
||||||
else if (command.IsDefaultCommand)
|
else if (command.IsDefaultCommand)
|
||||||
{
|
{
|
||||||
var commands = model.Commands.Where(x => !x.IsHidden && !x.IsDefaultCommand).ToList();
|
var commands = model.Commands.Where(x => !x.IsHidden && !x.IsDefaultCommand).ToList();
|
||||||
|
|
||||||
if (commands.Count > 0)
|
if (commands.Count > 0)
|
||||||
{
|
{
|
||||||
// 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($"[aqua][[{resources.Command}]][/]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,19 +249,19 @@ public class HelpProvider : IHelpProvider
|
|||||||
{
|
{
|
||||||
composer,
|
composer,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the examples section of the help information.
|
/// Gets the examples section of the help information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">The command model to write help for.</param>
|
/// <param name="model">The command model to write help for.</param>
|
||||||
/// <param name="command">The command for which to write help information (optional).</param>
|
/// <param name="command">The command for which to write help information (optional).</param>
|
||||||
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Examples from the command's direct children are used
|
/// Examples from the command's direct children are used
|
||||||
/// if no examples have been set on the specified command or model.
|
/// if no examples have been set on the specified command or model.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public virtual IEnumerable<IRenderable> GetExamples(ICommandModel model, ICommandInfo? command)
|
public virtual IEnumerable<IRenderable> GetExamples(ICommandModel model, ICommandInfo? command)
|
||||||
{
|
{
|
||||||
var maxExamples = int.MaxValue;
|
var maxExamples = int.MaxValue;
|
||||||
|
|
||||||
@ -272,12 +272,12 @@ public class HelpProvider : IHelpProvider
|
|||||||
// make sure that we limit the number of examples.
|
// make sure that we limit the number of examples.
|
||||||
maxExamples = MaximumIndirectExamples;
|
maxExamples = MaximumIndirectExamples;
|
||||||
|
|
||||||
// Start at the current command (if exists)
|
// Start at the current command (if exists)
|
||||||
// or alternatively commence at the model.
|
// or alternatively commence at the model.
|
||||||
var commandContainer = command ?? (ICommandContainer)model;
|
var commandContainer = command ?? (ICommandContainer)model;
|
||||||
var queue = new Queue<ICommandContainer>(new[] { commandContainer });
|
var queue = new Queue<ICommandContainer>(new[] { commandContainer });
|
||||||
|
|
||||||
// Traverse the command tree and look for examples.
|
// Traverse the command tree and look for examples.
|
||||||
// As soon as a node contains commands, bail.
|
// As soon as a node contains commands, bail.
|
||||||
while (queue.Count > 0)
|
while (queue.Count > 0)
|
||||||
{
|
{
|
||||||
@ -317,14 +317,14 @@ public class HelpProvider : IHelpProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Array.Empty<IRenderable>();
|
return Array.Empty<IRenderable>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the arguments section of the help information.
|
/// Gets the arguments section of the help information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">The command model to write help for.</param>
|
/// <param name="model">The command model to write help for.</param>
|
||||||
/// <param name="command">The command for which to write help information (optional).</param>
|
/// <param name="command">The command for which to write help information (optional).</param>
|
||||||
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
||||||
public virtual IEnumerable<IRenderable> GetArguments(ICommandModel model, ICommandInfo? command)
|
public virtual IEnumerable<IRenderable> GetArguments(ICommandModel model, ICommandInfo? command)
|
||||||
{
|
{
|
||||||
var arguments = HelpArgument.Get(command);
|
var arguments = HelpArgument.Get(command);
|
||||||
@ -361,13 +361,13 @@ public class HelpProvider : IHelpProvider
|
|||||||
result.Add(grid);
|
result.Add(grid);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the options section of the help information.
|
/// Gets the options section of the help information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">The command model to write help for.</param>
|
/// <param name="model">The command model to write help for.</param>
|
||||||
/// <param name="command">The command for which to write help information (optional).</param>
|
/// <param name="command">The command for which to write help information (optional).</param>
|
||||||
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
||||||
public virtual IEnumerable<IRenderable> GetOptions(ICommandModel model, ICommandInfo? command)
|
public virtual IEnumerable<IRenderable> GetOptions(ICommandModel model, ICommandInfo? command)
|
||||||
{
|
{
|
||||||
@ -469,18 +469,18 @@ public class HelpProvider : IHelpProvider
|
|||||||
result.Add(grid);
|
result.Add(grid);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the commands section of the help information.
|
/// Gets the commands section of the help information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">The command model to write help for.</param>
|
/// <param name="model">The command model to write help for.</param>
|
||||||
/// <param name="command">The command for which to write help information (optional).</param>
|
/// <param name="command">The command for which to write help information (optional).</param>
|
||||||
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
||||||
public virtual IEnumerable<IRenderable> GetCommands(ICommandModel model, ICommandInfo? command)
|
public virtual IEnumerable<IRenderable> GetCommands(ICommandModel model, ICommandInfo? command)
|
||||||
{
|
{
|
||||||
var commandContainer = command ?? (ICommandContainer)model;
|
var commandContainer = command ?? (ICommandContainer)model;
|
||||||
bool isDefaultCommand = command?.IsDefaultCommand ?? false;
|
bool isDefaultCommand = command?.IsDefaultCommand ?? false;
|
||||||
|
|
||||||
var commands = isDefaultCommand ? model.Commands : commandContainer.Commands;
|
var commands = isDefaultCommand ? model.Commands : commandContainer.Commands;
|
||||||
commands = commands.Where(x => !x.IsHidden).ToList();
|
commands = commands.Where(x => !x.IsHidden).ToList();
|
||||||
@ -530,16 +530,16 @@ public class HelpProvider : IHelpProvider
|
|||||||
result.Add(grid);
|
result.Add(grid);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the footer for the help information.
|
/// Gets the footer for the help information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">The command model to write help for.</param>
|
/// <param name="model">The command model to write help for.</param>
|
||||||
/// <param name="command">The command for which to write help information (optional).</param>
|
/// <param name="command">The command for which to write help information (optional).</param>
|
||||||
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects.</returns>
|
||||||
public virtual IEnumerable<IRenderable> GetFooter(ICommandModel model, ICommandInfo? command)
|
public virtual IEnumerable<IRenderable> GetFooter(ICommandModel model, ICommandInfo? command)
|
||||||
{
|
{
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,7 @@ namespace Spectre.Console.Cli.Help;
|
|||||||
/// Represents a command container.
|
/// Represents a command container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICommandContainer
|
public interface ICommandContainer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all the examples for the container.
|
/// Gets all the examples for the container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,42 +1,42 @@
|
|||||||
namespace Spectre.Console.Cli.Help;
|
namespace Spectre.Console.Cli.Help;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an executable command.
|
/// Represents an executable command.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICommandInfo : ICommandContainer
|
public interface ICommandInfo : ICommandContainer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the command.
|
/// Gets the name of the command.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Name { get; }
|
string Name { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the description of the command.
|
/// Gets the description of the command.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string? Description { get; }
|
string? Description { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the command is a branch.
|
/// Gets a value indicating whether the command is a branch.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsBranch { get; }
|
bool IsBranch { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the command is the default command within its container.
|
/// Gets a value indicating whether the command is the default command within its container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsDefaultCommand { get; }
|
bool IsDefaultCommand { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the command is hidden.
|
/// Gets a value indicating whether the command is hidden.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsHidden { get; }
|
bool IsHidden { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the parameters associated with the command.
|
/// Gets the parameters associated with the command.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IReadOnlyList<ICommandParameter> Parameters { get; }
|
IReadOnlyList<ICommandParameter> Parameters { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the parent command, if any.
|
/// Gets the parent command, if any.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ICommandInfo? Parent { get; }
|
ICommandInfo? Parent { get; }
|
||||||
}
|
}
|
@ -1,23 +1,23 @@
|
|||||||
namespace Spectre.Console.Cli.Help;
|
namespace Spectre.Console.Cli.Help;
|
||||||
|
|
||||||
internal static class ICommandInfoExtensions
|
internal static class ICommandInfoExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Walks up the command.Parent tree, adding each command into a list as it goes.
|
/// Walks up the command.Parent tree, adding each command into a list as it goes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>The first command added to the list is the current (ie. this one).</remarks>
|
/// <remarks>The first command added to the list is the current (ie. this one).</remarks>
|
||||||
/// <returns>The list of commands from current to root, as traversed by <see cref="CommandInfo.Parent"/>.</returns>
|
/// <returns>The list of commands from current to root, as traversed by <see cref="CommandInfo.Parent"/>.</returns>
|
||||||
public static List<ICommandInfo> Flatten(this ICommandInfo commandInfo)
|
public static List<ICommandInfo> Flatten(this ICommandInfo commandInfo)
|
||||||
{
|
{
|
||||||
var result = new Stack<Help.ICommandInfo>();
|
var result = new Stack<Help.ICommandInfo>();
|
||||||
|
|
||||||
var current = commandInfo;
|
var current = commandInfo;
|
||||||
while (current != null)
|
while (current != null)
|
||||||
{
|
{
|
||||||
result.Push(current);
|
result.Push(current);
|
||||||
current = current.Parent;
|
current = current.Parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.ToList();
|
return result.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
namespace Spectre.Console.Cli.Help;
|
namespace Spectre.Console.Cli.Help;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a command option.
|
/// Represents a command option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICommandOption : ICommandParameter
|
public interface ICommandOption : ICommandParameter
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the long names of the option.
|
/// Gets the long names of the option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IReadOnlyList<string> LongNames { get; }
|
IReadOnlyList<string> LongNames { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the short names of the option.
|
/// Gets the short names of the option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IReadOnlyList<string> ShortNames { get; }
|
IReadOnlyList<string> ShortNames { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the value name of the option, if applicable.
|
/// Gets the value name of the option, if applicable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string? ValueName { get; }
|
string? ValueName { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the option value is optional.
|
/// Gets a value indicating whether the option value is optional.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool ValueIsOptional { get; }
|
bool ValueIsOptional { get; }
|
||||||
}
|
}
|
@ -1,32 +1,32 @@
|
|||||||
namespace Spectre.Console.Cli.Help;
|
namespace Spectre.Console.Cli.Help;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a command parameter.
|
/// Represents a command parameter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICommandParameter
|
public interface ICommandParameter
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the parameter is a flag.
|
/// Gets a value indicating whether the parameter is a flag.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsFlag { get; }
|
bool IsFlag { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the parameter is required.
|
/// Gets a value indicating whether the parameter is required.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool Required { get; }
|
bool Required { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the description of the parameter.
|
/// Gets the description of the parameter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string? Description { get; }
|
string? Description { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the default value of the parameter, if specified.
|
/// Gets the default value of the parameter, if specified.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DefaultValueAttribute? DefaultValue { get; }
|
DefaultValueAttribute? DefaultValue { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the parameter is hidden.
|
/// Gets a value indicating whether the parameter is hidden.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsHidden { get; }
|
bool IsHidden { get; }
|
||||||
}
|
}
|
@ -1,20 +1,20 @@
|
|||||||
namespace Spectre.Console.Cli.Help;
|
namespace Spectre.Console.Cli.Help;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The help provider interface for Spectre.Console.
|
/// The help provider interface for Spectre.Console.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Implementations of this interface are responsbile
|
/// Implementations of this interface are responsbile
|
||||||
/// for writing command help to the terminal when the
|
/// for writing command help to the terminal when the
|
||||||
/// `-h` or `--help` has been specified on the command line.
|
/// `-h` or `--help` has been specified on the command line.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public interface IHelpProvider
|
public interface IHelpProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes help information for the application.
|
/// Writes help information for the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">The command model to write help for.</param>
|
/// <param name="model">The command model to write help for.</param>
|
||||||
/// <param name="command">The command for which to write help information (optional).</param>
|
/// <param name="command">The command for which to write help information (optional).</param>
|
||||||
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects representing the help information.</returns>
|
/// <returns>An enumerable collection of <see cref="IRenderable"/> objects representing the help information.</returns>
|
||||||
IEnumerable<IRenderable> Write(ICommandModel model, ICommandInfo? command);
|
IEnumerable<IRenderable> Write(ICommandModel model, ICommandInfo? command);
|
||||||
}
|
}
|
||||||
|
@ -24,22 +24,22 @@ public interface ICommandAppSettings
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the application version (use it to override auto-detected value).
|
/// Gets or sets the application version (use it to override auto-detected value).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string? ApplicationVersion { get; set; }
|
string? ApplicationVersion { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating how many examples from direct children to show in the help text.
|
/// Gets or sets a value indicating how many examples from direct children to show in the help text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int MaximumIndirectExamples { get; set; }
|
int MaximumIndirectExamples { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether any default values for command options are shown in the help text.
|
/// Gets or sets a value indicating whether any default values for command options are shown in the help text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool ShowOptionDefaultValues { get; set; }
|
bool ShowOptionDefaultValues { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether a trailing period of a command description is trimmed in the help text.
|
/// Gets or sets a value indicating whether a trailing period of a command description is trimmed in the help text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool TrimTrailingPeriod { get; set; }
|
bool TrimTrailingPeriod { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="IAnsiConsole"/>.
|
/// Gets or sets the <see cref="IAnsiConsole"/>.
|
||||||
@ -65,14 +65,14 @@ public interface ICommandAppSettings
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether or not parsing is strict.
|
/// Gets or sets a value indicating whether or not parsing is strict.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool StrictParsing { get; set; }
|
bool StrictParsing { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether or not flags found on the commnd line
|
/// Gets or sets a value indicating whether or not flags found on the commnd line
|
||||||
/// that would normally result in a <see cref="CommandParseException"/> being thrown
|
/// that would normally result in a <see cref="CommandParseException"/> being thrown
|
||||||
/// during parsing with the message "Flags cannot be assigned a value."
|
/// during parsing with the message "Flags cannot be assigned a value."
|
||||||
/// should instead be added to the remaining arguments collection.
|
/// should instead be added to the remaining arguments collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool ConvertFlagsToRemainingArguments { get; set; }
|
bool ConvertFlagsToRemainingArguments { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -4,19 +4,19 @@ namespace Spectre.Console.Cli;
|
|||||||
/// Represents a configurator.
|
/// Represents a configurator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IConfigurator
|
public interface IConfigurator
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the help provider for the application.
|
/// Sets the help provider for the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="helpProvider">The help provider to use.</param>
|
/// <param name="helpProvider">The help provider to use.</param>
|
||||||
public void SetHelpProvider(IHelpProvider helpProvider);
|
public void SetHelpProvider(IHelpProvider helpProvider);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the help provider for the application.
|
/// Sets the help provider for the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the help provider to instantiate at runtime and use.</typeparam>
|
/// <typeparam name="T">The type of the help provider to instantiate at runtime and use.</typeparam>
|
||||||
public void SetHelpProvider<T>()
|
public void SetHelpProvider<T>()
|
||||||
where T : IHelpProvider;
|
where T : IHelpProvider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the command app settings.
|
/// Gets the command app settings.
|
||||||
@ -66,5 +66,5 @@ public interface IConfigurator
|
|||||||
/// <param name="action">The command branch configurator.</param>
|
/// <param name="action">The command branch configurator.</param>
|
||||||
/// <returns>A branch configurator that can be used to configure the branch further.</returns>
|
/// <returns>A branch configurator that can be used to configure the branch further.</returns>
|
||||||
IBranchConfigurator AddBranch<TSettings>(string name, Action<IConfigurator<TSettings>> action)
|
IBranchConfigurator AddBranch<TSettings>(string name, Action<IConfigurator<TSettings>> action)
|
||||||
where TSettings : CommandSettings;
|
where TSettings : CommandSettings;
|
||||||
}
|
}
|
@ -1,146 +1,146 @@
|
|||||||
namespace Spectre.Console.Cli;
|
namespace Spectre.Console.Cli;
|
||||||
|
|
||||||
internal sealed class CommandExecutor
|
internal sealed class CommandExecutor
|
||||||
{
|
{
|
||||||
private readonly ITypeRegistrar _registrar;
|
private readonly ITypeRegistrar _registrar;
|
||||||
|
|
||||||
public CommandExecutor(ITypeRegistrar registrar)
|
public CommandExecutor(ITypeRegistrar registrar)
|
||||||
{
|
{
|
||||||
_registrar = registrar ?? throw new ArgumentNullException(nameof(registrar));
|
_registrar = registrar ?? throw new ArgumentNullException(nameof(registrar));
|
||||||
_registrar.Register(typeof(DefaultPairDeconstructor), typeof(DefaultPairDeconstructor));
|
_registrar.Register(typeof(DefaultPairDeconstructor), typeof(DefaultPairDeconstructor));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> Execute(IConfiguration configuration, IEnumerable<string> args)
|
public async Task<int> Execute(IConfiguration configuration, IEnumerable<string> args)
|
||||||
{
|
{
|
||||||
if (configuration == null)
|
if (configuration == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(configuration));
|
throw new ArgumentNullException(nameof(configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
args ??= new List<string>();
|
args ??= new List<string>();
|
||||||
|
|
||||||
_registrar.RegisterInstance(typeof(IConfiguration), configuration);
|
_registrar.RegisterInstance(typeof(IConfiguration), configuration);
|
||||||
_registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole());
|
_registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole());
|
||||||
|
|
||||||
// Create the command model.
|
// Create the command model.
|
||||||
var model = CommandModelBuilder.Build(configuration);
|
var model = CommandModelBuilder.Build(configuration);
|
||||||
_registrar.RegisterInstance(typeof(CommandModel), model);
|
_registrar.RegisterInstance(typeof(CommandModel), model);
|
||||||
_registrar.RegisterDependencies(model);
|
_registrar.RegisterDependencies(model);
|
||||||
|
|
||||||
// Asking for version? Kind of a hack, but it's alright.
|
// Asking for version? Kind of a hack, but it's alright.
|
||||||
// We should probably make this a bit better in the future.
|
// We should probably make this a bit better in the future.
|
||||||
if (args.Contains("-v") || args.Contains("--version"))
|
if (args.Contains("-v") || args.Contains("--version"))
|
||||||
{
|
{
|
||||||
var console = configuration.Settings.Console.GetConsole();
|
var console = configuration.Settings.Console.GetConsole();
|
||||||
console.WriteLine(ResolveApplicationVersion(configuration));
|
console.WriteLine(ResolveApplicationVersion(configuration));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse and map the model against the arguments.
|
// Parse and map the model against the arguments.
|
||||||
var parsedResult = ParseCommandLineArguments(model, configuration.Settings, args);
|
var parsedResult = ParseCommandLineArguments(model, configuration.Settings, args);
|
||||||
|
|
||||||
// Register the arguments with the container.
|
// Register the arguments with the container.
|
||||||
_registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult);
|
_registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult);
|
||||||
_registrar.RegisterInstance(typeof(IRemainingArguments), parsedResult.Remaining);
|
_registrar.RegisterInstance(typeof(IRemainingArguments), parsedResult.Remaining);
|
||||||
|
|
||||||
// Create the resolver.
|
// Create the resolver.
|
||||||
using (var resolver = new TypeResolverAdapter(_registrar.Build()))
|
using (var resolver = new TypeResolverAdapter(_registrar.Build()))
|
||||||
{
|
{
|
||||||
// Get the registered help provider, falling back to the default provider
|
// Get the registered help provider, falling back to the default provider
|
||||||
// if no custom implementations have been registered.
|
// if no custom implementations have been registered.
|
||||||
var helpProviders = resolver.Resolve(typeof(IEnumerable<IHelpProvider>)) as IEnumerable<IHelpProvider>;
|
var helpProviders = resolver.Resolve(typeof(IEnumerable<IHelpProvider>)) as IEnumerable<IHelpProvider>;
|
||||||
var helpProvider = helpProviders?.LastOrDefault() ?? new HelpProvider(configuration.Settings);
|
var helpProvider = helpProviders?.LastOrDefault() ?? new HelpProvider(configuration.Settings);
|
||||||
|
|
||||||
// Currently the root?
|
// Currently the root?
|
||||||
if (parsedResult?.Tree == null)
|
if (parsedResult?.Tree == null)
|
||||||
{
|
{
|
||||||
// Display help.
|
// Display help.
|
||||||
configuration.Settings.Console.SafeRender(helpProvider.Write(model, null));
|
configuration.Settings.Console.SafeRender(helpProvider.Write(model, null));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the command to execute.
|
// Get the command to execute.
|
||||||
var leaf = parsedResult.Tree.GetLeafCommand();
|
var leaf = parsedResult.Tree.GetLeafCommand();
|
||||||
if (leaf.Command.IsBranch || leaf.ShowHelp)
|
if (leaf.Command.IsBranch || leaf.ShowHelp)
|
||||||
{
|
{
|
||||||
// Branches can't be executed. Show help.
|
// Branches can't be executed. Show help.
|
||||||
configuration.Settings.Console.SafeRender(helpProvider.Write(model, leaf.Command));
|
configuration.Settings.Console.SafeRender(helpProvider.Write(model, leaf.Command));
|
||||||
return leaf.ShowHelp ? 0 : 1;
|
return leaf.ShowHelp ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this the default and is it called without arguments when there are required arguments?
|
// Is this the default and is it called without arguments when there are required arguments?
|
||||||
if (leaf.Command.IsDefaultCommand && args.Count() == 0 && leaf.Command.Parameters.Any(p => p.Required))
|
if (leaf.Command.IsDefaultCommand && args.Count() == 0 && leaf.Command.Parameters.Any(p => p.Required))
|
||||||
{
|
{
|
||||||
// Display help for default command.
|
// Display help for default command.
|
||||||
configuration.Settings.Console.SafeRender(helpProvider.Write(model, leaf.Command));
|
configuration.Settings.Console.SafeRender(helpProvider.Write(model, leaf.Command));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the content.
|
// Create the content.
|
||||||
var context = new CommandContext(parsedResult.Remaining, leaf.Command.Name, leaf.Command.Data);
|
var context = new CommandContext(parsedResult.Remaining, leaf.Command.Name, leaf.Command.Data);
|
||||||
|
|
||||||
// Execute the command tree.
|
// Execute the command tree.
|
||||||
return await Execute(leaf, parsedResult.Tree, context, resolver, configuration).ConfigureAwait(false);
|
return await Execute(leaf, parsedResult.Tree, context, resolver, configuration).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CS8603 // Possible null reference return.
|
#pragma warning disable CS8603 // Possible null reference return.
|
||||||
private CommandTreeParserResult ParseCommandLineArguments(CommandModel model, CommandAppSettings settings, IEnumerable<string> args)
|
private CommandTreeParserResult ParseCommandLineArguments(CommandModel model, CommandAppSettings settings, IEnumerable<string> args)
|
||||||
{
|
{
|
||||||
var parser = new CommandTreeParser(model, settings.CaseSensitivity, settings.ParsingMode, settings.ConvertFlagsToRemainingArguments);
|
var parser = new CommandTreeParser(model, settings.CaseSensitivity, settings.ParsingMode, settings.ConvertFlagsToRemainingArguments);
|
||||||
|
|
||||||
var parserContext = new CommandTreeParserContext(args, settings.ParsingMode);
|
var parserContext = new CommandTreeParserContext(args, settings.ParsingMode);
|
||||||
var tokenizerResult = CommandTreeTokenizer.Tokenize(args);
|
var tokenizerResult = CommandTreeTokenizer.Tokenize(args);
|
||||||
var parsedResult = parser.Parse(parserContext, tokenizerResult);
|
var parsedResult = parser.Parse(parserContext, tokenizerResult);
|
||||||
|
|
||||||
var lastParsedLeaf = parsedResult?.Tree?.GetLeafCommand();
|
var lastParsedLeaf = parsedResult?.Tree?.GetLeafCommand();
|
||||||
var lastParsedCommand = lastParsedLeaf?.Command;
|
var lastParsedCommand = lastParsedLeaf?.Command;
|
||||||
if (lastParsedLeaf != null && lastParsedCommand != null &&
|
if (lastParsedLeaf != null && lastParsedCommand != null &&
|
||||||
lastParsedCommand.IsBranch && !lastParsedLeaf.ShowHelp &&
|
lastParsedCommand.IsBranch && !lastParsedLeaf.ShowHelp &&
|
||||||
lastParsedCommand.DefaultCommand != null)
|
lastParsedCommand.DefaultCommand != null)
|
||||||
{
|
{
|
||||||
// Insert this branch's default command into the command line
|
// Insert this branch's default command into the command line
|
||||||
// arguments and try again to see if it will parse.
|
// arguments and try again to see if it will parse.
|
||||||
var argsWithDefaultCommand = new List<string>(args);
|
var argsWithDefaultCommand = new List<string>(args);
|
||||||
|
|
||||||
argsWithDefaultCommand.Insert(tokenizerResult.Tokens.Position, lastParsedCommand.DefaultCommand.Name);
|
argsWithDefaultCommand.Insert(tokenizerResult.Tokens.Position, lastParsedCommand.DefaultCommand.Name);
|
||||||
|
|
||||||
parserContext = new CommandTreeParserContext(argsWithDefaultCommand, settings.ParsingMode);
|
parserContext = new CommandTreeParserContext(argsWithDefaultCommand, settings.ParsingMode);
|
||||||
tokenizerResult = CommandTreeTokenizer.Tokenize(argsWithDefaultCommand);
|
tokenizerResult = CommandTreeTokenizer.Tokenize(argsWithDefaultCommand);
|
||||||
parsedResult = parser.Parse(parserContext, tokenizerResult);
|
parsedResult = parser.Parse(parserContext, tokenizerResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedResult;
|
return parsedResult;
|
||||||
}
|
}
|
||||||
#pragma warning restore CS8603 // Possible null reference return.
|
#pragma warning restore CS8603 // Possible null reference return.
|
||||||
|
|
||||||
private static string ResolveApplicationVersion(IConfiguration configuration)
|
private static string ResolveApplicationVersion(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
configuration.Settings.ApplicationVersion ?? // potential override
|
configuration.Settings.ApplicationVersion ?? // potential override
|
||||||
VersionHelper.GetVersion(Assembly.GetEntryAssembly());
|
VersionHelper.GetVersion(Assembly.GetEntryAssembly());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Task<int> Execute(
|
private static Task<int> Execute(
|
||||||
CommandTree leaf,
|
CommandTree leaf,
|
||||||
CommandTree tree,
|
CommandTree tree,
|
||||||
CommandContext context,
|
CommandContext context,
|
||||||
ITypeResolver resolver,
|
ITypeResolver resolver,
|
||||||
IConfiguration configuration)
|
IConfiguration configuration)
|
||||||
{
|
{
|
||||||
// Bind the command tree against the settings.
|
// Bind the command tree against the settings.
|
||||||
var settings = CommandBinder.Bind(tree, leaf.Command.SettingsType, resolver);
|
var settings = CommandBinder.Bind(tree, leaf.Command.SettingsType, resolver);
|
||||||
configuration.Settings.Interceptor?.Intercept(context, settings);
|
configuration.Settings.Interceptor?.Intercept(context, settings);
|
||||||
|
|
||||||
// Create and validate the command.
|
// Create and validate the command.
|
||||||
var command = leaf.CreateCommand(resolver);
|
var command = leaf.CreateCommand(resolver);
|
||||||
var validationResult = command.Validate(context, settings);
|
var validationResult = command.Validate(context, settings);
|
||||||
if (!validationResult.Successful)
|
if (!validationResult.Successful)
|
||||||
{
|
{
|
||||||
throw CommandRuntimeException.ValidationFailed(validationResult);
|
throw CommandRuntimeException.ValidationFailed(validationResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the command.
|
// Execute the command.
|
||||||
return command.Execute(context, settings);
|
return command.Execute(context, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace Spectre.Console.Cli;
|
namespace Spectre.Console.Cli;
|
||||||
|
|
||||||
internal sealed class BranchConfigurator : IBranchConfigurator
|
internal sealed class BranchConfigurator : IBranchConfigurator
|
||||||
{
|
{
|
||||||
|
@ -5,16 +5,16 @@ internal sealed class CommandAppSettings : ICommandAppSettings
|
|||||||
public CultureInfo? Culture { get; set; }
|
public CultureInfo? Culture { get; set; }
|
||||||
public string? ApplicationName { get; set; }
|
public string? ApplicationName { get; set; }
|
||||||
public string? ApplicationVersion { get; set; }
|
public string? ApplicationVersion { get; set; }
|
||||||
public int MaximumIndirectExamples { get; set; }
|
public int MaximumIndirectExamples { get; set; }
|
||||||
public bool ShowOptionDefaultValues { get; set; }
|
public bool ShowOptionDefaultValues { get; set; }
|
||||||
public IAnsiConsole? Console { get; set; }
|
public IAnsiConsole? Console { get; set; }
|
||||||
public ICommandInterceptor? Interceptor { get; set; }
|
public ICommandInterceptor? Interceptor { get; set; }
|
||||||
public ITypeRegistrarFrontend Registrar { get; set; }
|
public ITypeRegistrarFrontend Registrar { get; set; }
|
||||||
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; } = true;
|
||||||
public bool StrictParsing { get; set; }
|
public bool StrictParsing { get; set; }
|
||||||
public bool ConvertFlagsToRemainingArguments { get; set; } = false;
|
public bool ConvertFlagsToRemainingArguments { get; set; } = false;
|
||||||
|
|
||||||
public ParsingMode ParsingMode =>
|
public ParsingMode ParsingMode =>
|
||||||
@ -26,7 +26,7 @@ internal sealed class CommandAppSettings : ICommandAppSettings
|
|||||||
{
|
{
|
||||||
Registrar = new TypeRegistrar(registrar);
|
Registrar = new TypeRegistrar(registrar);
|
||||||
CaseSensitivity = CaseSensitivity.All;
|
CaseSensitivity = CaseSensitivity.All;
|
||||||
ShowOptionDefaultValues = true;
|
ShowOptionDefaultValues = true;
|
||||||
MaximumIndirectExamples = 5;
|
MaximumIndirectExamples = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,19 +19,19 @@ internal sealed class Configurator : IUnsafeConfigurator, IConfigurator, IConfig
|
|||||||
Settings = new CommandAppSettings(registrar);
|
Settings = new CommandAppSettings(registrar);
|
||||||
Examples = new List<string[]>();
|
Examples = new List<string[]>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetHelpProvider(IHelpProvider helpProvider)
|
public void SetHelpProvider(IHelpProvider helpProvider)
|
||||||
{
|
{
|
||||||
// Register the help provider
|
// Register the help provider
|
||||||
_registrar.RegisterInstance(typeof(IHelpProvider), helpProvider);
|
_registrar.RegisterInstance(typeof(IHelpProvider), helpProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetHelpProvider<T>()
|
public void SetHelpProvider<T>()
|
||||||
where T : IHelpProvider
|
where T : IHelpProvider
|
||||||
{
|
{
|
||||||
// Register the help provider
|
// Register the help provider
|
||||||
_registrar.Register(typeof(IHelpProvider), typeof(T));
|
_registrar.Register(typeof(IHelpProvider), typeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddExample(params string[] args)
|
public void AddExample(params string[] args)
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
namespace Spectre.Console.Cli;
|
namespace Spectre.Console.Cli;
|
||||||
|
|
||||||
internal sealed class CommandInfo : ICommandContainer, ICommandInfo
|
internal sealed class CommandInfo : ICommandContainer, ICommandInfo
|
||||||
{
|
{
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
@ -20,14 +20,14 @@ internal sealed class CommandInfo : ICommandContainer, ICommandInfo
|
|||||||
|
|
||||||
// only branches can have a default command
|
// only branches can have a default command
|
||||||
public CommandInfo? DefaultCommand => IsBranch ? Children.FirstOrDefault(c => c.IsDefaultCommand) : null;
|
public CommandInfo? DefaultCommand => IsBranch ? Children.FirstOrDefault(c => c.IsDefaultCommand) : null;
|
||||||
public bool IsHidden { get; }
|
public bool IsHidden { get; }
|
||||||
|
|
||||||
IReadOnlyList<ICommandInfo> Help.ICommandContainer.Commands => Children.Cast<ICommandInfo>().ToList();
|
IReadOnlyList<ICommandInfo> Help.ICommandContainer.Commands => Children.Cast<ICommandInfo>().ToList();
|
||||||
ICommandInfo? Help.ICommandContainer.DefaultCommand => DefaultCommand;
|
ICommandInfo? Help.ICommandContainer.DefaultCommand => DefaultCommand;
|
||||||
IReadOnlyList<ICommandParameter> ICommandInfo.Parameters => Parameters.Cast<ICommandParameter>().ToList();
|
IReadOnlyList<ICommandParameter> ICommandInfo.Parameters => Parameters.Cast<ICommandParameter>().ToList();
|
||||||
ICommandInfo? ICommandInfo.Parent => Parent;
|
ICommandInfo? ICommandInfo.Parent => Parent;
|
||||||
IReadOnlyList<string[]> Help.ICommandContainer.Examples => (IReadOnlyList<string[]>)Examples;
|
IReadOnlyList<string[]> Help.ICommandContainer.Examples => (IReadOnlyList<string[]>)Examples;
|
||||||
|
|
||||||
public CommandInfo(CommandInfo? parent, ConfiguredCommand prototype)
|
public CommandInfo(CommandInfo? parent, ConfiguredCommand prototype)
|
||||||
{
|
{
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
@ -54,5 +54,5 @@ internal sealed class CommandInfo : ICommandContainer, ICommandInfo
|
|||||||
Description = description.Description;
|
Description = description.Description;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,17 +1,17 @@
|
|||||||
namespace Spectre.Console.Cli;
|
namespace Spectre.Console.Cli;
|
||||||
|
|
||||||
internal sealed class CommandModel : ICommandContainer, ICommandModel
|
internal sealed class CommandModel : ICommandContainer, ICommandModel
|
||||||
{
|
{
|
||||||
public string? ApplicationName { get; }
|
public string? ApplicationName { get; }
|
||||||
public ParsingMode ParsingMode { get; }
|
public ParsingMode ParsingMode { get; }
|
||||||
public IList<CommandInfo> Commands { get; }
|
public IList<CommandInfo> Commands { get; }
|
||||||
public IList<string[]> Examples { get; }
|
public IList<string[]> Examples { get; }
|
||||||
|
|
||||||
public CommandInfo? DefaultCommand => Commands.FirstOrDefault(c => c.IsDefaultCommand);
|
public CommandInfo? DefaultCommand => Commands.FirstOrDefault(c => c.IsDefaultCommand);
|
||||||
|
|
||||||
string ICommandModel.ApplicationName => GetApplicationName(ApplicationName);
|
string ICommandModel.ApplicationName => GetApplicationName(ApplicationName);
|
||||||
IReadOnlyList<ICommandInfo> Help.ICommandContainer.Commands => Commands.Cast<ICommandInfo>().ToList();
|
IReadOnlyList<ICommandInfo> Help.ICommandContainer.Commands => Commands.Cast<ICommandInfo>().ToList();
|
||||||
ICommandInfo? Help.ICommandContainer.DefaultCommand => DefaultCommand;
|
ICommandInfo? Help.ICommandContainer.DefaultCommand => DefaultCommand;
|
||||||
IReadOnlyList<string[]> Help.ICommandContainer.Examples => (IReadOnlyList<string[]>)Examples;
|
IReadOnlyList<string[]> Help.ICommandContainer.Examples => (IReadOnlyList<string[]>)Examples;
|
||||||
|
|
||||||
public CommandModel(
|
public CommandModel(
|
||||||
@ -22,18 +22,18 @@ internal sealed class CommandModel : ICommandContainer, ICommandModel
|
|||||||
ApplicationName = settings.ApplicationName;
|
ApplicationName = settings.ApplicationName;
|
||||||
ParsingMode = settings.ParsingMode;
|
ParsingMode = settings.ParsingMode;
|
||||||
Commands = new List<CommandInfo>(commands ?? Array.Empty<CommandInfo>());
|
Commands = new List<CommandInfo>(commands ?? Array.Empty<CommandInfo>());
|
||||||
Examples = new List<string[]>(examples ?? Array.Empty<string[]>());
|
Examples = new List<string[]>(examples ?? Array.Empty<string[]>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the application.
|
/// Gets the name of the application.
|
||||||
/// If the provided <paramref name="applicationName"/> is not null or empty,
|
/// If the provided <paramref name="applicationName"/> is not null or empty,
|
||||||
/// it is returned. Otherwise the name of the current application
|
/// it is returned. Otherwise the name of the current application
|
||||||
/// is determined based on the executable file's name.
|
/// is determined based on the executable file's name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="applicationName">The optional name of the application.</param>
|
/// <param name="applicationName">The optional name of the application.</param>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// The name of the application, or a default value of "?" if no valid application name can be determined.
|
/// The name of the application, or a default value of "?" if no valid application name can be determined.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
private static string GetApplicationName(string? applicationName)
|
private static string GetApplicationName(string? applicationName)
|
||||||
{
|
{
|
||||||
@ -45,7 +45,7 @@ internal sealed class CommandModel : ICommandContainer, ICommandModel
|
|||||||
|
|
||||||
private static string? GetApplicationFile()
|
private static string? GetApplicationFile()
|
||||||
{
|
{
|
||||||
var location = Assembly.GetEntryAssembly()?.Location;
|
var location = Assembly.GetEntryAssembly()?.Location;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(location))
|
if (string.IsNullOrWhiteSpace(location))
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
namespace Spectre.Console.Cli;
|
namespace Spectre.Console.Cli;
|
||||||
|
|
||||||
internal static class CommandModelBuilder
|
internal static class CommandModelBuilder
|
||||||
{
|
{
|
||||||
// Consider removing this in favor for value tuples at some point.
|
// Consider removing this in favor for value tuples at some point.
|
||||||
@ -31,8 +31,8 @@ internal static class CommandModelBuilder
|
|||||||
configuration.DefaultCommand.Examples.AddRange(configuration.Examples);
|
configuration.DefaultCommand.Examples.AddRange(configuration.Examples);
|
||||||
|
|
||||||
// Build the default command.
|
// Build the default command.
|
||||||
var defaultCommand = Build(null, configuration.DefaultCommand);
|
var defaultCommand = Build(null, configuration.DefaultCommand);
|
||||||
|
|
||||||
result.Add(defaultCommand);
|
result.Add(defaultCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ internal static class CommandModelBuilder
|
|||||||
foreach (var childCommand in command.Children)
|
foreach (var childCommand in command.Children)
|
||||||
{
|
{
|
||||||
var child = Build(info, childCommand);
|
var child = Build(info, childCommand);
|
||||||
info.Children.Add(child);
|
info.Children.Add(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize argument positions.
|
// Normalize argument positions.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
namespace Spectre.Console.Cli;
|
namespace Spectre.Console.Cli;
|
||||||
|
|
||||||
internal abstract class CommandParameter : ICommandParameterInfo, ICommandParameter
|
internal abstract class CommandParameter : ICommandParameterInfo, ICommandParameter
|
||||||
{
|
{
|
||||||
public Guid Id { get; }
|
public Guid Id { get; }
|
||||||
@ -17,10 +17,10 @@ internal abstract class CommandParameter : ICommandParameterInfo, ICommandParame
|
|||||||
public string PropertyName => Property.Name;
|
public string PropertyName => Property.Name;
|
||||||
|
|
||||||
public virtual bool WantRawValue => ParameterType.IsPairDeconstructable()
|
public virtual bool WantRawValue => ParameterType.IsPairDeconstructable()
|
||||||
&& (PairDeconstructor != null || Converter == null);
|
&& (PairDeconstructor != null || Converter == null);
|
||||||
|
|
||||||
public bool IsFlag => ParameterKind == ParameterKind.Flag;
|
public bool IsFlag => ParameterKind == ParameterKind.Flag;
|
||||||
|
|
||||||
protected CommandParameter(
|
protected CommandParameter(
|
||||||
Type parameterType, ParameterKind parameterKind, PropertyInfo property,
|
Type parameterType, ParameterKind parameterKind, PropertyInfo property,
|
||||||
string? description, TypeConverterAttribute? converter,
|
string? description, TypeConverterAttribute? converter,
|
||||||
|
@ -8,13 +8,13 @@ internal interface ICommandContainer
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all commands in the container.
|
/// Gets all commands in the container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IList<CommandInfo> Commands { get; }
|
IList<CommandInfo> Commands { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the default command for the container.
|
/// Gets the default command for the container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Returns null if a default command has not been set.
|
/// Returns null if a default command has not been set.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
CommandInfo? DefaultCommand { get; }
|
CommandInfo? DefaultCommand { get; }
|
||||||
}
|
}
|
@ -1,12 +1,12 @@
|
|||||||
using static Spectre.Console.Cli.CommandTreeTokenizer;
|
using static Spectre.Console.Cli.CommandTreeTokenizer;
|
||||||
|
|
||||||
namespace Spectre.Console.Cli;
|
namespace Spectre.Console.Cli;
|
||||||
|
|
||||||
internal class CommandTreeParser
|
internal class CommandTreeParser
|
||||||
{
|
{
|
||||||
private readonly CommandModel _configuration;
|
private readonly CommandModel _configuration;
|
||||||
private readonly ParsingMode _parsingMode;
|
private readonly ParsingMode _parsingMode;
|
||||||
private readonly CommandOptionAttribute _help;
|
private readonly CommandOptionAttribute _help;
|
||||||
private readonly bool _convertFlagsToRemainingArguments;
|
private readonly bool _convertFlagsToRemainingArguments;
|
||||||
|
|
||||||
public CaseSensitivity CaseSensitivity { get; }
|
public CaseSensitivity CaseSensitivity { get; }
|
||||||
@ -21,20 +21,20 @@ internal class CommandTreeParser
|
|||||||
{
|
{
|
||||||
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
||||||
_parsingMode = parsingMode ?? _configuration.ParsingMode;
|
_parsingMode = parsingMode ?? _configuration.ParsingMode;
|
||||||
_help = new CommandOptionAttribute("-h|--help");
|
_help = new CommandOptionAttribute("-h|--help");
|
||||||
_convertFlagsToRemainingArguments = convertFlagsToRemainingArguments ?? false;
|
_convertFlagsToRemainingArguments = convertFlagsToRemainingArguments ?? false;
|
||||||
|
|
||||||
CaseSensitivity = caseSensitivity;
|
CaseSensitivity = caseSensitivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandTreeParserResult Parse(IEnumerable<string> args)
|
public CommandTreeParserResult Parse(IEnumerable<string> args)
|
||||||
{
|
{
|
||||||
var parserContext = new CommandTreeParserContext(args, _parsingMode);
|
var parserContext = new CommandTreeParserContext(args, _parsingMode);
|
||||||
var tokenizerResult = CommandTreeTokenizer.Tokenize(args);
|
var tokenizerResult = CommandTreeTokenizer.Tokenize(args);
|
||||||
|
|
||||||
return Parse(parserContext, tokenizerResult);
|
return Parse(parserContext, tokenizerResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandTreeParserResult Parse(CommandTreeParserContext context, CommandTreeTokenizerResult tokenizerResult)
|
public CommandTreeParserResult Parse(CommandTreeParserContext context, CommandTreeTokenizerResult tokenizerResult)
|
||||||
{
|
{
|
||||||
var tokens = tokenizerResult.Tokens;
|
var tokens = tokenizerResult.Tokens;
|
||||||
@ -258,8 +258,8 @@ internal class CommandTreeParser
|
|||||||
// Find the option.
|
// Find the option.
|
||||||
var option = node.FindOption(token.Value, isLongOption, CaseSensitivity);
|
var option = node.FindOption(token.Value, isLongOption, CaseSensitivity);
|
||||||
if (option != null)
|
if (option != null)
|
||||||
{
|
{
|
||||||
ParseOptionValue(context, stream, token, node, option);
|
ParseOptionValue(context, stream, token, node, option);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,10 +291,10 @@ internal class CommandTreeParser
|
|||||||
CommandTreeParserContext context,
|
CommandTreeParserContext context,
|
||||||
CommandTreeTokenStream stream,
|
CommandTreeTokenStream stream,
|
||||||
CommandTreeToken token,
|
CommandTreeToken token,
|
||||||
CommandTree current,
|
CommandTree current,
|
||||||
CommandParameter? parameter = null)
|
CommandParameter? parameter = null)
|
||||||
{
|
{
|
||||||
bool addToMappedCommandParameters = parameter != null;
|
bool addToMappedCommandParameters = parameter != null;
|
||||||
|
|
||||||
var value = default(string);
|
var value = default(string);
|
||||||
|
|
||||||
@ -312,49 +312,49 @@ internal class CommandTreeParser
|
|||||||
{
|
{
|
||||||
// Is this a command?
|
// Is this a command?
|
||||||
if (current.Command.FindCommand(valueToken.Value, CaseSensitivity) == null)
|
if (current.Command.FindCommand(valueToken.Value, CaseSensitivity) == null)
|
||||||
{
|
{
|
||||||
if (parameter != null)
|
if (parameter != null)
|
||||||
{
|
{
|
||||||
if (parameter.ParameterKind == ParameterKind.Flag)
|
if (parameter.ParameterKind == ParameterKind.Flag)
|
||||||
{
|
{
|
||||||
if (!CliConstants.AcceptedBooleanValues.Contains(valueToken.Value, StringComparer.OrdinalIgnoreCase))
|
if (!CliConstants.AcceptedBooleanValues.Contains(valueToken.Value, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (!valueToken.HadSeparator)
|
if (!valueToken.HadSeparator)
|
||||||
{
|
{
|
||||||
// Do nothing
|
// Do nothing
|
||||||
// - assume valueToken is unrelated to the flag parameter (ie. we've parsed it unnecessarily)
|
// - assume valueToken is unrelated to the flag parameter (ie. we've parsed it unnecessarily)
|
||||||
// - rely on the "No value?" code below to set the flag to its default value
|
// - rely on the "No value?" code below to set the flag to its default value
|
||||||
// - valueToken will be handled on the next pass of the parser
|
// - valueToken will be handled on the next pass of the parser
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Flags cannot be assigned a value.
|
// Flags cannot be assigned a value.
|
||||||
if (_convertFlagsToRemainingArguments)
|
if (_convertFlagsToRemainingArguments)
|
||||||
{
|
{
|
||||||
value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
|
value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
|
||||||
|
|
||||||
context.AddRemainingArgument(token.Value, value);
|
context.AddRemainingArgument(token.Value, value);
|
||||||
|
|
||||||
// Prevent the option and it's non-boolean value from being added to
|
// Prevent the option and it's non-boolean value from being added to
|
||||||
// mapped parameters (otherwise an exception will be thrown later
|
// mapped parameters (otherwise an exception will be thrown later
|
||||||
// when binding the value to the flag in the comand settings)
|
// when binding the value to the flag in the comand settings)
|
||||||
addToMappedCommandParameters = false;
|
addToMappedCommandParameters = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw CommandParseException.CannotAssignValueToFlag(context.Arguments, token);
|
throw CommandParseException.CannotAssignValueToFlag(context.Arguments, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
|
value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
|
value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -370,13 +370,13 @@ internal class CommandTreeParser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
context.AddRemainingArgument(token.Value, parseValue ? valueToken.Value : null);
|
context.AddRemainingArgument(token.Value, parseValue ? valueToken.Value : null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (parameter == null && // Only add tokens which have not been matched to a command parameter
|
if (parameter == null && // Only add tokens which have not been matched to a command parameter
|
||||||
(context.State == State.Remaining || context.ParsingMode == ParsingMode.Relaxed))
|
(context.State == State.Remaining || context.ParsingMode == ParsingMode.Relaxed))
|
||||||
{
|
{
|
||||||
context.AddRemainingArgument(token.Value, null);
|
context.AddRemainingArgument(token.Value, null);
|
||||||
@ -399,10 +399,10 @@ internal class CommandTreeParser
|
|||||||
if (parameter.IsFlagValue())
|
if (parameter.IsFlagValue())
|
||||||
{
|
{
|
||||||
value = null;
|
value = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw CommandParseException.OptionHasNoValue(context.Arguments, token, option);
|
throw CommandParseException.OptionHasNoValue(context.Arguments, token, option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -415,9 +415,9 @@ internal class CommandTreeParser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameter != null && addToMappedCommandParameters)
|
if (parameter != null && addToMappedCommandParameters)
|
||||||
{
|
{
|
||||||
current.Mapped.Add(new MappedCommandParameter(parameter, value));
|
current.Mapped.Add(new MappedCommandParameter(parameter, value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,15 +26,15 @@ internal class CommandTreeParserContext
|
|||||||
public void IncreaseArgumentPosition()
|
public void IncreaseArgumentPosition()
|
||||||
{
|
{
|
||||||
CurrentArgumentPosition++;
|
CurrentArgumentPosition++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRemainingArgument(string key, string? value)
|
public void AddRemainingArgument(string key, string? value)
|
||||||
{
|
{
|
||||||
if (!_remaining.ContainsKey(key))
|
if (!_remaining.ContainsKey(key))
|
||||||
{
|
{
|
||||||
_remaining.Add(key, new List<string?>());
|
_remaining.Add(key, new List<string?>());
|
||||||
}
|
}
|
||||||
|
|
||||||
_remaining[key].Add(value);
|
_remaining[key].Add(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ internal sealed class CommandTreeToken
|
|||||||
public int Position { get; }
|
public int Position { get; }
|
||||||
public string Value { get; }
|
public string Value { get; }
|
||||||
public string Representation { get; }
|
public string Representation { get; }
|
||||||
public bool IsGrouped { get; set; }
|
public bool IsGrouped { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether a separater was encountered immediately before the <see cref="CommandTreeToken.Value"/>.
|
/// Gets or sets a value indicating whether a separater was encountered immediately before the <see cref="CommandTreeToken.Value"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HadSeparator { get; set; }
|
public bool HadSeparator { get; set; }
|
||||||
|
|
||||||
public enum Kind
|
public enum Kind
|
||||||
|
@ -5,7 +5,7 @@ internal sealed class CommandTreeTokenStream : IReadOnlyList<CommandTreeToken>
|
|||||||
private readonly List<CommandTreeToken> _tokens;
|
private readonly List<CommandTreeToken> _tokens;
|
||||||
private int _position;
|
private int _position;
|
||||||
|
|
||||||
public int Count => _tokens.Count;
|
public int Count => _tokens.Count;
|
||||||
public int Position => _position;
|
public int Position => _position;
|
||||||
|
|
||||||
public CommandTreeToken this[int index] => _tokens[index];
|
public CommandTreeToken this[int index] => _tokens[index];
|
||||||
|
@ -29,13 +29,13 @@ internal static class CommandTreeTokenizer
|
|||||||
var context = new CommandTreeTokenizerContext();
|
var context = new CommandTreeTokenizerContext();
|
||||||
|
|
||||||
foreach (var arg in args)
|
foreach (var arg in args)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(arg))
|
if (string.IsNullOrEmpty(arg))
|
||||||
{
|
{
|
||||||
// Null strings in the args array are still represented as tokens
|
// Null strings in the args array are still represented as tokens
|
||||||
tokens.Add(new CommandTreeToken(CommandTreeToken.Kind.String, position, string.Empty, string.Empty));
|
tokens.Add(new CommandTreeToken(CommandTreeToken.Kind.String, position, string.Empty, string.Empty));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var start = position;
|
var start = position;
|
||||||
var reader = new TextBuffer(previousReader, arg);
|
var reader = new TextBuffer(previousReader, arg);
|
||||||
@ -55,30 +55,30 @@ internal static class CommandTreeTokenizer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static int ParseToken(CommandTreeTokenizerContext context, TextBuffer reader, int position, int start, List<CommandTreeToken> tokens)
|
private static int ParseToken(CommandTreeTokenizerContext context, TextBuffer reader, int position, int start, List<CommandTreeToken> tokens)
|
||||||
{
|
{
|
||||||
if (!reader.ReachedEnd && reader.Peek() == '-')
|
if (!reader.ReachedEnd && reader.Peek() == '-')
|
||||||
{
|
{
|
||||||
// Option
|
// Option
|
||||||
tokens.AddRange(ScanOptions(context, reader));
|
tokens.AddRange(ScanOptions(context, reader));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Command or argument
|
// Command or argument
|
||||||
while (reader.Peek() != -1)
|
while (reader.Peek() != -1)
|
||||||
{
|
{
|
||||||
if (reader.ReachedEnd)
|
if (reader.ReachedEnd)
|
||||||
{
|
{
|
||||||
position += reader.Position - start;
|
position += reader.Position - start;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens.Add(ScanString(context, reader));
|
tokens.Add(ScanString(context, reader));
|
||||||
|
|
||||||
// Flush remaining tokens
|
// Flush remaining tokens
|
||||||
context.FlushRemaining();
|
context.FlushRemaining();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ internal static class CommandTreeTokenizer
|
|||||||
builder.Append(current);
|
builder.Append(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
var value = builder.ToString();
|
var value = builder.ToString();
|
||||||
return new CommandTreeToken(CommandTreeToken.Kind.String, position, value, value);
|
return new CommandTreeToken(CommandTreeToken.Kind.String, position, value, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,8 +149,8 @@ internal static class CommandTreeTokenizer
|
|||||||
var token = new CommandTreeToken(CommandTreeToken.Kind.String, reader.Position, "=", "=");
|
var token = new CommandTreeToken(CommandTreeToken.Kind.String, reader.Position, "=", "=");
|
||||||
throw CommandParseException.OptionValueWasExpected(reader.Original, token);
|
throw CommandParseException.OptionValueWasExpected(reader.Original, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var tokenValue = ScanString(context, reader);
|
var tokenValue = ScanString(context, reader);
|
||||||
tokenValue.HadSeparator = true;
|
tokenValue.HadSeparator = true;
|
||||||
result.Add(tokenValue);
|
result.Add(tokenValue);
|
||||||
}
|
}
|
||||||
@ -193,7 +193,7 @@ internal static class CommandTreeTokenizer
|
|||||||
// be tokenized as strings. This block handles parsing those cases, but we only allow this
|
// be tokenized as strings. This block handles parsing those cases, but we only allow this
|
||||||
// when the digit is the first character in the token (i.e. "-a1" is always an error), hence the
|
// when the digit is the first character in the token (i.e. "-a1" is always an error), hence the
|
||||||
// result.Count == 0 check above.
|
// result.Count == 0 check above.
|
||||||
string value = string.Empty;
|
string value = string.Empty;
|
||||||
|
|
||||||
while (!reader.ReachedEnd)
|
while (!reader.ReachedEnd)
|
||||||
{
|
{
|
||||||
@ -212,12 +212,12 @@ internal static class CommandTreeTokenizer
|
|||||||
result.Add(new CommandTreeToken(CommandTreeToken.Kind.String, position, value, value));
|
result.Add(new CommandTreeToken(CommandTreeToken.Kind.String, position, value, value));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Create a token representing the short option.
|
// Create a token representing the short option.
|
||||||
var representation = current.ToString(CultureInfo.InvariantCulture);
|
var representation = current.ToString(CultureInfo.InvariantCulture);
|
||||||
var tokenPosition = position + 1 + result.Count;
|
var tokenPosition = position + 1 + result.Count;
|
||||||
var token = new CommandTreeToken(CommandTreeToken.Kind.ShortOption, tokenPosition, representation, representation);
|
var token = new CommandTreeToken(CommandTreeToken.Kind.ShortOption, tokenPosition, representation, representation);
|
||||||
|
|
||||||
throw CommandParseException.InvalidShortOptionName(reader.Original, token);
|
throw CommandParseException.InvalidShortOptionName(reader.Original, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ global using System.Linq;
|
|||||||
global using System.Reflection;
|
global using System.Reflection;
|
||||||
global using System.Text;
|
global using System.Text;
|
||||||
global using System.Threading.Tasks;
|
global using System.Threading.Tasks;
|
||||||
global using System.Xml;
|
global using System.Xml;
|
||||||
global using Spectre.Console.Cli.Help;
|
global using Spectre.Console.Cli.Help;
|
||||||
global using Spectre.Console.Cli.Unsafe;
|
global using Spectre.Console.Cli.Unsafe;
|
||||||
global using Spectre.Console.Rendering;
|
global using Spectre.Console.Rendering;
|
@ -1,153 +1,153 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.42000
|
// Runtime Version:4.0.30319.42000
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace Spectre.Console.Cli.Resources {
|
namespace Spectre.Console.Cli.Resources {
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
// class via a tool like ResGen or Visual Studio.
|
// class via a tool like ResGen or Visual Studio.
|
||||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
// with the /str option, or rebuild your VS project.
|
// with the /str option, or rebuild your VS project.
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
internal class HelpProvider {
|
internal class HelpProvider {
|
||||||
|
|
||||||
private static global::System.Resources.ResourceManager resourceMan;
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
internal HelpProvider() {
|
internal HelpProvider() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the cached ResourceManager instance used by this class.
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
get {
|
get {
|
||||||
if (object.ReferenceEquals(resourceMan, null)) {
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Spectre.Console.Cli.Resources.HelpProvider", typeof(HelpProvider).Assembly);
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Spectre.Console.Cli.Resources.HelpProvider", typeof(HelpProvider).Assembly);
|
||||||
resourceMan = temp;
|
resourceMan = temp;
|
||||||
}
|
}
|
||||||
return resourceMan;
|
return resourceMan;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Overrides the current thread's CurrentUICulture property for all
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
/// resource lookups using this strongly typed resource class.
|
/// resource lookups using this strongly typed resource class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
internal static global::System.Globalization.CultureInfo Culture {
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
get {
|
get {
|
||||||
return resourceCulture;
|
return resourceCulture;
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
resourceCulture = value;
|
resourceCulture = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to ARGUMENTS.
|
/// Looks up a localized string similar to ARGUMENTS.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string Arguments {
|
internal static string Arguments {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Arguments", resourceCulture);
|
return ResourceManager.GetString("Arguments", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to COMMAND.
|
/// Looks up a localized string similar to COMMAND.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string Command {
|
internal static string Command {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Command", resourceCulture);
|
return ResourceManager.GetString("Command", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to COMMANDS.
|
/// Looks up a localized string similar to COMMANDS.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string Commands {
|
internal static string Commands {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Commands", resourceCulture);
|
return ResourceManager.GetString("Commands", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to DEFAULT.
|
/// Looks up a localized string similar to DEFAULT.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string Default {
|
internal static string Default {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Default", resourceCulture);
|
return ResourceManager.GetString("Default", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to DESCRIPTION.
|
/// Looks up a localized string similar to DESCRIPTION.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string Description {
|
internal static string Description {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Description", resourceCulture);
|
return ResourceManager.GetString("Description", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to EXAMPLES.
|
/// Looks up a localized string similar to EXAMPLES.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string Examples {
|
internal static string Examples {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Examples", resourceCulture);
|
return ResourceManager.GetString("Examples", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to OPTIONS.
|
/// Looks up a localized string similar to OPTIONS.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string Options {
|
internal static string Options {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Options", resourceCulture);
|
return ResourceManager.GetString("Options", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Prints help information.
|
/// Looks up a localized string similar to Prints help information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string PrintHelpDescription {
|
internal static string PrintHelpDescription {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("PrintHelpDescription", resourceCulture);
|
return ResourceManager.GetString("PrintHelpDescription", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Prints version information.
|
/// Looks up a localized string similar to Prints version information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string PrintVersionDescription {
|
internal static string PrintVersionDescription {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("PrintVersionDescription", resourceCulture);
|
return ResourceManager.GetString("PrintVersionDescription", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to USAGE.
|
/// Looks up a localized string similar to USAGE.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string Usage {
|
internal static string Usage {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Usage", resourceCulture);
|
return ResourceManager.GetString("Usage", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,8 +141,8 @@ public sealed class CommandAppTester
|
|||||||
.Trim();
|
.Trim();
|
||||||
|
|
||||||
return new CommandAppResult(result, output, context, settings);
|
return new CommandAppResult(result, output, context, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs the command application asynchronously.
|
/// Runs the command application asynchronously.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -60,7 +60,7 @@ public static partial class AnsiConsoleExtensions
|
|||||||
|
|
||||||
if (!char.IsControl(key.KeyChar))
|
if (!char.IsControl(key.KeyChar))
|
||||||
{
|
{
|
||||||
text += key.KeyChar.ToString();
|
text += key.KeyChar.ToString();
|
||||||
var output = key.KeyChar.ToString();
|
var output = key.KeyChar.ToString();
|
||||||
console.Write(secret ? output.Mask(mask) : output, style);
|
console.Write(secret ? output.Mask(mask) : output, style);
|
||||||
}
|
}
|
||||||
|
@ -185,28 +185,28 @@ public static class StringExtensions
|
|||||||
#else
|
#else
|
||||||
return text.Contains(value, StringComparison.Ordinal);
|
return text.Contains(value, StringComparison.Ordinal);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Masks" every character in a string.
|
/// "Masks" every character in a string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">String value to mask.</param>
|
/// <param name="value">String value to mask.</param>
|
||||||
/// <param name="mask">Character to use for masking.</param>
|
/// <param name="mask">Character to use for masking.</param>
|
||||||
/// <returns>Masked string.</returns>
|
/// <returns>Masked string.</returns>
|
||||||
public static string Mask(this string value, char? mask)
|
public static string Mask(this string value, char? mask)
|
||||||
{
|
{
|
||||||
var output = string.Empty;
|
var output = string.Empty;
|
||||||
|
|
||||||
if (mask is null)
|
if (mask is null)
|
||||||
{
|
{
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var c in value)
|
foreach (var c in value)
|
||||||
{
|
{
|
||||||
output += mask;
|
output += mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace Spectre.Console;
|
namespace Spectre.Console;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents horizontal alignment.
|
/// Represents horizontal alignment.
|
||||||
|
@ -286,25 +286,25 @@ public static class TextPromptExtensions
|
|||||||
|
|
||||||
obj.IsSecret = true;
|
obj.IsSecret = true;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Replaces prompt user input with mask in the console.
|
/// Replaces prompt user input with mask in the console.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The prompt type.</typeparam>
|
/// <typeparam name="T">The prompt type.</typeparam>
|
||||||
/// <param name="obj">The prompt.</param>
|
/// <param name="obj">The prompt.</param>
|
||||||
/// <param name="mask">The masking character to use for the secret.</param>
|
/// <param name="mask">The masking character to use for the secret.</param>
|
||||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
public static TextPrompt<T> Secret<T>(this TextPrompt<T> obj, char? mask)
|
public static TextPrompt<T> Secret<T>(this TextPrompt<T> obj, char? mask)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.IsSecret = true;
|
obj.IsSecret = true;
|
||||||
obj.Mask = mask;
|
obj.Mask = mask;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Spectre.Console;
|
namespace Spectre.Console;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents vertical alignment.
|
/// Represents vertical alignment.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Spectre.Console;
|
namespace Spectre.Console;
|
||||||
|
|
||||||
internal static class TypeNameHelper
|
internal static class TypeNameHelper
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Spectre.Console;
|
namespace Spectre.Console;
|
||||||
|
|
||||||
[DebuggerDisplay("{Region,nq}")]
|
[DebuggerDisplay("{Region,nq}")]
|
||||||
internal sealed class LayoutRender
|
internal sealed class LayoutRender
|
||||||
|
@ -5,7 +5,7 @@ public static class SpectreAnalyzerVerifier<TAnalyzer>
|
|||||||
{
|
{
|
||||||
public static Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
|
public static Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
|
||||||
=> VerifyCodeFixAsync(source, OutputKind.DynamicallyLinkedLibrary, new[] { expected }, fixedSource);
|
=> VerifyCodeFixAsync(source, OutputKind.DynamicallyLinkedLibrary, new[] { expected }, fixedSource);
|
||||||
|
|
||||||
public static Task VerifyCodeFixAsync(string source, OutputKind outputKind, DiagnosticResult expected, string fixedSource)
|
public static Task VerifyCodeFixAsync(string source, OutputKind outputKind, DiagnosticResult expected, string fixedSource)
|
||||||
=> VerifyCodeFixAsync(source, outputKind, new[] { expected }, fixedSource);
|
=> VerifyCodeFixAsync(source, outputKind, new[] { expected }, fixedSource);
|
||||||
|
|
||||||
@ -13,10 +13,10 @@ public static class SpectreAnalyzerVerifier<TAnalyzer>
|
|||||||
{
|
{
|
||||||
var test = new Test
|
var test = new Test
|
||||||
{
|
{
|
||||||
TestCode = source,
|
TestCode = source,
|
||||||
TestState =
|
TestState =
|
||||||
{
|
{
|
||||||
OutputKind = outputKind,
|
OutputKind = outputKind,
|
||||||
},
|
},
|
||||||
FixedCode = fixedSource,
|
FixedCode = fixedSource,
|
||||||
};
|
};
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
namespace Spectre.Console.Tests.Data;
|
namespace Spectre.Console.Tests.Data;
|
||||||
|
|
||||||
public sealed class AsynchronousCommand : AsyncCommand<AsynchronousCommandSettings>
|
public sealed class AsynchronousCommand : AsyncCommand<AsynchronousCommandSettings>
|
||||||
{
|
{
|
||||||
private readonly IAnsiConsole _console;
|
private readonly IAnsiConsole _console;
|
||||||
|
|
||||||
public AsynchronousCommand(IAnsiConsole console)
|
public AsynchronousCommand(IAnsiConsole console)
|
||||||
{
|
{
|
||||||
_console = console;
|
_console = console;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async override Task<int> ExecuteAsync(CommandContext context, AsynchronousCommandSettings settings)
|
public async override Task<int> ExecuteAsync(CommandContext context, AsynchronousCommandSettings settings)
|
||||||
{
|
{
|
||||||
// Simulate a long running asynchronous task
|
// Simulate a long running asynchronous task
|
||||||
await Task.Delay(200);
|
await Task.Delay(200);
|
||||||
|
|
||||||
if (settings.ThrowException)
|
if (settings.ThrowException)
|
||||||
{
|
{
|
||||||
throw new Exception($"Throwing exception asynchronously");
|
throw new Exception($"Throwing exception asynchronously");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_console.WriteLine($"Finished executing asynchronously");
|
_console.WriteLine($"Finished executing asynchronously");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
|
|
||||||
public class GreeterCommand : Command<OptionalArgumentWithDefaultValueSettings>
|
public class GreeterCommand : Command<OptionalArgumentWithDefaultValueSettings>
|
||||||
{
|
{
|
||||||
private readonly IAnsiConsole _console;
|
private readonly IAnsiConsole _console;
|
||||||
|
|
||||||
public GreeterCommand(IAnsiConsole console)
|
public GreeterCommand(IAnsiConsole console)
|
||||||
{
|
{
|
||||||
_console = console;
|
_console = console;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int Execute(CommandContext context, OptionalArgumentWithDefaultValueSettings settings)
|
public override int Execute(CommandContext context, OptionalArgumentWithDefaultValueSettings settings)
|
||||||
{
|
{
|
||||||
_console.WriteLine(settings.Greeting);
|
_console.WriteLine(settings.Greeting);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,34 +1,34 @@
|
|||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
namespace Spectre.Console.Cli.Tests.Data.Help;
|
namespace Spectre.Console.Cli.Tests.Data.Help;
|
||||||
|
|
||||||
internal class CustomHelpProvider : HelpProvider
|
internal class CustomHelpProvider : HelpProvider
|
||||||
{
|
{
|
||||||
private readonly string version;
|
private readonly string version;
|
||||||
|
|
||||||
public CustomHelpProvider(ICommandAppSettings settings, string version)
|
public CustomHelpProvider(ICommandAppSettings settings, string version)
|
||||||
: base(settings)
|
: base(settings)
|
||||||
{
|
{
|
||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<IRenderable> GetHeader(ICommandModel model, ICommandInfo command)
|
public override IEnumerable<IRenderable> GetHeader(ICommandModel model, ICommandInfo command)
|
||||||
{
|
{
|
||||||
return new IRenderable[]
|
return new IRenderable[]
|
||||||
{
|
{
|
||||||
new Text("--------------------------------------"), Text.NewLine,
|
new Text("--------------------------------------"), Text.NewLine,
|
||||||
new Text("--- CUSTOM HELP PROVIDER ---"), Text.NewLine,
|
new Text("--- CUSTOM HELP PROVIDER ---"), Text.NewLine,
|
||||||
new Text("--------------------------------------"), Text.NewLine,
|
new Text("--------------------------------------"), Text.NewLine,
|
||||||
Text.NewLine,
|
Text.NewLine,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<IRenderable> GetFooter(ICommandModel model, ICommandInfo command)
|
public override IEnumerable<IRenderable> GetFooter(ICommandModel model, ICommandInfo command)
|
||||||
{
|
{
|
||||||
return new IRenderable[]
|
return new IRenderable[]
|
||||||
{
|
{
|
||||||
Text.NewLine,
|
Text.NewLine,
|
||||||
new Text($"Version {version}"),
|
new Text($"Version {version}"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
namespace Spectre.Console.Cli.Tests.Data.Help;
|
namespace Spectre.Console.Cli.Tests.Data.Help;
|
||||||
|
|
||||||
internal class RedirectHelpProvider : IHelpProvider
|
internal class RedirectHelpProvider : IHelpProvider
|
||||||
{
|
{
|
||||||
public virtual IEnumerable<IRenderable> Write(ICommandModel model)
|
public virtual IEnumerable<IRenderable> Write(ICommandModel model)
|
||||||
{
|
{
|
||||||
return Write(model, null);
|
return Write(model, null);
|
||||||
}
|
}
|
||||||
#nullable enable
|
#nullable enable
|
||||||
public virtual IEnumerable<IRenderable> Write(ICommandModel model, ICommandInfo? command)
|
public virtual IEnumerable<IRenderable> Write(ICommandModel model, ICommandInfo? command)
|
||||||
#nullable disable
|
#nullable disable
|
||||||
{
|
{
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
new Text("Help has moved online. Please see: http://www.example.com"),
|
new Text("Help has moved online. Please see: http://www.example.com"),
|
||||||
Text.NewLine,
|
Text.NewLine,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
namespace Spectre.Console.Tests.Data;
|
namespace Spectre.Console.Tests.Data;
|
||||||
|
|
||||||
public sealed class AsynchronousCommandSettings : CommandSettings
|
public sealed class AsynchronousCommandSettings : CommandSettings
|
||||||
{
|
{
|
||||||
[CommandOption("--ThrowException")]
|
[CommandOption("--ThrowException")]
|
||||||
[DefaultValue(false)]
|
[DefaultValue(false)]
|
||||||
public bool ThrowException { get; set; }
|
public bool ThrowException { get; set; }
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace Spectre.Console.Tests.Data;
|
namespace Spectre.Console.Tests.Data;
|
||||||
|
|
||||||
public class ReptileSettings : AnimalSettings
|
public class ReptileSettings : AnimalSettings
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
namespace Spectre.Console.Tests.Data;
|
namespace Spectre.Console.Tests.Data;
|
||||||
|
|
||||||
public sealed class ThrowingCommandSettings : CommandSettings
|
public sealed class ThrowingCommandSettings : CommandSettings
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ global using System.Linq;
|
|||||||
global using System.Runtime.CompilerServices;
|
global using System.Runtime.CompilerServices;
|
||||||
global using System.Threading.Tasks;
|
global using System.Threading.Tasks;
|
||||||
global using Shouldly;
|
global using Shouldly;
|
||||||
global using Spectre.Console.Cli;
|
global using Spectre.Console.Cli;
|
||||||
global using Spectre.Console.Cli.Help;
|
global using Spectre.Console.Cli.Help;
|
||||||
global using Spectre.Console.Cli.Unsafe;
|
global using Spectre.Console.Cli.Unsafe;
|
||||||
global using Spectre.Console.Testing;
|
global using Spectre.Console.Testing;
|
||||||
|
@ -1,70 +1,70 @@
|
|||||||
namespace Spectre.Console.Tests.Unit.Cli;
|
namespace Spectre.Console.Tests.Unit.Cli;
|
||||||
|
|
||||||
public sealed partial class CommandAppTests
|
public sealed partial class CommandAppTests
|
||||||
{
|
{
|
||||||
public sealed class Async
|
public sealed class Async
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void Should_Execute_Command_Asynchronously()
|
public async void Should_Execute_Command_Asynchronously()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.SetDefaultCommand<AsynchronousCommand>();
|
app.SetDefaultCommand<AsynchronousCommand>();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = await app.RunAsync();
|
var result = await app.RunAsync();
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ExitCode.ShouldBe(0);
|
result.ExitCode.ShouldBe(0);
|
||||||
result.Output.ShouldBe("Finished executing asynchronously");
|
result.Output.ShouldBe("Finished executing asynchronously");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void Should_Handle_Exception_Asynchronously()
|
public async void Should_Handle_Exception_Asynchronously()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.SetDefaultCommand<AsynchronousCommand>();
|
app.SetDefaultCommand<AsynchronousCommand>();
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = await app.RunAsync(new[]
|
var result = await app.RunAsync(new[]
|
||||||
{
|
{
|
||||||
"--ThrowException",
|
"--ThrowException",
|
||||||
"true",
|
"true",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ExitCode.ShouldBe(-1);
|
result.ExitCode.ShouldBe(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void Should_Throw_Exception_Asynchronously()
|
public async void Should_Throw_Exception_Asynchronously()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.SetDefaultCommand<AsynchronousCommand>();
|
app.SetDefaultCommand<AsynchronousCommand>();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = await Record.ExceptionAsync(async () =>
|
var result = await Record.ExceptionAsync(async () =>
|
||||||
await app.RunAsync(new[]
|
await app.RunAsync(new[]
|
||||||
{
|
{
|
||||||
"--ThrowException",
|
"--ThrowException",
|
||||||
"true",
|
"true",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ShouldBeOfType<Exception>().And(ex =>
|
result.ShouldBeOfType<Exception>().And(ex =>
|
||||||
{
|
{
|
||||||
ex.Message.ShouldBe("Throwing exception asynchronously");
|
ex.Message.ShouldBe("Throwing exception asynchronously");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,133 +3,133 @@ namespace Spectre.Console.Tests.Unit.Cli;
|
|||||||
public sealed partial class CommandAppTests
|
public sealed partial class CommandAppTests
|
||||||
{
|
{
|
||||||
public sealed class Branches
|
public sealed class Branches
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Run_The_Default_Command_On_Branch()
|
public void Should_Run_The_Default_Command_On_Branch()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||||
{
|
{
|
||||||
animal.SetDefaultCommand<CatCommand>();
|
animal.SetDefaultCommand<CatCommand>();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = app.Run(new[]
|
var result = app.Run(new[]
|
||||||
{
|
{
|
||||||
"animal", "4",
|
"animal", "4",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ExitCode.ShouldBe(0);
|
result.ExitCode.ShouldBe(0);
|
||||||
result.Settings.ShouldBeOfType<CatSettings>();
|
result.Settings.ShouldBeOfType<CatSettings>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Throw_When_No_Default_Command_On_Branch()
|
public void Should_Throw_When_No_Default_Command_On_Branch()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddBranch<AnimalSettings>("animal", animal => { });
|
config.AddBranch<AnimalSettings>("animal", animal => { });
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = Record.Exception(() =>
|
var result = Record.Exception(() =>
|
||||||
{
|
{
|
||||||
app.Run(new[]
|
app.Run(new[]
|
||||||
{
|
{
|
||||||
"animal", "4",
|
"animal", "4",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
|
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
|
||||||
{
|
{
|
||||||
ex.Message.ShouldBe("The branch 'animal' does not define any commands.");
|
ex.Message.ShouldBe("The branch 'animal' does not define any commands.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1515:SingleLineCommentMustBePrecededByBlankLine", Justification = "Helps to illustrate the expected behaviour of this unit test.")]
|
[SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1515:SingleLineCommentMustBePrecededByBlankLine", Justification = "Helps to illustrate the expected behaviour of this unit test.")]
|
||||||
[SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1005:SingleLineCommentsMustBeginWithSingleSpace", Justification = "Helps to illustrate the expected behaviour of this unit test.")]
|
[SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1005:SingleLineCommentsMustBeginWithSingleSpace", Justification = "Helps to illustrate the expected behaviour of this unit test.")]
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Be_Unable_To_Parse_Default_Command_Arguments_Relaxed_Parsing()
|
public void Should_Be_Unable_To_Parse_Default_Command_Arguments_Relaxed_Parsing()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||||
{
|
{
|
||||||
animal.SetDefaultCommand<CatCommand>();
|
animal.SetDefaultCommand<CatCommand>();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = app.Run(new[]
|
var result = app.Run(new[]
|
||||||
{
|
{
|
||||||
// The CommandTreeParser should be unable to determine which command line
|
// The CommandTreeParser should be unable to determine which command line
|
||||||
// arguments belong to the branch and which belong to the branch's
|
// arguments belong to the branch and which belong to the branch's
|
||||||
// default command (once inserted).
|
// default command (once inserted).
|
||||||
"animal", "4", "--name", "Kitty",
|
"animal", "4", "--name", "Kitty",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ExitCode.ShouldBe(0);
|
result.ExitCode.ShouldBe(0);
|
||||||
result.Settings.ShouldBeOfType<CatSettings>().And(cat =>
|
result.Settings.ShouldBeOfType<CatSettings>().And(cat =>
|
||||||
{
|
{
|
||||||
cat.Legs.ShouldBe(4);
|
cat.Legs.ShouldBe(4);
|
||||||
//cat.Name.ShouldBe("Kitty"); //<-- Should normally be correct, but instead name will be added to the remaining arguments (see below).
|
//cat.Name.ShouldBe("Kitty"); //<-- Should normally be correct, but instead name will be added to the remaining arguments (see below).
|
||||||
});
|
});
|
||||||
result.Context.Remaining.Parsed.Count.ShouldBe(1);
|
result.Context.Remaining.Parsed.Count.ShouldBe(1);
|
||||||
result.Context.ShouldHaveRemainingArgument("name", values: new[] { "Kitty", });
|
result.Context.ShouldHaveRemainingArgument("name", values: new[] { "Kitty", });
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Be_Unable_To_Parse_Default_Command_Arguments_Strict_Parsing()
|
public void Should_Be_Unable_To_Parse_Default_Command_Arguments_Strict_Parsing()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.UseStrictParsing();
|
config.UseStrictParsing();
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||||
{
|
{
|
||||||
animal.SetDefaultCommand<CatCommand>();
|
animal.SetDefaultCommand<CatCommand>();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = Record.Exception(() =>
|
var result = Record.Exception(() =>
|
||||||
{
|
{
|
||||||
app.Run(new[]
|
app.Run(new[]
|
||||||
{
|
{
|
||||||
// The CommandTreeParser should be unable to determine which command line
|
// The CommandTreeParser should be unable to determine which command line
|
||||||
// arguments belong to the branch and which belong to the branch's
|
// arguments belong to the branch and which belong to the branch's
|
||||||
// default command (once inserted).
|
// default command (once inserted).
|
||||||
"animal", "4", "--name", "Kitty",
|
"animal", "4", "--name", "Kitty",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
||||||
{
|
{
|
||||||
ex.Message.ShouldBe("Unknown option 'name'.");
|
ex.Message.ShouldBe("Unknown option 'name'.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Run_The_Default_Command_On_Branch_On_Branch()
|
public void Should_Run_The_Default_Command_On_Branch_On_Branch()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
@ -141,23 +141,23 @@ public sealed partial class CommandAppTests
|
|||||||
mammal.SetDefaultCommand<CatCommand>();
|
mammal.SetDefaultCommand<CatCommand>();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = app.Run(new[]
|
var result = app.Run(new[]
|
||||||
{
|
{
|
||||||
"animal", "4", "mammal",
|
"animal", "4", "mammal",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ExitCode.ShouldBe(0);
|
result.ExitCode.ShouldBe(0);
|
||||||
result.Settings.ShouldBeOfType<CatSettings>();
|
result.Settings.ShouldBeOfType<CatSettings>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Run_The_Default_Command_On_Branch_On_Branch_With_Arguments()
|
public void Should_Run_The_Default_Command_On_Branch_On_Branch_With_Arguments()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
@ -169,83 +169,83 @@ public sealed partial class CommandAppTests
|
|||||||
mammal.SetDefaultCommand<CatCommand>();
|
mammal.SetDefaultCommand<CatCommand>();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = app.Run(new[]
|
var result = app.Run(new[]
|
||||||
{
|
{
|
||||||
"animal", "4", "mammal", "--name", "Kitty",
|
"animal", "4", "mammal", "--name", "Kitty",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ExitCode.ShouldBe(0);
|
result.ExitCode.ShouldBe(0);
|
||||||
result.Settings.ShouldBeOfType<CatSettings>().And(cat =>
|
result.Settings.ShouldBeOfType<CatSettings>().And(cat =>
|
||||||
{
|
{
|
||||||
cat.Legs.ShouldBe(4);
|
cat.Legs.ShouldBe(4);
|
||||||
cat.Name.ShouldBe("Kitty");
|
cat.Name.ShouldBe("Kitty");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Run_The_Default_Command_Not_The_Named_Command_On_Branch()
|
public void Should_Run_The_Default_Command_Not_The_Named_Command_On_Branch()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||||
{
|
{
|
||||||
animal.AddCommand<DogCommand>("dog");
|
animal.AddCommand<DogCommand>("dog");
|
||||||
|
|
||||||
animal.SetDefaultCommand<CatCommand>();
|
animal.SetDefaultCommand<CatCommand>();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = app.Run(new[]
|
var result = app.Run(new[]
|
||||||
{
|
{
|
||||||
"animal", "4",
|
"animal", "4",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ExitCode.ShouldBe(0);
|
result.ExitCode.ShouldBe(0);
|
||||||
result.Settings.ShouldBeOfType<CatSettings>();
|
result.Settings.ShouldBeOfType<CatSettings>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Run_The_Named_Command_Not_The_Default_Command_On_Branch()
|
public void Should_Run_The_Named_Command_Not_The_Default_Command_On_Branch()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||||
{
|
{
|
||||||
animal.AddCommand<DogCommand>("dog");
|
animal.AddCommand<DogCommand>("dog");
|
||||||
|
|
||||||
animal.SetDefaultCommand<LionCommand>();
|
animal.SetDefaultCommand<LionCommand>();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = app.Run(new[]
|
var result = app.Run(new[]
|
||||||
{
|
{
|
||||||
"animal", "4", "dog", "12", "--good-boy", "--name", "Rufus",
|
"animal", "4", "dog", "12", "--good-boy", "--name", "Rufus",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ExitCode.ShouldBe(0);
|
result.ExitCode.ShouldBe(0);
|
||||||
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
|
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
|
||||||
{
|
{
|
||||||
dog.Legs.ShouldBe(4);
|
dog.Legs.ShouldBe(4);
|
||||||
dog.Age.ShouldBe(12);
|
dog.Age.ShouldBe(12);
|
||||||
dog.GoodBoy.ShouldBe(true);
|
dog.GoodBoy.ShouldBe(true);
|
||||||
dog.Name.ShouldBe("Rufus");
|
dog.Name.ShouldBe("Rufus");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Allow_Multiple_Branches_Multiple_Commands()
|
public void Should_Allow_Multiple_Branches_Multiple_Commands()
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
using Spectre.Console.Cli.Tests.Data.Help;
|
using Spectre.Console.Cli.Tests.Data.Help;
|
||||||
|
|
||||||
namespace Spectre.Console.Tests.Unit.Cli;
|
namespace Spectre.Console.Tests.Unit.Cli;
|
||||||
|
|
||||||
public sealed partial class CommandAppTests
|
public sealed partial class CommandAppTests
|
||||||
@ -93,12 +93,12 @@ public sealed partial class CommandAppTests
|
|||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = fixture.Run("cat", "--help");
|
var result = fixture.Run("cat", "--help");
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Branch_Called_Without_Help")]
|
[Expectation("Branch_Called_Without_Help")]
|
||||||
public Task Should_Output_Branch_When_Called_Without_Help_Option()
|
public Task Should_Output_Branch_When_Called_Without_Help_Option()
|
||||||
@ -110,27 +110,27 @@ public sealed partial class CommandAppTests
|
|||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
configurator.AddBranch<CatSettings>("cat", animal =>
|
configurator.AddBranch<CatSettings>("cat", animal =>
|
||||||
{
|
{
|
||||||
animal.SetDescription("Contains settings for a cat.");
|
animal.SetDescription("Contains settings for a cat.");
|
||||||
animal.AddCommand<LionCommand>("lion");
|
animal.AddCommand<LionCommand>("lion");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = fixture.Run("cat");
|
var result = fixture.Run("cat");
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Branch_Default_Greeter")]
|
[Expectation("Branch_Default_Greeter")]
|
||||||
public Task Should_Output_Branch_With_Default_Correctly()
|
public Task Should_Output_Branch_With_Default_Correctly()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var fixture = new CommandAppTester();
|
var fixture = new CommandAppTester();
|
||||||
fixture.Configure(configurator =>
|
fixture.Configure(configurator =>
|
||||||
{
|
{
|
||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
configurator.AddBranch<OptionalArgumentWithDefaultValueSettings>("branch", animal =>
|
configurator.AddBranch<OptionalArgumentWithDefaultValueSettings>("branch", animal =>
|
||||||
{
|
{
|
||||||
animal.SetDefaultCommand<GreeterCommand>();
|
animal.SetDefaultCommand<GreeterCommand>();
|
||||||
@ -138,8 +138,8 @@ public sealed partial class CommandAppTests
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = fixture.Run("branch", "--help");
|
var result = fixture.Run("branch", "--help");
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
@ -186,7 +186,7 @@ public sealed partial class CommandAppTests
|
|||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = fixture.Run("cat", "lion", "--help");
|
var result = fixture.Run("cat", "lion", "--help");
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
@ -233,13 +233,13 @@ public sealed partial class CommandAppTests
|
|||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(null, "EN")]
|
[InlineData(null, "EN")]
|
||||||
[InlineData("", "EN")]
|
[InlineData("", "EN")]
|
||||||
[InlineData("en", "EN")]
|
[InlineData("en", "EN")]
|
||||||
[InlineData("en-EN", "EN")]
|
[InlineData("en-EN", "EN")]
|
||||||
[InlineData("fr", "FR")]
|
[InlineData("fr", "FR")]
|
||||||
[InlineData("fr-FR", "FR")]
|
[InlineData("fr-FR", "FR")]
|
||||||
[InlineData("sv", "SV")]
|
[InlineData("sv", "SV")]
|
||||||
[InlineData("sv-SE", "SV")]
|
[InlineData("sv-SE", "SV")]
|
||||||
[InlineData("de", "DE")]
|
[InlineData("de", "DE")]
|
||||||
[InlineData("de-DE", "DE")]
|
[InlineData("de-DE", "DE")]
|
||||||
[Expectation("Default_Without_Args_Additional")]
|
[Expectation("Default_Without_Args_Additional")]
|
||||||
public Task Should_Output_Default_Command_And_Additional_Commands_When_Default_Command_Has_Required_Parameters_And_Is_Called_Without_Args_Localised(string culture, string expectationPrefix)
|
public Task Should_Output_Default_Command_And_Additional_Commands_When_Default_Command_Has_Required_Parameters_And_Is_Called_Without_Args_Localised(string culture, string expectationPrefix)
|
||||||
@ -281,106 +281,106 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Custom_Help_Registered_By_Instance")]
|
[Expectation("Custom_Help_Registered_By_Instance")]
|
||||||
public Task Should_Output_Custom_Help_When_Registered_By_Instance()
|
public Task Should_Output_Custom_Help_When_Registered_By_Instance()
|
||||||
{
|
{
|
||||||
var registrar = new DefaultTypeRegistrar();
|
var registrar = new DefaultTypeRegistrar();
|
||||||
|
|
||||||
// Given
|
// Given
|
||||||
var fixture = new CommandAppTester(registrar);
|
var fixture = new CommandAppTester(registrar);
|
||||||
fixture.Configure(configurator =>
|
fixture.Configure(configurator =>
|
||||||
{
|
{
|
||||||
// Create the custom help provider
|
// Create the custom help provider
|
||||||
var helpProvider = new CustomHelpProvider(configurator.Settings, "1.0");
|
var helpProvider = new CustomHelpProvider(configurator.Settings, "1.0");
|
||||||
|
|
||||||
// Register the custom help provider instance
|
// Register the custom help provider instance
|
||||||
registrar.RegisterInstance(typeof(IHelpProvider), helpProvider);
|
registrar.RegisterInstance(typeof(IHelpProvider), helpProvider);
|
||||||
|
|
||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
configurator.AddCommand<DogCommand>("dog");
|
configurator.AddCommand<DogCommand>("dog");
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = fixture.Run();
|
var result = fixture.Run();
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Custom_Help_Registered_By_Type")]
|
[Expectation("Custom_Help_Registered_By_Type")]
|
||||||
public Task Should_Output_Custom_Help_When_Registered_By_Type()
|
public Task Should_Output_Custom_Help_When_Registered_By_Type()
|
||||||
{
|
{
|
||||||
var registrar = new DefaultTypeRegistrar();
|
var registrar = new DefaultTypeRegistrar();
|
||||||
|
|
||||||
// Given
|
// Given
|
||||||
var fixture = new CommandAppTester(registrar);
|
var fixture = new CommandAppTester(registrar);
|
||||||
fixture.Configure(configurator =>
|
fixture.Configure(configurator =>
|
||||||
{
|
{
|
||||||
// Register the custom help provider type
|
// Register the custom help provider type
|
||||||
registrar.Register(typeof(IHelpProvider), typeof(RedirectHelpProvider));
|
registrar.Register(typeof(IHelpProvider), typeof(RedirectHelpProvider));
|
||||||
|
|
||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
configurator.AddCommand<DogCommand>("dog");
|
configurator.AddCommand<DogCommand>("dog");
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = fixture.Run();
|
var result = fixture.Run();
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Custom_Help_Configured_By_Instance")]
|
[Expectation("Custom_Help_Configured_By_Instance")]
|
||||||
public Task Should_Output_Custom_Help_When_Configured_By_Instance()
|
public Task Should_Output_Custom_Help_When_Configured_By_Instance()
|
||||||
{
|
{
|
||||||
var registrar = new DefaultTypeRegistrar();
|
var registrar = new DefaultTypeRegistrar();
|
||||||
|
|
||||||
// Given
|
// Given
|
||||||
var fixture = new CommandAppTester(registrar);
|
var fixture = new CommandAppTester(registrar);
|
||||||
fixture.Configure(configurator =>
|
fixture.Configure(configurator =>
|
||||||
{
|
{
|
||||||
// Configure the custom help provider instance
|
// Configure the custom help provider instance
|
||||||
configurator.SetHelpProvider(new CustomHelpProvider(configurator.Settings, "1.0"));
|
configurator.SetHelpProvider(new CustomHelpProvider(configurator.Settings, "1.0"));
|
||||||
|
|
||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
configurator.AddCommand<DogCommand>("dog");
|
configurator.AddCommand<DogCommand>("dog");
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = fixture.Run();
|
var result = fixture.Run();
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Custom_Help_Configured_By_Type")]
|
[Expectation("Custom_Help_Configured_By_Type")]
|
||||||
public Task Should_Output_Custom_Help_When_Configured_By_Type()
|
public Task Should_Output_Custom_Help_When_Configured_By_Type()
|
||||||
{
|
{
|
||||||
var registrar = new DefaultTypeRegistrar();
|
var registrar = new DefaultTypeRegistrar();
|
||||||
|
|
||||||
// Given
|
// Given
|
||||||
var fixture = new CommandAppTester(registrar);
|
var fixture = new CommandAppTester(registrar);
|
||||||
fixture.Configure(configurator =>
|
fixture.Configure(configurator =>
|
||||||
{
|
{
|
||||||
// Configure the custom help provider type
|
// Configure the custom help provider type
|
||||||
configurator.SetHelpProvider<RedirectHelpProvider>();
|
configurator.SetHelpProvider<RedirectHelpProvider>();
|
||||||
|
|
||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
configurator.AddCommand<DogCommand>("dog");
|
configurator.AddCommand<DogCommand>("dog");
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = fixture.Run();
|
var result = fixture.Run();
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Root_Examples")]
|
[Expectation("Root_Examples")]
|
||||||
@ -391,20 +391,20 @@ public sealed partial class CommandAppTests
|
|||||||
fixture.Configure(configurator =>
|
fixture.Configure(configurator =>
|
||||||
{
|
{
|
||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
|
|
||||||
// All root examples should be shown
|
// All root examples should be shown
|
||||||
configurator.AddExample("dog", "--name", "Rufus", "--age", "12", "--good-boy");
|
configurator.AddExample("dog", "--name", "Rufus", "--age", "12", "--good-boy");
|
||||||
configurator.AddExample("dog", "--name", "Luna");
|
configurator.AddExample("dog", "--name", "Luna");
|
||||||
configurator.AddExample("dog", "--name", "Charlie");
|
configurator.AddExample("dog", "--name", "Charlie");
|
||||||
configurator.AddExample("dog", "--name", "Bella");
|
configurator.AddExample("dog", "--name", "Bella");
|
||||||
configurator.AddExample("dog", "--name", "Daisy");
|
configurator.AddExample("dog", "--name", "Daisy");
|
||||||
configurator.AddExample("dog", "--name", "Milo");
|
configurator.AddExample("dog", "--name", "Milo");
|
||||||
configurator.AddExample("horse", "--name", "Brutus");
|
configurator.AddExample("horse", "--name", "Brutus");
|
||||||
configurator.AddExample("horse", "--name", "Sugar", "--IsAlive", "false");
|
configurator.AddExample("horse", "--name", "Sugar", "--IsAlive", "false");
|
||||||
configurator.AddExample("horse", "--name", "Cash");
|
configurator.AddExample("horse", "--name", "Cash");
|
||||||
configurator.AddExample("horse", "--name", "Dakota");
|
configurator.AddExample("horse", "--name", "Dakota");
|
||||||
configurator.AddExample("horse", "--name", "Cisco");
|
configurator.AddExample("horse", "--name", "Cisco");
|
||||||
configurator.AddExample("horse", "--name", "Spirit");
|
configurator.AddExample("horse", "--name", "Spirit");
|
||||||
|
|
||||||
configurator.AddCommand<DogCommand>("dog");
|
configurator.AddCommand<DogCommand>("dog");
|
||||||
configurator.AddCommand<HorseCommand>("horse");
|
configurator.AddCommand<HorseCommand>("horse");
|
||||||
@ -415,10 +415,10 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Root_Examples_Children")]
|
[Expectation("Root_Examples_Children")]
|
||||||
[SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1512:SingleLineCommentsMustNotBeFollowedByBlankLine", Justification = "Single line comment is relevant to several code blocks that follow.")]
|
[SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1512:SingleLineCommentsMustNotBeFollowedByBlankLine", Justification = "Single line comment is relevant to several code blocks that follow.")]
|
||||||
public Task Should_Output_Examples_Defined_On_Direct_Children_If_Root_Has_No_Examples()
|
public Task Should_Output_Examples_Defined_On_Direct_Children_If_Root_Has_No_Examples()
|
||||||
{
|
{
|
||||||
@ -426,135 +426,24 @@ public sealed partial class CommandAppTests
|
|||||||
var fixture = new CommandAppTester();
|
var fixture = new CommandAppTester();
|
||||||
fixture.Configure(configurator =>
|
fixture.Configure(configurator =>
|
||||||
{
|
{
|
||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
|
|
||||||
// It should be capped to the first 5 examples by default
|
// It should be capped to the first 5 examples by default
|
||||||
|
|
||||||
configurator.AddCommand<DogCommand>("dog")
|
configurator.AddCommand<DogCommand>("dog")
|
||||||
.WithExample("dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
.WithExample("dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
||||||
.WithExample("dog", "--name", "Luna")
|
.WithExample("dog", "--name", "Luna")
|
||||||
.WithExample("dog", "--name", "Charlie")
|
.WithExample("dog", "--name", "Charlie")
|
||||||
.WithExample("dog", "--name", "Bella")
|
.WithExample("dog", "--name", "Bella")
|
||||||
.WithExample("dog", "--name", "Daisy")
|
.WithExample("dog", "--name", "Daisy")
|
||||||
.WithExample("dog", "--name", "Milo");
|
.WithExample("dog", "--name", "Milo");
|
||||||
|
|
||||||
configurator.AddCommand<HorseCommand>("horse")
|
configurator.AddCommand<HorseCommand>("horse")
|
||||||
.WithExample("horse", "--name", "Brutus")
|
.WithExample("horse", "--name", "Brutus")
|
||||||
.WithExample("horse", "--name", "Sugar", "--IsAlive", "false")
|
.WithExample("horse", "--name", "Sugar", "--IsAlive", "false")
|
||||||
.WithExample("horse", "--name", "Cash")
|
.WithExample("horse", "--name", "Cash")
|
||||||
.WithExample("horse", "--name", "Dakota")
|
.WithExample("horse", "--name", "Dakota")
|
||||||
.WithExample("horse", "--name", "Cisco")
|
.WithExample("horse", "--name", "Cisco")
|
||||||
.WithExample("horse", "--name", "Spirit");
|
|
||||||
});
|
|
||||||
|
|
||||||
// When
|
|
||||||
var result = fixture.Run("--help");
|
|
||||||
|
|
||||||
// Then
|
|
||||||
return Verifier.Verify(result.Output);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Expectation("Root_Examples_Children_Eight")]
|
|
||||||
public Task Should_Output_Eight_Examples_Defined_On_Direct_Children_If_Root_Has_No_Examples()
|
|
||||||
{
|
|
||||||
// Given
|
|
||||||
var fixture = new CommandAppTester();
|
|
||||||
fixture.Configure(configurator =>
|
|
||||||
{
|
|
||||||
configurator.SetApplicationName("myapp");
|
|
||||||
|
|
||||||
// Show the first 8 examples defined on the direct children
|
|
||||||
configurator.Settings.MaximumIndirectExamples = 8;
|
|
||||||
|
|
||||||
configurator.AddCommand<DogCommand>("dog")
|
|
||||||
.WithExample("dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
|
||||||
.WithExample("dog", "--name", "Luna")
|
|
||||||
.WithExample("dog", "--name", "Charlie")
|
|
||||||
.WithExample("dog", "--name", "Bella")
|
|
||||||
.WithExample("dog", "--name", "Daisy")
|
|
||||||
.WithExample("dog", "--name", "Milo");
|
|
||||||
|
|
||||||
configurator.AddCommand<HorseCommand>("horse")
|
|
||||||
.WithExample("horse", "--name", "Brutus")
|
|
||||||
.WithExample("horse", "--name", "Sugar", "--IsAlive", "false")
|
|
||||||
.WithExample("horse", "--name", "Cash")
|
|
||||||
.WithExample("horse", "--name", "Dakota")
|
|
||||||
.WithExample("horse", "--name", "Cisco")
|
|
||||||
.WithExample("horse", "--name", "Spirit");
|
|
||||||
});
|
|
||||||
|
|
||||||
// When
|
|
||||||
var result = fixture.Run("--help");
|
|
||||||
|
|
||||||
// Then
|
|
||||||
return Verifier.Verify(result.Output);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Expectation("Root_Examples_Children_Twelve")]
|
|
||||||
public Task Should_Output_All_Examples_Defined_On_Direct_Children_If_Root_Has_No_Examples()
|
|
||||||
{
|
|
||||||
// Given
|
|
||||||
var fixture = new CommandAppTester();
|
|
||||||
fixture.Configure(configurator =>
|
|
||||||
{
|
|
||||||
configurator.SetApplicationName("myapp");
|
|
||||||
|
|
||||||
// Show all examples defined on the direct children
|
|
||||||
configurator.Settings.MaximumIndirectExamples = int.MaxValue;
|
|
||||||
|
|
||||||
configurator.AddCommand<DogCommand>("dog")
|
|
||||||
.WithExample("dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
|
||||||
.WithExample("dog", "--name", "Luna")
|
|
||||||
.WithExample("dog", "--name", "Charlie")
|
|
||||||
.WithExample("dog", "--name", "Bella")
|
|
||||||
.WithExample("dog", "--name", "Daisy")
|
|
||||||
.WithExample("dog", "--name", "Milo");
|
|
||||||
|
|
||||||
configurator.AddCommand<HorseCommand>("horse")
|
|
||||||
.WithExample("horse", "--name", "Brutus")
|
|
||||||
.WithExample("horse", "--name", "Sugar", "--IsAlive", "false")
|
|
||||||
.WithExample("horse", "--name", "Cash")
|
|
||||||
.WithExample("horse", "--name", "Dakota")
|
|
||||||
.WithExample("horse", "--name", "Cisco")
|
|
||||||
.WithExample("horse", "--name", "Spirit");
|
|
||||||
});
|
|
||||||
|
|
||||||
// When
|
|
||||||
var result = fixture.Run("--help");
|
|
||||||
|
|
||||||
// Then
|
|
||||||
return Verifier.Verify(result.Output);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Expectation("Root_Examples_Children_None")]
|
|
||||||
public Task Should_Not_Output_Examples_Defined_On_Direct_Children_If_Root_Has_No_Examples()
|
|
||||||
{
|
|
||||||
// Given
|
|
||||||
var fixture = new CommandAppTester();
|
|
||||||
fixture.Configure(configurator =>
|
|
||||||
{
|
|
||||||
configurator.SetApplicationName("myapp");
|
|
||||||
|
|
||||||
// Do not show examples defined on the direct children
|
|
||||||
configurator.Settings.MaximumIndirectExamples = 0;
|
|
||||||
|
|
||||||
configurator.AddCommand<DogCommand>("dog")
|
|
||||||
.WithExample("dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
|
||||||
.WithExample("dog", "--name", "Luna")
|
|
||||||
.WithExample("dog", "--name", "Charlie")
|
|
||||||
.WithExample("dog", "--name", "Bella")
|
|
||||||
.WithExample("dog", "--name", "Daisy")
|
|
||||||
.WithExample("dog", "--name", "Milo");
|
|
||||||
|
|
||||||
configurator.AddCommand<HorseCommand>("horse")
|
|
||||||
.WithExample("horse", "--name", "Brutus")
|
|
||||||
.WithExample("horse", "--name", "Sugar", "--IsAlive", "false")
|
|
||||||
.WithExample("horse", "--name", "Cash")
|
|
||||||
.WithExample("horse", "--name", "Dakota")
|
|
||||||
.WithExample("horse", "--name", "Cisco")
|
|
||||||
.WithExample("horse", "--name", "Spirit");
|
.WithExample("horse", "--name", "Spirit");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -566,7 +455,118 @@ public sealed partial class CommandAppTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Root_Examples_Leafs")]
|
[Expectation("Root_Examples_Children_Eight")]
|
||||||
|
public Task Should_Output_Eight_Examples_Defined_On_Direct_Children_If_Root_Has_No_Examples()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var fixture = new CommandAppTester();
|
||||||
|
fixture.Configure(configurator =>
|
||||||
|
{
|
||||||
|
configurator.SetApplicationName("myapp");
|
||||||
|
|
||||||
|
// Show the first 8 examples defined on the direct children
|
||||||
|
configurator.Settings.MaximumIndirectExamples = 8;
|
||||||
|
|
||||||
|
configurator.AddCommand<DogCommand>("dog")
|
||||||
|
.WithExample("dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
||||||
|
.WithExample("dog", "--name", "Luna")
|
||||||
|
.WithExample("dog", "--name", "Charlie")
|
||||||
|
.WithExample("dog", "--name", "Bella")
|
||||||
|
.WithExample("dog", "--name", "Daisy")
|
||||||
|
.WithExample("dog", "--name", "Milo");
|
||||||
|
|
||||||
|
configurator.AddCommand<HorseCommand>("horse")
|
||||||
|
.WithExample("horse", "--name", "Brutus")
|
||||||
|
.WithExample("horse", "--name", "Sugar", "--IsAlive", "false")
|
||||||
|
.WithExample("horse", "--name", "Cash")
|
||||||
|
.WithExample("horse", "--name", "Dakota")
|
||||||
|
.WithExample("horse", "--name", "Cisco")
|
||||||
|
.WithExample("horse", "--name", "Spirit");
|
||||||
|
});
|
||||||
|
|
||||||
|
// When
|
||||||
|
var result = fixture.Run("--help");
|
||||||
|
|
||||||
|
// Then
|
||||||
|
return Verifier.Verify(result.Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Expectation("Root_Examples_Children_Twelve")]
|
||||||
|
public Task Should_Output_All_Examples_Defined_On_Direct_Children_If_Root_Has_No_Examples()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var fixture = new CommandAppTester();
|
||||||
|
fixture.Configure(configurator =>
|
||||||
|
{
|
||||||
|
configurator.SetApplicationName("myapp");
|
||||||
|
|
||||||
|
// Show all examples defined on the direct children
|
||||||
|
configurator.Settings.MaximumIndirectExamples = int.MaxValue;
|
||||||
|
|
||||||
|
configurator.AddCommand<DogCommand>("dog")
|
||||||
|
.WithExample("dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
||||||
|
.WithExample("dog", "--name", "Luna")
|
||||||
|
.WithExample("dog", "--name", "Charlie")
|
||||||
|
.WithExample("dog", "--name", "Bella")
|
||||||
|
.WithExample("dog", "--name", "Daisy")
|
||||||
|
.WithExample("dog", "--name", "Milo");
|
||||||
|
|
||||||
|
configurator.AddCommand<HorseCommand>("horse")
|
||||||
|
.WithExample("horse", "--name", "Brutus")
|
||||||
|
.WithExample("horse", "--name", "Sugar", "--IsAlive", "false")
|
||||||
|
.WithExample("horse", "--name", "Cash")
|
||||||
|
.WithExample("horse", "--name", "Dakota")
|
||||||
|
.WithExample("horse", "--name", "Cisco")
|
||||||
|
.WithExample("horse", "--name", "Spirit");
|
||||||
|
});
|
||||||
|
|
||||||
|
// When
|
||||||
|
var result = fixture.Run("--help");
|
||||||
|
|
||||||
|
// Then
|
||||||
|
return Verifier.Verify(result.Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Expectation("Root_Examples_Children_None")]
|
||||||
|
public Task Should_Not_Output_Examples_Defined_On_Direct_Children_If_Root_Has_No_Examples()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var fixture = new CommandAppTester();
|
||||||
|
fixture.Configure(configurator =>
|
||||||
|
{
|
||||||
|
configurator.SetApplicationName("myapp");
|
||||||
|
|
||||||
|
// Do not show examples defined on the direct children
|
||||||
|
configurator.Settings.MaximumIndirectExamples = 0;
|
||||||
|
|
||||||
|
configurator.AddCommand<DogCommand>("dog")
|
||||||
|
.WithExample("dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
||||||
|
.WithExample("dog", "--name", "Luna")
|
||||||
|
.WithExample("dog", "--name", "Charlie")
|
||||||
|
.WithExample("dog", "--name", "Bella")
|
||||||
|
.WithExample("dog", "--name", "Daisy")
|
||||||
|
.WithExample("dog", "--name", "Milo");
|
||||||
|
|
||||||
|
configurator.AddCommand<HorseCommand>("horse")
|
||||||
|
.WithExample("horse", "--name", "Brutus")
|
||||||
|
.WithExample("horse", "--name", "Sugar", "--IsAlive", "false")
|
||||||
|
.WithExample("horse", "--name", "Cash")
|
||||||
|
.WithExample("horse", "--name", "Dakota")
|
||||||
|
.WithExample("horse", "--name", "Cisco")
|
||||||
|
.WithExample("horse", "--name", "Spirit");
|
||||||
|
});
|
||||||
|
|
||||||
|
// When
|
||||||
|
var result = fixture.Run("--help");
|
||||||
|
|
||||||
|
// Then
|
||||||
|
return Verifier.Verify(result.Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Expectation("Root_Examples_Leafs")]
|
||||||
[SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1512:SingleLineCommentsMustNotBeFollowedByBlankLine", Justification = "Single line comment is relevant to several code blocks that follow.")]
|
[SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1512:SingleLineCommentsMustNotBeFollowedByBlankLine", Justification = "Single line comment is relevant to several code blocks that follow.")]
|
||||||
public Task Should_Output_Examples_Defined_On_Leaves_If_No_Other_Examples_Are_Found()
|
public Task Should_Output_Examples_Defined_On_Leaves_If_No_Other_Examples_Are_Found()
|
||||||
{
|
{
|
||||||
@ -577,24 +577,24 @@ public sealed partial class CommandAppTests
|
|||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
configurator.AddBranch<AnimalSettings>("animal", animal =>
|
configurator.AddBranch<AnimalSettings>("animal", animal =>
|
||||||
{
|
{
|
||||||
animal.SetDescription("The animal command.");
|
animal.SetDescription("The animal command.");
|
||||||
|
|
||||||
// It should be capped to the first 5 examples by default
|
// It should be capped to the first 5 examples by default
|
||||||
|
|
||||||
animal.AddCommand<DogCommand>("dog")
|
animal.AddCommand<DogCommand>("dog")
|
||||||
.WithExample("animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
.WithExample("animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
||||||
.WithExample("animal", "dog", "--name", "Luna")
|
.WithExample("animal", "dog", "--name", "Luna")
|
||||||
.WithExample("animal", "dog", "--name", "Charlie")
|
.WithExample("animal", "dog", "--name", "Charlie")
|
||||||
.WithExample("animal", "dog", "--name", "Bella")
|
.WithExample("animal", "dog", "--name", "Bella")
|
||||||
.WithExample("animal", "dog", "--name", "Daisy")
|
.WithExample("animal", "dog", "--name", "Daisy")
|
||||||
.WithExample("animal", "dog", "--name", "Milo");
|
.WithExample("animal", "dog", "--name", "Milo");
|
||||||
|
|
||||||
animal.AddCommand<HorseCommand>("horse")
|
animal.AddCommand<HorseCommand>("horse")
|
||||||
.WithExample("animal", "horse", "--name", "Brutus")
|
.WithExample("animal", "horse", "--name", "Brutus")
|
||||||
.WithExample("animal", "horse", "--name", "Sugar", "--IsAlive", "false")
|
.WithExample("animal", "horse", "--name", "Sugar", "--IsAlive", "false")
|
||||||
.WithExample("animal", "horse", "--name", "Cash")
|
.WithExample("animal", "horse", "--name", "Cash")
|
||||||
.WithExample("animal", "horse", "--name", "Dakota")
|
.WithExample("animal", "horse", "--name", "Dakota")
|
||||||
.WithExample("animal", "horse", "--name", "Cisco")
|
.WithExample("animal", "horse", "--name", "Cisco")
|
||||||
.WithExample("animal", "horse", "--name", "Spirit");
|
.WithExample("animal", "horse", "--name", "Spirit");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -604,10 +604,10 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Root_Examples_Leafs_Eight")]
|
[Expectation("Root_Examples_Leafs_Eight")]
|
||||||
public Task Should_Output_Eight_Examples_Defined_On_Leaves_If_No_Other_Examples_Are_Found()
|
public Task Should_Output_Eight_Examples_Defined_On_Leaves_If_No_Other_Examples_Are_Found()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
@ -617,25 +617,25 @@ public sealed partial class CommandAppTests
|
|||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
configurator.AddBranch<AnimalSettings>("animal", animal =>
|
configurator.AddBranch<AnimalSettings>("animal", animal =>
|
||||||
{
|
{
|
||||||
animal.SetDescription("The animal command.");
|
animal.SetDescription("The animal command.");
|
||||||
|
|
||||||
// Show the first 8 examples defined on the direct children
|
// Show the first 8 examples defined on the direct children
|
||||||
configurator.Settings.MaximumIndirectExamples = 8;
|
configurator.Settings.MaximumIndirectExamples = 8;
|
||||||
|
|
||||||
animal.AddCommand<DogCommand>("dog")
|
animal.AddCommand<DogCommand>("dog")
|
||||||
.WithExample("animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
.WithExample("animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
||||||
.WithExample("animal", "dog", "--name", "Luna")
|
.WithExample("animal", "dog", "--name", "Luna")
|
||||||
.WithExample("animal", "dog", "--name", "Charlie")
|
.WithExample("animal", "dog", "--name", "Charlie")
|
||||||
.WithExample("animal", "dog", "--name", "Bella")
|
.WithExample("animal", "dog", "--name", "Bella")
|
||||||
.WithExample("animal", "dog", "--name", "Daisy")
|
.WithExample("animal", "dog", "--name", "Daisy")
|
||||||
.WithExample("animal", "dog", "--name", "Milo");
|
.WithExample("animal", "dog", "--name", "Milo");
|
||||||
|
|
||||||
animal.AddCommand<HorseCommand>("horse")
|
animal.AddCommand<HorseCommand>("horse")
|
||||||
.WithExample("animal", "horse", "--name", "Brutus")
|
.WithExample("animal", "horse", "--name", "Brutus")
|
||||||
.WithExample("animal", "horse", "--name", "Sugar", "--IsAlive", "false")
|
.WithExample("animal", "horse", "--name", "Sugar", "--IsAlive", "false")
|
||||||
.WithExample("animal", "horse", "--name", "Cash")
|
.WithExample("animal", "horse", "--name", "Cash")
|
||||||
.WithExample("animal", "horse", "--name", "Dakota")
|
.WithExample("animal", "horse", "--name", "Dakota")
|
||||||
.WithExample("animal", "horse", "--name", "Cisco")
|
.WithExample("animal", "horse", "--name", "Cisco")
|
||||||
.WithExample("animal", "horse", "--name", "Spirit");
|
.WithExample("animal", "horse", "--name", "Spirit");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -645,10 +645,10 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Root_Examples_Leafs_Twelve")]
|
[Expectation("Root_Examples_Leafs_Twelve")]
|
||||||
public Task Should_Output_All_Examples_Defined_On_Leaves_If_No_Other_Examples_Are_Found()
|
public Task Should_Output_All_Examples_Defined_On_Leaves_If_No_Other_Examples_Are_Found()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
@ -658,25 +658,25 @@ public sealed partial class CommandAppTests
|
|||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
configurator.AddBranch<AnimalSettings>("animal", animal =>
|
configurator.AddBranch<AnimalSettings>("animal", animal =>
|
||||||
{
|
{
|
||||||
animal.SetDescription("The animal command.");
|
animal.SetDescription("The animal command.");
|
||||||
|
|
||||||
// Show all examples defined on the direct children
|
// Show all examples defined on the direct children
|
||||||
configurator.Settings.MaximumIndirectExamples = int.MaxValue;
|
configurator.Settings.MaximumIndirectExamples = int.MaxValue;
|
||||||
|
|
||||||
animal.AddCommand<DogCommand>("dog")
|
animal.AddCommand<DogCommand>("dog")
|
||||||
.WithExample("animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
.WithExample("animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
||||||
.WithExample("animal", "dog", "--name", "Luna")
|
.WithExample("animal", "dog", "--name", "Luna")
|
||||||
.WithExample("animal", "dog", "--name", "Charlie")
|
.WithExample("animal", "dog", "--name", "Charlie")
|
||||||
.WithExample("animal", "dog", "--name", "Bella")
|
.WithExample("animal", "dog", "--name", "Bella")
|
||||||
.WithExample("animal", "dog", "--name", "Daisy")
|
.WithExample("animal", "dog", "--name", "Daisy")
|
||||||
.WithExample("animal", "dog", "--name", "Milo");
|
.WithExample("animal", "dog", "--name", "Milo");
|
||||||
|
|
||||||
animal.AddCommand<HorseCommand>("horse")
|
animal.AddCommand<HorseCommand>("horse")
|
||||||
.WithExample("animal", "horse", "--name", "Brutus")
|
.WithExample("animal", "horse", "--name", "Brutus")
|
||||||
.WithExample("animal", "horse", "--name", "Sugar", "--IsAlive", "false")
|
.WithExample("animal", "horse", "--name", "Sugar", "--IsAlive", "false")
|
||||||
.WithExample("animal", "horse", "--name", "Cash")
|
.WithExample("animal", "horse", "--name", "Cash")
|
||||||
.WithExample("animal", "horse", "--name", "Dakota")
|
.WithExample("animal", "horse", "--name", "Dakota")
|
||||||
.WithExample("animal", "horse", "--name", "Cisco")
|
.WithExample("animal", "horse", "--name", "Cisco")
|
||||||
.WithExample("animal", "horse", "--name", "Spirit");
|
.WithExample("animal", "horse", "--name", "Spirit");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -686,10 +686,10 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Root_Examples_Leafs_None")]
|
[Expectation("Root_Examples_Leafs_None")]
|
||||||
public Task Should_Not_Output_Examples_Defined_On_Leaves_If_No_Other_Examples_Are_Found()
|
public Task Should_Not_Output_Examples_Defined_On_Leaves_If_No_Other_Examples_Are_Found()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
@ -699,25 +699,25 @@ public sealed partial class CommandAppTests
|
|||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
configurator.AddBranch<AnimalSettings>("animal", animal =>
|
configurator.AddBranch<AnimalSettings>("animal", animal =>
|
||||||
{
|
{
|
||||||
animal.SetDescription("The animal command.");
|
animal.SetDescription("The animal command.");
|
||||||
|
|
||||||
// Do not show examples defined on the direct children
|
// Do not show examples defined on the direct children
|
||||||
configurator.Settings.MaximumIndirectExamples = 0;
|
configurator.Settings.MaximumIndirectExamples = 0;
|
||||||
|
|
||||||
animal.AddCommand<DogCommand>("dog")
|
animal.AddCommand<DogCommand>("dog")
|
||||||
.WithExample("animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
.WithExample("animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy")
|
||||||
.WithExample("animal", "dog", "--name", "Luna")
|
.WithExample("animal", "dog", "--name", "Luna")
|
||||||
.WithExample("animal", "dog", "--name", "Charlie")
|
.WithExample("animal", "dog", "--name", "Charlie")
|
||||||
.WithExample("animal", "dog", "--name", "Bella")
|
.WithExample("animal", "dog", "--name", "Bella")
|
||||||
.WithExample("animal", "dog", "--name", "Daisy")
|
.WithExample("animal", "dog", "--name", "Daisy")
|
||||||
.WithExample("animal", "dog", "--name", "Milo");
|
.WithExample("animal", "dog", "--name", "Milo");
|
||||||
|
|
||||||
animal.AddCommand<HorseCommand>("horse")
|
animal.AddCommand<HorseCommand>("horse")
|
||||||
.WithExample("animal", "horse", "--name", "Brutus")
|
.WithExample("animal", "horse", "--name", "Brutus")
|
||||||
.WithExample("animal", "horse", "--name", "Sugar", "--IsAlive", "false")
|
.WithExample("animal", "horse", "--name", "Sugar", "--IsAlive", "false")
|
||||||
.WithExample("animal", "horse", "--name", "Cash")
|
.WithExample("animal", "horse", "--name", "Cash")
|
||||||
.WithExample("animal", "horse", "--name", "Dakota")
|
.WithExample("animal", "horse", "--name", "Dakota")
|
||||||
.WithExample("animal", "horse", "--name", "Cisco")
|
.WithExample("animal", "horse", "--name", "Cisco")
|
||||||
.WithExample("animal", "horse", "--name", "Spirit");
|
.WithExample("animal", "horse", "--name", "Spirit");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -737,23 +737,23 @@ public sealed partial class CommandAppTests
|
|||||||
var fixture = new CommandAppTester();
|
var fixture = new CommandAppTester();
|
||||||
fixture.Configure(configurator =>
|
fixture.Configure(configurator =>
|
||||||
{
|
{
|
||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
configurator.AddBranch<AnimalSettings>("animal", animal =>
|
configurator.AddBranch<AnimalSettings>("animal", animal =>
|
||||||
{
|
{
|
||||||
animal.SetDescription("The animal command.");
|
animal.SetDescription("The animal command.");
|
||||||
|
|
||||||
// All branch examples should be shown
|
// All branch examples should be shown
|
||||||
animal.AddExample("animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy");
|
animal.AddExample("animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy");
|
||||||
animal.AddExample("animal", "dog", "--name", "Luna");
|
animal.AddExample("animal", "dog", "--name", "Luna");
|
||||||
animal.AddExample("animal", "dog", "--name", "Charlie");
|
animal.AddExample("animal", "dog", "--name", "Charlie");
|
||||||
animal.AddExample("animal", "dog", "--name", "Bella");
|
animal.AddExample("animal", "dog", "--name", "Bella");
|
||||||
animal.AddExample("animal", "dog", "--name", "Daisy");
|
animal.AddExample("animal", "dog", "--name", "Daisy");
|
||||||
animal.AddExample("animal", "dog", "--name", "Milo");
|
animal.AddExample("animal", "dog", "--name", "Milo");
|
||||||
animal.AddExample("animal", "horse", "--name", "Brutus");
|
animal.AddExample("animal", "horse", "--name", "Brutus");
|
||||||
animal.AddExample("animal", "horse", "--name", "Sugar", "--IsAlive", "false");
|
animal.AddExample("animal", "horse", "--name", "Sugar", "--IsAlive", "false");
|
||||||
animal.AddExample("animal", "horse", "--name", "Cash");
|
animal.AddExample("animal", "horse", "--name", "Cash");
|
||||||
animal.AddExample("animal", "horse", "--name", "Dakota");
|
animal.AddExample("animal", "horse", "--name", "Dakota");
|
||||||
animal.AddExample("animal", "horse", "--name", "Cisco");
|
animal.AddExample("animal", "horse", "--name", "Cisco");
|
||||||
animal.AddExample("animal", "horse", "--name", "Spirit");
|
animal.AddExample("animal", "horse", "--name", "Spirit");
|
||||||
|
|
||||||
animal.AddCommand<DogCommand>("dog")
|
animal.AddCommand<DogCommand>("dog")
|
||||||
@ -768,7 +768,7 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Default_Examples")]
|
[Expectation("Default_Examples")]
|
||||||
@ -780,13 +780,13 @@ public sealed partial class CommandAppTests
|
|||||||
fixture.Configure(configurator =>
|
fixture.Configure(configurator =>
|
||||||
{
|
{
|
||||||
configurator.SetApplicationName("myapp");
|
configurator.SetApplicationName("myapp");
|
||||||
|
|
||||||
// All root examples should be shown
|
// All root examples should be shown
|
||||||
configurator.AddExample("--name", "Rufus", "--age", "12", "--good-boy");
|
configurator.AddExample("--name", "Rufus", "--age", "12", "--good-boy");
|
||||||
configurator.AddExample("--name", "Luna");
|
configurator.AddExample("--name", "Luna");
|
||||||
configurator.AddExample("--name", "Charlie");
|
configurator.AddExample("--name", "Charlie");
|
||||||
configurator.AddExample("--name", "Bella");
|
configurator.AddExample("--name", "Bella");
|
||||||
configurator.AddExample("--name", "Daisy");
|
configurator.AddExample("--name", "Daisy");
|
||||||
configurator.AddExample("--name", "Milo");
|
configurator.AddExample("--name", "Milo");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -352,8 +352,8 @@ public sealed partial class CommandAppTests
|
|||||||
var result = app.Run("dog", "-u");
|
var result = app.Run("dog", "-u");
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(result.Output);
|
return Verifier.Verify(result.Output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[UsesVerify]
|
[UsesVerify]
|
||||||
@ -584,7 +584,7 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Output.ShouldBe("Error: Command 'dog' is missing required argument 'AGE'.");
|
result.Output.ShouldBe("Error: Command 'dog' is missing required argument 'AGE'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,16 @@ namespace Spectre.Console.Tests.Unit.Cli;
|
|||||||
public sealed partial class CommandAppTests
|
public sealed partial class CommandAppTests
|
||||||
{
|
{
|
||||||
public sealed class Remaining
|
public sealed class Remaining
|
||||||
{
|
{
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("-a")]
|
[InlineData("-a")]
|
||||||
[InlineData("--alive")]
|
[InlineData("--alive")]
|
||||||
public void Should_Not_Add_Known_Flags_To_Remaining_Arguments_RelaxedParsing(string knownFlag)
|
public void Should_Not_Add_Known_Flags_To_Remaining_Arguments_RelaxedParsing(string knownFlag)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddCommand<DogCommand>("dog");
|
config.AddCommand<DogCommand>("dog");
|
||||||
});
|
});
|
||||||
@ -20,29 +20,29 @@ public sealed partial class CommandAppTests
|
|||||||
// When
|
// When
|
||||||
var result = app.Run(new[]
|
var result = app.Run(new[]
|
||||||
{
|
{
|
||||||
"dog", "12", "4",
|
"dog", "12", "4",
|
||||||
knownFlag,
|
knownFlag,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
|
||||||
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
|
|
||||||
{
|
|
||||||
dog.IsAlive.ShouldBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
result.Context.Remaining.Parsed.Count.ShouldBe(0);
|
// Then
|
||||||
|
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
|
||||||
|
{
|
||||||
|
dog.IsAlive.ShouldBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
result.Context.Remaining.Parsed.Count.ShouldBe(0);
|
||||||
result.Context.Remaining.Raw.Count.ShouldBe(0);
|
result.Context.Remaining.Raw.Count.ShouldBe(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("-r")]
|
[InlineData("-r")]
|
||||||
[InlineData("--romeo")]
|
[InlineData("--romeo")]
|
||||||
public void Should_Add_Unknown_Flags_To_Remaining_Arguments_RelaxedParsing(string unknownFlag)
|
public void Should_Add_Unknown_Flags_To_Remaining_Arguments_RelaxedParsing(string unknownFlag)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddCommand<DogCommand>("dog");
|
config.AddCommand<DogCommand>("dog");
|
||||||
});
|
});
|
||||||
@ -50,23 +50,23 @@ public sealed partial class CommandAppTests
|
|||||||
// When
|
// When
|
||||||
var result = app.Run(new[]
|
var result = app.Run(new[]
|
||||||
{
|
{
|
||||||
"dog", "12", "4",
|
"dog", "12", "4",
|
||||||
unknownFlag,
|
unknownFlag,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Context.Remaining.Parsed.Count.ShouldBe(1);
|
result.Context.Remaining.Parsed.Count.ShouldBe(1);
|
||||||
result.Context.ShouldHaveRemainingArgument(unknownFlag.TrimStart('-'), values: new[] { (string)null });
|
result.Context.ShouldHaveRemainingArgument(unknownFlag.TrimStart('-'), values: new[] { (string)null });
|
||||||
result.Context.Remaining.Raw.Count.ShouldBe(0);
|
result.Context.Remaining.Raw.Count.ShouldBe(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Add_Unknown_Flags_When_Grouped_To_Remaining_Arguments_RelaxedParsing()
|
public void Should_Add_Unknown_Flags_When_Grouped_To_Remaining_Arguments_RelaxedParsing()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddCommand<DogCommand>("dog");
|
config.AddCommand<DogCommand>("dog");
|
||||||
});
|
});
|
||||||
@ -74,25 +74,25 @@ public sealed partial class CommandAppTests
|
|||||||
// When
|
// When
|
||||||
var result = app.Run(new[]
|
var result = app.Run(new[]
|
||||||
{
|
{
|
||||||
"dog", "12", "4",
|
"dog", "12", "4",
|
||||||
"-agr",
|
"-agr",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Context.Remaining.Parsed.Count.ShouldBe(1);
|
result.Context.Remaining.Parsed.Count.ShouldBe(1);
|
||||||
result.Context.ShouldHaveRemainingArgument("r", values: new[] { (string)null });
|
result.Context.ShouldHaveRemainingArgument("r", values: new[] { (string)null });
|
||||||
result.Context.Remaining.Raw.Count.ShouldBe(0);
|
result.Context.Remaining.Raw.Count.ShouldBe(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("-a")]
|
[InlineData("-a")]
|
||||||
[InlineData("--alive")]
|
[InlineData("--alive")]
|
||||||
public void Should_Not_Add_Known_Flags_To_Remaining_Arguments_StrictParsing(string knownFlag)
|
public void Should_Not_Add_Known_Flags_To_Remaining_Arguments_StrictParsing(string knownFlag)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.UseStrictParsing();
|
config.UseStrictParsing();
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddCommand<DogCommand>("dog");
|
config.AddCommand<DogCommand>("dog");
|
||||||
@ -101,68 +101,68 @@ public sealed partial class CommandAppTests
|
|||||||
// When
|
// When
|
||||||
var result = app.Run(new[]
|
var result = app.Run(new[]
|
||||||
{
|
{
|
||||||
"dog", "12", "4",
|
"dog", "12", "4",
|
||||||
knownFlag,
|
knownFlag,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Context.Remaining.Parsed.Count.ShouldBe(0);
|
result.Context.Remaining.Parsed.Count.ShouldBe(0);
|
||||||
result.Context.Remaining.Raw.Count.ShouldBe(0);
|
result.Context.Remaining.Raw.Count.ShouldBe(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("-r")]
|
[InlineData("-r")]
|
||||||
[InlineData("--romeo")]
|
[InlineData("--romeo")]
|
||||||
public void Should_Not_Add_Unknown_Flags_To_Remaining_Arguments_StrictParsing(string unknownFlag)
|
public void Should_Not_Add_Unknown_Flags_To_Remaining_Arguments_StrictParsing(string unknownFlag)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.UseStrictParsing();
|
config.UseStrictParsing();
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddCommand<DogCommand>("dog");
|
config.AddCommand<DogCommand>("dog");
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = Record.Exception(() => app.Run(new[]
|
var result = Record.Exception(() => app.Run(new[]
|
||||||
{
|
{
|
||||||
"dog", "12", "4",
|
"dog", "12", "4",
|
||||||
unknownFlag,
|
unknownFlag,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
||||||
{
|
{
|
||||||
ex.Message.ShouldBe($"Unknown option '{unknownFlag.TrimStart('-')}'.");
|
ex.Message.ShouldBe($"Unknown option '{unknownFlag.TrimStart('-')}'.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Not_Add_Unknown_Flags_When_Grouped_To_Remaining_Arguments_StrictParsing()
|
public void Should_Not_Add_Unknown_Flags_When_Grouped_To_Remaining_Arguments_StrictParsing()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.UseStrictParsing();
|
config.UseStrictParsing();
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddCommand<DogCommand>("dog");
|
config.AddCommand<DogCommand>("dog");
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = Record.Exception(() => app.Run(new[]
|
var result = Record.Exception(() => app.Run(new[]
|
||||||
{
|
{
|
||||||
"dog", "12", "4",
|
"dog", "12", "4",
|
||||||
"-agr",
|
"-agr",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
||||||
{
|
{
|
||||||
ex.Message.ShouldBe($"Unknown option 'r'.");
|
ex.Message.ShouldBe($"Unknown option 'r'.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Register_Remaining_Parsed_Arguments_With_Context()
|
public void Should_Register_Remaining_Parsed_Arguments_With_Context()
|
||||||
@ -254,19 +254,19 @@ public sealed partial class CommandAppTests
|
|||||||
result.Context.Remaining.Raw[0].ShouldBe("/c");
|
result.Context.Remaining.Raw[0].ShouldBe("/c");
|
||||||
result.Context.Remaining.Raw[1].ShouldBe("\"set && pause\"");
|
result.Context.Remaining.Raw[1].ShouldBe("\"set && pause\"");
|
||||||
result.Context.Remaining.Raw[2].ShouldBe("Name=\" -Rufus --' ");
|
result.Context.Remaining.Raw[2].ShouldBe("Name=\" -Rufus --' ");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(true)]
|
[InlineData(true)]
|
||||||
[InlineData(false)]
|
[InlineData(false)]
|
||||||
public void Should_Convert_Flags_To_Remaining_Arguments_If_Cannot_Be_Assigned(bool useStrictParsing)
|
public void Should_Convert_Flags_To_Remaining_Arguments_If_Cannot_Be_Assigned(bool useStrictParsing)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.Settings.ConvertFlagsToRemainingArguments = true;
|
config.Settings.ConvertFlagsToRemainingArguments = true;
|
||||||
config.Settings.StrictParsing = useStrictParsing;
|
config.Settings.StrictParsing = useStrictParsing;
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddCommand<DogCommand>("dog");
|
config.AddCommand<DogCommand>("dog");
|
||||||
});
|
});
|
||||||
@ -280,8 +280,8 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Context.Remaining.Parsed.Count.ShouldBe(1);
|
result.Context.Remaining.Parsed.Count.ShouldBe(1);
|
||||||
result.Context.ShouldHaveRemainingArgument("good-boy", values: new[] { "Please be good Rufus!" });
|
result.Context.ShouldHaveRemainingArgument("good-boy", values: new[] { "Please be good Rufus!" });
|
||||||
|
|
||||||
result.Context.Remaining.Raw.Count.ShouldBe(0); // nb. there are no "raw" remaining arguments on the command line
|
result.Context.Remaining.Raw.Count.ShouldBe(0); // nb. there are no "raw" remaining arguments on the command line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Output.ShouldStartWith("Spectre.Cli version ");
|
result.Output.ShouldStartWith("Spectre.Cli version ");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Output_Application_Version_To_The_Console_With_No_Command()
|
public void Should_Output_Application_Version_To_The_Console_With_No_Command()
|
||||||
{
|
{
|
||||||
@ -24,7 +24,7 @@ public sealed partial class CommandAppTests
|
|||||||
var fixture = new CommandAppTester();
|
var fixture = new CommandAppTester();
|
||||||
fixture.Configure(configurator =>
|
fixture.Configure(configurator =>
|
||||||
{
|
{
|
||||||
configurator.SetApplicationVersion("1.0");
|
configurator.SetApplicationVersion("1.0");
|
||||||
});
|
});
|
||||||
|
|
||||||
// When
|
// When
|
||||||
@ -32,8 +32,8 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Output.ShouldBe("1.0");
|
result.Output.ShouldBe("1.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Output_Application_Version_To_The_Console_With_Command()
|
public void Should_Output_Application_Version_To_The_Console_With_Command()
|
||||||
{
|
{
|
||||||
@ -41,8 +41,8 @@ public sealed partial class CommandAppTests
|
|||||||
var fixture = new CommandAppTester();
|
var fixture = new CommandAppTester();
|
||||||
fixture.Configure(configurator =>
|
fixture.Configure(configurator =>
|
||||||
{
|
{
|
||||||
configurator.SetApplicationVersion("1.0");
|
configurator.SetApplicationVersion("1.0");
|
||||||
|
|
||||||
configurator.AddCommand<EmptyCommand>("empty");
|
configurator.AddCommand<EmptyCommand>("empty");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -51,8 +51,8 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Output.ShouldBe("1.0");
|
result.Output.ShouldBe("1.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Output_Application_Version_To_The_Console_With_Default_Command()
|
public void Should_Output_Application_Version_To_The_Console_With_Default_Command()
|
||||||
{
|
{
|
||||||
@ -69,8 +69,8 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Output.ShouldBe("1.0");
|
result.Output.ShouldBe("1.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Output_Application_Version_To_The_Console_With_Branch_Default_Command()
|
public void Should_Output_Application_Version_To_The_Console_With_Branch_Default_Command()
|
||||||
{
|
{
|
||||||
@ -78,11 +78,11 @@ public sealed partial class CommandAppTests
|
|||||||
var fixture = new CommandAppTester();
|
var fixture = new CommandAppTester();
|
||||||
fixture.Configure(configurator =>
|
fixture.Configure(configurator =>
|
||||||
{
|
{
|
||||||
configurator.SetApplicationVersion("1.0");
|
configurator.SetApplicationVersion("1.0");
|
||||||
|
|
||||||
configurator.AddBranch<EmptyCommandSettings>("branch", branch =>
|
configurator.AddBranch<EmptyCommandSettings>("branch", branch =>
|
||||||
{
|
{
|
||||||
branch.SetDefaultCommand<EmptyCommand>();
|
branch.SetDefaultCommand<EmptyCommand>();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1041,66 +1041,66 @@ public sealed partial class CommandAppTests
|
|||||||
// Then
|
// Then
|
||||||
result.Context.ShouldNotBeNull();
|
result.Context.ShouldNotBeNull();
|
||||||
result.Context.Data.ShouldBe(123);
|
result.Context.Data.ShouldBe(123);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class Default_Command
|
public sealed class Default_Command
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Be_Able_To_Set_The_Default_Command()
|
public void Should_Be_Able_To_Set_The_Default_Command()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandAppTester();
|
var app = new CommandAppTester();
|
||||||
app.SetDefaultCommand<DogCommand>();
|
app.SetDefaultCommand<DogCommand>();
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = app.Run(new[]
|
var result = app.Run(new[]
|
||||||
{
|
{
|
||||||
"4", "12", "--good-boy", "--name", "Rufus",
|
"4", "12", "--good-boy", "--name", "Rufus",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ExitCode.ShouldBe(0);
|
result.ExitCode.ShouldBe(0);
|
||||||
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
|
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
|
||||||
{
|
{
|
||||||
dog.Legs.ShouldBe(4);
|
dog.Legs.ShouldBe(4);
|
||||||
dog.Age.ShouldBe(12);
|
dog.Age.ShouldBe(12);
|
||||||
dog.GoodBoy.ShouldBe(true);
|
dog.GoodBoy.ShouldBe(true);
|
||||||
dog.Name.ShouldBe("Rufus");
|
dog.Name.ShouldBe("Rufus");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Set_The_Default_Command_Description_Data_CommandApp()
|
public void Should_Set_The_Default_Command_Description_Data_CommandApp()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandApp();
|
var app = new CommandApp();
|
||||||
app.SetDefaultCommand<DogCommand>()
|
app.SetDefaultCommand<DogCommand>()
|
||||||
.WithDescription("The default command")
|
.WithDescription("The default command")
|
||||||
.WithData(new string[] { "foo", "bar" });
|
.WithData(new string[] { "foo", "bar" });
|
||||||
|
|
||||||
// When
|
// When
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
app.GetConfigurator().DefaultCommand.ShouldNotBeNull();
|
app.GetConfigurator().DefaultCommand.ShouldNotBeNull();
|
||||||
app.GetConfigurator().DefaultCommand.Description.ShouldBe("The default command");
|
app.GetConfigurator().DefaultCommand.Description.ShouldBe("The default command");
|
||||||
app.GetConfigurator().DefaultCommand.Data.ShouldBe(new string[] { "foo", "bar" });
|
app.GetConfigurator().DefaultCommand.Data.ShouldBe(new string[] { "foo", "bar" });
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Set_The_Default_Command_Description_Data_CommandAppOfT()
|
public void Should_Set_The_Default_Command_Description_Data_CommandAppOfT()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var app = new CommandApp<DogCommand>()
|
var app = new CommandApp<DogCommand>()
|
||||||
.WithDescription("The default command")
|
.WithDescription("The default command")
|
||||||
.WithData(new string[] { "foo", "bar" });
|
.WithData(new string[] { "foo", "bar" });
|
||||||
|
|
||||||
// When
|
// When
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
app.GetConfigurator().DefaultCommand.ShouldNotBeNull();
|
app.GetConfigurator().DefaultCommand.ShouldNotBeNull();
|
||||||
app.GetConfigurator().DefaultCommand.Description.ShouldBe("The default command");
|
app.GetConfigurator().DefaultCommand.Description.ShouldBe("The default command");
|
||||||
app.GetConfigurator().DefaultCommand.Data.ShouldBe(new string[] { "foo", "bar" });
|
app.GetConfigurator().DefaultCommand.Data.ShouldBe(new string[] { "foo", "bar" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class Delegate_Commands
|
public sealed class Delegate_Commands
|
||||||
@ -1114,7 +1114,7 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
var app = new CommandApp();
|
var app = new CommandApp();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddDelegate<DogSettings>(
|
config.AddDelegate<DogSettings>(
|
||||||
"foo", (context, settings) =>
|
"foo", (context, settings) =>
|
||||||
@ -1134,8 +1134,8 @@ public sealed partial class CommandAppTests
|
|||||||
dog.Age.ShouldBe(12);
|
dog.Age.ShouldBe(12);
|
||||||
dog.Legs.ShouldBe(4);
|
dog.Legs.ShouldBe(4);
|
||||||
data.ShouldBe(2);
|
data.ShouldBe(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void Should_Execute_Async_Delegate_Command_At_Root_Level()
|
public async void Should_Execute_Async_Delegate_Command_At_Root_Level()
|
||||||
{
|
{
|
||||||
@ -1145,7 +1145,7 @@ public sealed partial class CommandAppTests
|
|||||||
|
|
||||||
var app = new CommandApp();
|
var app = new CommandApp();
|
||||||
app.Configure(config =>
|
app.Configure(config =>
|
||||||
{
|
{
|
||||||
config.PropagateExceptions();
|
config.PropagateExceptions();
|
||||||
config.AddAsyncDelegate<DogSettings>(
|
config.AddAsyncDelegate<DogSettings>(
|
||||||
"foo", (context, settings) =>
|
"foo", (context, settings) =>
|
||||||
@ -1199,8 +1199,8 @@ public sealed partial class CommandAppTests
|
|||||||
dog.Age.ShouldBe(12);
|
dog.Age.ShouldBe(12);
|
||||||
dog.Legs.ShouldBe(4);
|
dog.Legs.ShouldBe(4);
|
||||||
data.ShouldBe(2);
|
data.ShouldBe(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void Should_Execute_Nested_Async_Delegate_Command()
|
public async void Should_Execute_Nested_Async_Delegate_Command()
|
||||||
{
|
{
|
||||||
|
@ -1,314 +1,314 @@
|
|||||||
namespace Spectre.Console.Tests.Unit.Cli.Parsing;
|
namespace Spectre.Console.Tests.Unit.Cli.Parsing;
|
||||||
|
|
||||||
public class CommandTreeTokenizerTests
|
public class CommandTreeTokenizerTests
|
||||||
{
|
{
|
||||||
public sealed class ScanString
|
public sealed class ScanString
|
||||||
{
|
{
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("")]
|
[InlineData("")]
|
||||||
[InlineData(" ")]
|
[InlineData(" ")]
|
||||||
[InlineData(" ")]
|
[InlineData(" ")]
|
||||||
[InlineData("\t")]
|
[InlineData("\t")]
|
||||||
[InlineData("\r\n\t")]
|
[InlineData("\r\n\t")]
|
||||||
[InlineData("👋🏻")]
|
[InlineData("👋🏻")]
|
||||||
[InlineData("🐎👋🏻🔥❤️")]
|
[InlineData("🐎👋🏻🔥❤️")]
|
||||||
[InlineData("\"🐎👋🏻🔥❤️\" is an emoji sequence")]
|
[InlineData("\"🐎👋🏻🔥❤️\" is an emoji sequence")]
|
||||||
public void Should_Preserve_Edgecase_Inputs(string actualAndExpected)
|
public void Should_Preserve_Edgecase_Inputs(string actualAndExpected)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = CommandTreeTokenizer.Tokenize(new string[] { actualAndExpected });
|
var result = CommandTreeTokenizer.Tokenize(new string[] { actualAndExpected });
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Tokens.Count.ShouldBe(1);
|
result.Tokens.Count.ShouldBe(1);
|
||||||
result.Tokens[0].Value.ShouldBe(actualAndExpected);
|
result.Tokens[0].Value.ShouldBe(actualAndExpected);
|
||||||
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
||||||
// Double-quote handling
|
// Double-quote handling
|
||||||
[InlineData("\"")]
|
[InlineData("\"")]
|
||||||
[InlineData("\"\"")]
|
[InlineData("\"\"")]
|
||||||
[InlineData("\"Rufus\"")]
|
[InlineData("\"Rufus\"")]
|
||||||
[InlineData("\" Rufus\"")]
|
[InlineData("\" Rufus\"")]
|
||||||
[InlineData("\"-R\"")]
|
[InlineData("\"-R\"")]
|
||||||
[InlineData("\"-Rufus\"")]
|
[InlineData("\"-Rufus\"")]
|
||||||
[InlineData("\" -Rufus\"")]
|
[InlineData("\" -Rufus\"")]
|
||||||
|
|
||||||
// Single-quote handling
|
// Single-quote handling
|
||||||
[InlineData("'")]
|
[InlineData("'")]
|
||||||
[InlineData("''")]
|
[InlineData("''")]
|
||||||
[InlineData("'Rufus'")]
|
[InlineData("'Rufus'")]
|
||||||
[InlineData("' Rufus'")]
|
[InlineData("' Rufus'")]
|
||||||
[InlineData("'-R'")]
|
[InlineData("'-R'")]
|
||||||
[InlineData("'-Rufus'")]
|
[InlineData("'-Rufus'")]
|
||||||
[InlineData("' -Rufus'")]
|
[InlineData("' -Rufus'")]
|
||||||
public void Should_Preserve_Quotes(string actualAndExpected)
|
public void Should_Preserve_Quotes(string actualAndExpected)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = CommandTreeTokenizer.Tokenize(new string[] { actualAndExpected });
|
var result = CommandTreeTokenizer.Tokenize(new string[] { actualAndExpected });
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Tokens.Count.ShouldBe(1);
|
result.Tokens.Count.ShouldBe(1);
|
||||||
result.Tokens[0].Value.ShouldBe(actualAndExpected);
|
result.Tokens[0].Value.ShouldBe(actualAndExpected);
|
||||||
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("Rufus-")]
|
[InlineData("Rufus-")]
|
||||||
[InlineData("Rufus--")]
|
[InlineData("Rufus--")]
|
||||||
[InlineData("R-u-f-u-s")]
|
[InlineData("R-u-f-u-s")]
|
||||||
public void Should_Preserve_Hyphen_Delimiters(string actualAndExpected)
|
public void Should_Preserve_Hyphen_Delimiters(string actualAndExpected)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = CommandTreeTokenizer.Tokenize(new string[] { actualAndExpected });
|
var result = CommandTreeTokenizer.Tokenize(new string[] { actualAndExpected });
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Tokens.Count.ShouldBe(1);
|
result.Tokens.Count.ShouldBe(1);
|
||||||
result.Tokens[0].Value.ShouldBe(actualAndExpected);
|
result.Tokens[0].Value.ShouldBe(actualAndExpected);
|
||||||
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(" Rufus")]
|
[InlineData(" Rufus")]
|
||||||
[InlineData("Rufus ")]
|
[InlineData("Rufus ")]
|
||||||
[InlineData(" Rufus ")]
|
[InlineData(" Rufus ")]
|
||||||
public void Should_Preserve_Spaces(string actualAndExpected)
|
public void Should_Preserve_Spaces(string actualAndExpected)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = CommandTreeTokenizer.Tokenize(new string[] { actualAndExpected });
|
var result = CommandTreeTokenizer.Tokenize(new string[] { actualAndExpected });
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Tokens.Count.ShouldBe(1);
|
result.Tokens.Count.ShouldBe(1);
|
||||||
result.Tokens[0].Value.ShouldBe(actualAndExpected);
|
result.Tokens[0].Value.ShouldBe(actualAndExpected);
|
||||||
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(" \" -Rufus -- ")]
|
[InlineData(" \" -Rufus -- ")]
|
||||||
[InlineData("Name=\" -Rufus --' ")]
|
[InlineData("Name=\" -Rufus --' ")]
|
||||||
public void Should_Preserve_Quotes_Hyphen_Delimiters_Spaces(string actualAndExpected)
|
public void Should_Preserve_Quotes_Hyphen_Delimiters_Spaces(string actualAndExpected)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = CommandTreeTokenizer.Tokenize(new string[] { actualAndExpected });
|
var result = CommandTreeTokenizer.Tokenize(new string[] { actualAndExpected });
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Tokens.Count.ShouldBe(1);
|
result.Tokens.Count.ShouldBe(1);
|
||||||
result.Tokens[0].Value.ShouldBe(actualAndExpected);
|
result.Tokens[0].Value.ShouldBe(actualAndExpected);
|
||||||
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ScanLongOption
|
public sealed class ScanLongOption
|
||||||
{
|
{
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("--Name-", "Name-")]
|
[InlineData("--Name-", "Name-")]
|
||||||
[InlineData("--Name_", "Name_")]
|
[InlineData("--Name_", "Name_")]
|
||||||
public void Should_Allow_Hyphens_And_Underscores_In_Option_Name(string actual, string expected)
|
public void Should_Allow_Hyphens_And_Underscores_In_Option_Name(string actual, string expected)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = CommandTreeTokenizer.Tokenize(new string[] { actual });
|
var result = CommandTreeTokenizer.Tokenize(new string[] { actual });
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Tokens.Count.ShouldBe(1);
|
result.Tokens.Count.ShouldBe(1);
|
||||||
result.Tokens[0].Value.ShouldBe(expected);
|
result.Tokens[0].Value.ShouldBe(expected);
|
||||||
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.LongOption);
|
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.LongOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("-- ")]
|
[InlineData("-- ")]
|
||||||
[InlineData("--Name ")]
|
[InlineData("--Name ")]
|
||||||
[InlineData("--Name\"")]
|
[InlineData("--Name\"")]
|
||||||
[InlineData("--Nam\"e")]
|
[InlineData("--Nam\"e")]
|
||||||
public void Should_Throw_On_Invalid_Option_Name(string actual)
|
public void Should_Throw_On_Invalid_Option_Name(string actual)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = Record.Exception(() => CommandTreeTokenizer.Tokenize(new string[] { actual }));
|
var result = Record.Exception(() => CommandTreeTokenizer.Tokenize(new string[] { actual }));
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
||||||
{
|
{
|
||||||
ex.Message.ShouldBe("Invalid long option name.");
|
ex.Message.ShouldBe("Invalid long option name.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ScanShortOptions
|
public sealed class ScanShortOptions
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Accept_Option_Without_Value()
|
public void Should_Accept_Option_Without_Value()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = CommandTreeTokenizer.Tokenize(new[] { "-a" });
|
var result = CommandTreeTokenizer.Tokenize(new[] { "-a" });
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Remaining.ShouldBeEmpty();
|
result.Remaining.ShouldBeEmpty();
|
||||||
result.Tokens.ShouldHaveSingleItem();
|
result.Tokens.ShouldHaveSingleItem();
|
||||||
|
|
||||||
var t = result.Tokens[0];
|
var t = result.Tokens[0];
|
||||||
t.TokenKind.ShouldBe(CommandTreeToken.Kind.ShortOption);
|
t.TokenKind.ShouldBe(CommandTreeToken.Kind.ShortOption);
|
||||||
t.IsGrouped.ShouldBe(false);
|
t.IsGrouped.ShouldBe(false);
|
||||||
t.Position.ShouldBe(0);
|
t.Position.ShouldBe(0);
|
||||||
t.Value.ShouldBe("a");
|
t.Value.ShouldBe("a");
|
||||||
t.Representation.ShouldBe("-a");
|
t.Representation.ShouldBe("-a");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("-a:foo")]
|
[InlineData("-a:foo")]
|
||||||
[InlineData("-a=foo")]
|
[InlineData("-a=foo")]
|
||||||
public void Should_Accept_Option_With_Value(string param)
|
public void Should_Accept_Option_With_Value(string param)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = CommandTreeTokenizer.Tokenize(new[] { param });
|
var result = CommandTreeTokenizer.Tokenize(new[] { param });
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Remaining.ShouldBeEmpty();
|
result.Remaining.ShouldBeEmpty();
|
||||||
result.Tokens.Count.ShouldBe(2);
|
result.Tokens.Count.ShouldBe(2);
|
||||||
|
|
||||||
var t = result.Tokens.Consume();
|
var t = result.Tokens.Consume();
|
||||||
t.TokenKind.ShouldBe(CommandTreeToken.Kind.ShortOption);
|
t.TokenKind.ShouldBe(CommandTreeToken.Kind.ShortOption);
|
||||||
t.IsGrouped.ShouldBe(false);
|
t.IsGrouped.ShouldBe(false);
|
||||||
t.Position.ShouldBe(0);
|
t.Position.ShouldBe(0);
|
||||||
t.Value.ShouldBe("a");
|
t.Value.ShouldBe("a");
|
||||||
t.Representation.ShouldBe("-a");
|
t.Representation.ShouldBe("-a");
|
||||||
|
|
||||||
t = result.Tokens.Consume();
|
t = result.Tokens.Consume();
|
||||||
t.TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
t.TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
||||||
t.IsGrouped.ShouldBe(false);
|
t.IsGrouped.ShouldBe(false);
|
||||||
t.Position.ShouldBe(3);
|
t.Position.ShouldBe(3);
|
||||||
t.Value.ShouldBe("foo");
|
t.Value.ShouldBe("foo");
|
||||||
t.Representation.ShouldBe("foo");
|
t.Representation.ShouldBe("foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
||||||
// Positive values
|
// Positive values
|
||||||
[InlineData("-a:1.5", null, "1.5")]
|
[InlineData("-a:1.5", null, "1.5")]
|
||||||
[InlineData("-a=1.5", null, "1.5")]
|
[InlineData("-a=1.5", null, "1.5")]
|
||||||
[InlineData("-a", "1.5", "1.5")]
|
[InlineData("-a", "1.5", "1.5")]
|
||||||
|
|
||||||
// Negative values
|
// Negative values
|
||||||
[InlineData("-a:-1.5", null, "-1.5")]
|
[InlineData("-a:-1.5", null, "-1.5")]
|
||||||
[InlineData("-a=-1.5", null, "-1.5")]
|
[InlineData("-a=-1.5", null, "-1.5")]
|
||||||
[InlineData("-a", "-1.5", "-1.5")]
|
[InlineData("-a", "-1.5", "-1.5")]
|
||||||
public void Should_Accept_Option_With_Numeric_Value(string firstArg, string secondArg, string expectedValue)
|
public void Should_Accept_Option_With_Numeric_Value(string firstArg, string secondArg, string expectedValue)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
List<string> args = new List<string>();
|
List<string> args = new List<string>();
|
||||||
args.Add(firstArg);
|
args.Add(firstArg);
|
||||||
if (secondArg != null)
|
if (secondArg != null)
|
||||||
{
|
{
|
||||||
args.Add(secondArg);
|
args.Add(secondArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = CommandTreeTokenizer.Tokenize(args);
|
var result = CommandTreeTokenizer.Tokenize(args);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Remaining.ShouldBeEmpty();
|
result.Remaining.ShouldBeEmpty();
|
||||||
result.Tokens.Count.ShouldBe(2);
|
result.Tokens.Count.ShouldBe(2);
|
||||||
|
|
||||||
var t = result.Tokens.Consume();
|
var t = result.Tokens.Consume();
|
||||||
t.TokenKind.ShouldBe(CommandTreeToken.Kind.ShortOption);
|
t.TokenKind.ShouldBe(CommandTreeToken.Kind.ShortOption);
|
||||||
t.IsGrouped.ShouldBe(false);
|
t.IsGrouped.ShouldBe(false);
|
||||||
t.Position.ShouldBe(0);
|
t.Position.ShouldBe(0);
|
||||||
t.Value.ShouldBe("a");
|
t.Value.ShouldBe("a");
|
||||||
t.Representation.ShouldBe("-a");
|
t.Representation.ShouldBe("-a");
|
||||||
|
|
||||||
t = result.Tokens.Consume();
|
t = result.Tokens.Consume();
|
||||||
t.TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
t.TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
||||||
t.IsGrouped.ShouldBe(false);
|
t.IsGrouped.ShouldBe(false);
|
||||||
t.Position.ShouldBe(3);
|
t.Position.ShouldBe(3);
|
||||||
t.Value.ShouldBe(expectedValue);
|
t.Value.ShouldBe(expectedValue);
|
||||||
t.Representation.ShouldBe(expectedValue);
|
t.Representation.ShouldBe(expectedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Accept_Option_With_Negative_Numeric_Prefixed_String_Value()
|
public void Should_Accept_Option_With_Negative_Numeric_Prefixed_String_Value()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = CommandTreeTokenizer.Tokenize(new[] { "-6..2 " });
|
var result = CommandTreeTokenizer.Tokenize(new[] { "-6..2 " });
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Remaining.ShouldBeEmpty();
|
result.Remaining.ShouldBeEmpty();
|
||||||
result.Tokens.ShouldHaveSingleItem();
|
result.Tokens.ShouldHaveSingleItem();
|
||||||
|
|
||||||
var t = result.Tokens[0];
|
var t = result.Tokens[0];
|
||||||
t.TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
t.TokenKind.ShouldBe(CommandTreeToken.Kind.String);
|
||||||
t.IsGrouped.ShouldBe(false);
|
t.IsGrouped.ShouldBe(false);
|
||||||
t.Position.ShouldBe(0);
|
t.Position.ShouldBe(0);
|
||||||
t.Value.ShouldBe("-6..2");
|
t.Value.ShouldBe("-6..2");
|
||||||
t.Representation.ShouldBe("-6..2");
|
t.Representation.ShouldBe("-6..2");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("-N ", "N")]
|
[InlineData("-N ", "N")]
|
||||||
public void Should_Remove_Trailing_Spaces_In_Option_Name(string actual, string expected)
|
public void Should_Remove_Trailing_Spaces_In_Option_Name(string actual, string expected)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = CommandTreeTokenizer.Tokenize(new string[] { actual });
|
var result = CommandTreeTokenizer.Tokenize(new string[] { actual });
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.Tokens.Count.ShouldBe(1);
|
result.Tokens.Count.ShouldBe(1);
|
||||||
result.Tokens[0].Value.ShouldBe(expected);
|
result.Tokens[0].Value.ShouldBe(expected);
|
||||||
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.ShortOption);
|
result.Tokens[0].TokenKind.ShouldBe(CommandTreeToken.Kind.ShortOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("-N-")]
|
[InlineData("-N-")]
|
||||||
[InlineData("-N\"")]
|
[InlineData("-N\"")]
|
||||||
[InlineData("-a1")]
|
[InlineData("-a1")]
|
||||||
public void Should_Throw_On_Invalid_Option_Name(string actual)
|
public void Should_Throw_On_Invalid_Option_Name(string actual)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = Record.Exception(() => CommandTreeTokenizer.Tokenize(new string[] { actual }));
|
var result = Record.Exception(() => CommandTreeTokenizer.Tokenize(new string[] { actual }));
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
||||||
{
|
{
|
||||||
ex.Message.ShouldBe("Short option does not have a valid name.");
|
ex.Message.ShouldBe("Short option does not have a valid name.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("-")]
|
[InlineData("-")]
|
||||||
[InlineData("- ")]
|
[InlineData("- ")]
|
||||||
public void Should_Throw_On_Missing_Option_Name(string actual)
|
public void Should_Throw_On_Missing_Option_Name(string actual)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
|
|
||||||
// When
|
// When
|
||||||
var result = Record.Exception(() => CommandTreeTokenizer.Tokenize(new string[] { actual }));
|
var result = Record.Exception(() => CommandTreeTokenizer.Tokenize(new string[] { actual }));
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
||||||
{
|
{
|
||||||
ex.Message.ShouldBe("Option does not have a name.");
|
ex.Message.ShouldBe("Option does not have a name.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Spectre.Console.Tests.Unit.Cli.Testing;
|
namespace Spectre.Console.Tests.Unit.Cli.Testing;
|
||||||
|
|
||||||
public class FakeTypeRegistrarTests
|
public class FakeTypeRegistrarTests
|
||||||
{
|
{
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
namespace Spectre.Console.Tests.Unit;
|
namespace Spectre.Console.Tests.Unit;
|
||||||
|
|
||||||
public sealed class StyleTests
|
public sealed class StyleTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Convert_From_Color_As_Expected()
|
public void Should_Convert_From_Color_As_Expected()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
Style style;
|
Style style;
|
||||||
|
|
||||||
// When
|
// When
|
||||||
style = Color.Red;
|
style = Color.Red;
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
style.Foreground.ShouldBe(Color.Red);
|
style.Foreground.ShouldBe(Color.Red);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Should_Combine_Two_Styles_As_Expected()
|
public void Should_Combine_Two_Styles_As_Expected()
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Spectre.Console.Tests;
|
namespace Spectre.Console.Tests;
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
public sealed class GitHubIssueAttribute : Attribute
|
public sealed class GitHubIssueAttribute : Attribute
|
||||||
|
Loading…
x
Reference in New Issue
Block a user