mirror of
https://github.com/spectreconsole/spectre.console.git
synced 2025-10-25 15:19:23 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
168f35202d | ||
|
|
225305f90e | ||
|
|
8fed3bc575 | ||
|
|
19eb273813 | ||
|
|
48df9cf68b | ||
|
|
2f6b4f53c4 | ||
|
|
21ac952307 | ||
|
|
e86f9d3c5a | ||
|
|
9c9eb04f91 | ||
|
|
ba4b7b97f8 | ||
|
|
b738187b28 | ||
|
|
b3ef7d4fa6 | ||
|
|
c5c1852fc3 | ||
|
|
045d0922c8 | ||
|
|
949f35defd | ||
|
|
f5a2735501 | ||
|
|
d02c9e552e | ||
|
|
a4ae36738b | ||
|
|
35d2750b68 | ||
|
|
4d2d927caa | ||
|
|
174d285035 |
11
.github/workflows/ci.yaml
vendored
11
.github/workflows/ci.yaml
vendored
@@ -13,17 +13,15 @@ jobs:
|
||||
|
||||
docs:
|
||||
name: Documentation
|
||||
if: false # Disable for now
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@master
|
||||
|
||||
- name: Setup dotnet
|
||||
- name: Setup dotnet 6.0.100
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
include-prerelease: true
|
||||
dotnet-version: 6.0.100
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
@@ -86,6 +84,11 @@ jobs:
|
||||
with:
|
||||
dotnet-version: 5.0.301
|
||||
|
||||
- name: Setup dotnet 6.0.100
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 6.0.100
|
||||
|
||||
- name: Integration Tests
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
@@ -17,7 +17,6 @@ jobs:
|
||||
|
||||
build:
|
||||
name: Deploy
|
||||
if: false # Disable for now
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -25,11 +24,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup dotnet
|
||||
- name: Setup dotnet 6.0.100
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
include-prerelease: true
|
||||
dotnet-version: 6.0.100
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
19
.github/workflows/publish.yaml
vendored
19
.github/workflows/publish.yaml
vendored
@@ -19,17 +19,15 @@ jobs:
|
||||
|
||||
docs:
|
||||
name: Documentation
|
||||
if: false # Disable for now
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@master
|
||||
|
||||
- name: Setup dotnet
|
||||
- name: Setup dotnet 6.0.100
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
include-prerelease: true
|
||||
dotnet-version: 6.0.100
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
@@ -45,7 +43,7 @@ jobs:
|
||||
|
||||
build:
|
||||
name: Build
|
||||
# needs: [docs]
|
||||
needs: [docs]
|
||||
if: "!contains(github.event.head_commit.message, 'skip-ci') || startsWith(github.ref, 'refs/tags/')"
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -74,6 +72,11 @@ jobs:
|
||||
with:
|
||||
dotnet-version: 5.0.301
|
||||
|
||||
- name: Setup dotnet 6.0.100
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 6.0.100
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -105,6 +108,12 @@ jobs:
|
||||
with:
|
||||
dotnet-version: 5.0.301
|
||||
|
||||
- name: Setup dotnet 6.0
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
include-prerelease: true
|
||||
|
||||
- name: Publish
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
16
build.cake
16
build.cake
@@ -14,7 +14,7 @@ Task("Build")
|
||||
.IsDependentOn("Clean")
|
||||
.Does(context =>
|
||||
{
|
||||
DotNetCoreBuild("./src/Spectre.Console.sln", new DotNetCoreBuildSettings {
|
||||
DotNetBuild("./src/Spectre.Console.sln", new DotNetBuildSettings {
|
||||
Configuration = configuration,
|
||||
NoIncremental = context.HasArgument("rebuild"),
|
||||
MSBuildSettings = new DotNetCoreMSBuildSettings()
|
||||
@@ -26,7 +26,7 @@ Task("Build-Analyzer")
|
||||
.IsDependentOn("Build")
|
||||
.Does(context =>
|
||||
{
|
||||
DotNetCoreBuild("./src/Spectre.Console.Analyzer.sln", new DotNetCoreBuildSettings {
|
||||
DotNetBuild("./src/Spectre.Console.Analyzer.sln", new DotNetBuildSettings {
|
||||
Configuration = configuration,
|
||||
NoIncremental = context.HasArgument("rebuild"),
|
||||
MSBuildSettings = new DotNetCoreMSBuildSettings()
|
||||
@@ -38,7 +38,7 @@ Task("Build-Examples")
|
||||
.IsDependentOn("Build")
|
||||
.Does(context =>
|
||||
{
|
||||
DotNetCoreBuild("./examples/Examples.sln", new DotNetCoreBuildSettings {
|
||||
DotNetBuild("./examples/Examples.sln", new DotNetBuildSettings {
|
||||
Configuration = configuration,
|
||||
NoIncremental = context.HasArgument("rebuild"),
|
||||
MSBuildSettings = new DotNetCoreMSBuildSettings()
|
||||
@@ -52,13 +52,13 @@ Task("Test")
|
||||
.IsDependentOn("Build-Examples")
|
||||
.Does(context =>
|
||||
{
|
||||
DotNetCoreTest("./test/Spectre.Console.Tests/Spectre.Console.Tests.csproj", new DotNetCoreTestSettings {
|
||||
DotNetTest("./test/Spectre.Console.Tests/Spectre.Console.Tests.csproj", new DotNetTestSettings {
|
||||
Configuration = configuration,
|
||||
NoRestore = true,
|
||||
NoBuild = true,
|
||||
});
|
||||
|
||||
DotNetCoreTest("./test/Spectre.Console.Analyzer.Tests/Spectre.Console.Analyzer.Tests.csproj", new DotNetCoreTestSettings {
|
||||
DotNetTest("./test/Spectre.Console.Analyzer.Tests/Spectre.Console.Analyzer.Tests.csproj", new DotNetTestSettings {
|
||||
Configuration = configuration,
|
||||
NoRestore = true,
|
||||
NoBuild = true,
|
||||
@@ -69,7 +69,7 @@ Task("Package")
|
||||
.IsDependentOn("Test")
|
||||
.Does(context =>
|
||||
{
|
||||
context.DotNetCorePack($"./src/Spectre.Console.sln", new DotNetCorePackSettings {
|
||||
context.DotNetPack($"./src/Spectre.Console.sln", new DotNetPackSettings {
|
||||
Configuration = configuration,
|
||||
NoRestore = true,
|
||||
NoBuild = true,
|
||||
@@ -78,7 +78,7 @@ Task("Package")
|
||||
.TreatAllWarningsAs(MSBuildTreatAllWarningsAs.Error)
|
||||
});
|
||||
|
||||
context.DotNetCorePack($"./src/Spectre.Console.Analyzer.sln", new DotNetCorePackSettings {
|
||||
context.DotNetPack($"./src/Spectre.Console.Analyzer.sln", new DotNetPackSettings {
|
||||
Configuration = configuration,
|
||||
NoRestore = true,
|
||||
NoBuild = true,
|
||||
@@ -134,7 +134,7 @@ Task("Publish-NuGet")
|
||||
foreach(var file in context.GetFiles("./.artifacts/*.nupkg"))
|
||||
{
|
||||
context.Information("Publishing {0}...", file.GetFilename().FullPath);
|
||||
DotNetCoreNuGetPush(file.FullPath, new DotNetCoreNuGetPushSettings
|
||||
DotNetNuGetPush(file.FullPath, new DotNetNuGetPushSettings
|
||||
{
|
||||
Source = "https://api.nuget.org/v3/index.json",
|
||||
ApiKey = apiKey,
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Playwright" Version="1.13.0-next-1" />
|
||||
|
||||
<PackageReference Include="Statiq.Web" Version="1.0.0-beta.31" />
|
||||
<PackageReference Include="Statiq.Web" Version="1.0.0-beta.34" />
|
||||
<PackageReference Include="MinVer" PrivateAssets="All" Version="2.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -74,6 +74,9 @@ return app.Run(args);
|
||||
|
||||
`TypeRegistrar` is a custom class that must be created by the user. This [example using `Microsoft.Extensions.DependencyInjection` as the container](https://github.com/spectreconsole/spectre.console/tree/main/examples/Cli/Injection) provides an example `TypeRegistrar` and `TypeResolver` that can be added to your application with small adjustments for your DI container.
|
||||
|
||||
Hint: If you do write your own implementation of `TypeRegistrar` and `TypeResolver` and you have some form of unit tests in place for your project,
|
||||
there is a utility `TypeRegistrarBaseTests` available that can be used to ensure your implementations adhere to the required implementation. Simply call `TypeRegistrarBaseTests.RunAllTests()` and expect no `TypeRegistrarBaseTests.TestFailedException` to be thrown.
|
||||
|
||||
## Interception
|
||||
|
||||
`CommandApp` also provides a `SetInterceptor` configuration. An interceptor is run before all commands are executed. This is typically used for configuring logging or other infrastructure concerns.
|
||||
|
||||
116
docs/input/cli/exceptions.md
Normal file
116
docs/input/cli/exceptions.md
Normal file
@@ -0,0 +1,116 @@
|
||||
Title: Exceptions
|
||||
Order: 12
|
||||
Description: "Handling exceptions in *Spectre.Console.Cli*"
|
||||
---
|
||||
|
||||
Exceptions happen.
|
||||
|
||||
`Spectre.Console.Cli` handles exceptions, writes a user friendly message to the console and sets the exitCode
|
||||
of the application to `-1`.
|
||||
While this might be enough for the needs of most applications, there are some options to customize this behavior.
|
||||
|
||||
## Propagating exceptions
|
||||
|
||||
The most basic way is to set `PropagateExceptions()` during configuration and handle everything.
|
||||
While this option grants the most freedom, it also requires the most work: Setting `PropagateExceptions`
|
||||
means that `Spectre.Console.Cli` effectively re-throws exceptions.
|
||||
This means that `app.Run()` should be wrapped in a `try`-`catch`-block which has to handle the exception
|
||||
(i.e. outputting something useful) and also provide the exitCode (or `return` value) for the application.
|
||||
|
||||
```csharp
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace MyApp
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
var app = new CommandApp<FileSizeCommand>();
|
||||
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
return app.Run(args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything);
|
||||
return -99;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Using a custom ExceptionHandler
|
||||
|
||||
Using the `SetErrorHandler()` during configuration it is possible to handle exceptions in a defined way.
|
||||
This method comes in two flavours: One that uses the default exitCode (or `return` value) of `-1` and one
|
||||
where the exitCode needs to be supplied.
|
||||
|
||||
### Using `SetErrorHandler(Func<Exception, int> handler)`
|
||||
|
||||
Using this method exceptions can be handled in a custom way. The return value of the handler is used as
|
||||
the exitCode for the application.
|
||||
|
||||
```csharp
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace MyApp
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
var app = new CommandApp<FileSizeCommand>();
|
||||
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.SetExceptionHandler(ex =>
|
||||
{
|
||||
AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything);
|
||||
return -99;
|
||||
});
|
||||
});
|
||||
|
||||
return app.Run(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using `SetErrorHandler(Action<Exception> handler)`
|
||||
|
||||
Using this method exceptions can be handled in a custom way, much the same as with the `SetErrorHandler(Func<Exception, int> handler)`.
|
||||
Using the `Action` as the handler however, it is not possible (or required) to supply a return value.
|
||||
The exitCode for the application will be `-1`.
|
||||
|
||||
```csharp
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace MyApp
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
var app = new CommandApp<FileSizeCommand>();
|
||||
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.SetExceptionHandler(ex =>
|
||||
{
|
||||
AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything);
|
||||
});
|
||||
});
|
||||
|
||||
return app.Run(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -61,8 +61,8 @@ In our `Main()` method, an instance of `Spectre.Console.Cli`'s `CommandApp` is
|
||||
|
||||
This command will have three parameters.
|
||||
|
||||
* The main parameter for the command will be the path. This is to be passed in as the first argument without needing to specify any command line flags. To configure that setting, use the `CommandArgument` attribute. The `[searchPath]` parameters of `CommandArgument` drives not only how the built in help display will render the help text, but the square brackets tells `Spectre.Console.Cli` that this argument is optional through convention.
|
||||
* The second will be specified as a parameter option. The `CommandOption` attribute is used to specify this action along with the option command line flag. In the case of `SearchPattern` both `-p` and `--path` are valid.
|
||||
* The main parameter for the command will be the path. This is to be passed in as the first argument without needing to specify any command line flags. To configure that setting, use the `CommandArgument` attribute. The `[searchPath]` parameter of `CommandArgument` drives not only how the built in help display will render the help text, but the square brackets tells `Spectre.Console.Cli` that this argument is optional through convention.
|
||||
* The second will be specified as a parameter option. The `CommandOption` attribute is used to specify this action along with the option command line flag. In the case of `SearchPattern` both `-p` and `--pattern` are valid.
|
||||
* The third will also be a parameter option. Here `DefaultValue` is used to indicate the default value will be `true`. For boolean parameters these will be interpreted as flags which means the user can just specify `--hidden` rather than `-hidden true`.
|
||||
|
||||
When `args` is passed into the `CommandApp`'s run method, `Spectre.Console.Cli` will parse those arguments and populate an instance of your settings. Upon success, it will then pass those settings into an instance of the specified command's `Execute` method.
|
||||
|
||||
@@ -15,7 +15,7 @@ Console markup uses a syntax inspired by bbcode. If you write the style (see [St
|
||||
in square brackets, e.g. `[bold red]`, that style will apply until it is closed with a `[/]`.
|
||||
|
||||
```csharp
|
||||
AnsiConsole.Render(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
|
||||
@@ -26,7 +26,7 @@ rendering of `IRenderable` also have overloads for rendering rich text.
|
||||
var table = new Table();
|
||||
table.AddColumn(new TableColumn(new Markup("[yellow]Foo[/]")));
|
||||
table.AddColumn(new TableColumn("[blue]Bar[/]"));
|
||||
AnsiConsole.Render(table);
|
||||
AnsiConsole.Write(table);
|
||||
```
|
||||
|
||||
## Convenience methods
|
||||
|
||||
@@ -29,9 +29,8 @@ var fruits = AnsiConsole.Prompt(
|
||||
.InstructionsText(
|
||||
"[grey](Press [blue]<space>[/] to toggle a fruit, " +
|
||||
"[green]<enter>[/] to accept)[/]")
|
||||
.AddChoice("Apple")
|
||||
.AddChoices(new[] {
|
||||
"Apricot", "Avocado",
|
||||
"Apple", "Apricot", "Avocado",
|
||||
"Banana", "Blackcurrant", "Blueberry",
|
||||
"Cherry", "Cloudberry", "Cocunut",
|
||||
}));
|
||||
|
||||
@@ -22,9 +22,8 @@ var fruit = AnsiConsole.Prompt(
|
||||
.Title("What's your [green]favorite fruit[/]?")
|
||||
.PageSize(10)
|
||||
.MoreChoicesText("[grey](Move up and down to reveal more fruits)[/]")
|
||||
.AddChoice("Apple")
|
||||
.AddChoices(new[] {
|
||||
"Apricot", "Avocado",
|
||||
"Apple", "Apricot", "Avocado",
|
||||
"Banana", "Blackcurrant", "Blueberry",
|
||||
"Cherry", "Cloudberry", "Cocunut",
|
||||
}));
|
||||
|
||||
@@ -9,7 +9,7 @@ Spectre.Console to show their support and to ensure the longevity of the project
|
||||
* [Rodney Littles II](https://github.com/RLittlesII)
|
||||
* [Martin Björkström](https://github.com/bjorkstromm)
|
||||
* [Dave Glick](https://github.com/daveaglick)
|
||||
* [Kim Gunanrsson](https://github.com/kimgunnarsson)
|
||||
* [Kim Gunnarsson](https://github.com/kimgunnarsson)
|
||||
* [Andrew McClenaghan](https://github.com/andymac4182)
|
||||
* [C. Augusto Proiete](https://github.com/augustoproiete)
|
||||
* [Viktor Elofsson](https://github.com/vktr)
|
||||
|
||||
@@ -17,7 +17,7 @@ Use `BarChart` to render bar charts to the console.
|
||||
### Basic usage
|
||||
|
||||
```csharp
|
||||
AnsiConsole.Render(new BarChart()
|
||||
AnsiConsole.Write(new BarChart()
|
||||
.Width(60)
|
||||
.Label("[green bold underline]Number of fruits[/]")
|
||||
.CenterLabel()
|
||||
@@ -38,7 +38,7 @@ var items = new List<(string Label, double Value)>
|
||||
};
|
||||
|
||||
// Render bar chart
|
||||
AnsiConsole.Render(new BarChart()
|
||||
AnsiConsole.Write(new BarChart()
|
||||
.Width(60)
|
||||
.Label("[green bold underline]Number of fruits[/]")
|
||||
.CenterLabel()
|
||||
@@ -72,7 +72,7 @@ var items = new List<Fruit>
|
||||
};
|
||||
|
||||
// Render bar chart
|
||||
AnsiConsole.Render(new BarChart()
|
||||
AnsiConsole.Write(new BarChart()
|
||||
.Width(60)
|
||||
.Label("[green bold underline]Number of fruits[/]")
|
||||
.CenterLabel()
|
||||
|
||||
@@ -16,7 +16,7 @@ To render a calendar, create a `Calendar` instance with a target date.
|
||||
|
||||
```csharp
|
||||
var calendar = new Calendar(2020,10);
|
||||
AnsiConsole.Render(calendar);
|
||||
AnsiConsole.Write(calendar);
|
||||
```
|
||||
|
||||
<?# AsciiCast cast="calendar" /?>
|
||||
@@ -27,8 +27,8 @@ You can set the calendar's culture to show localized weekdays.
|
||||
|
||||
```csharp
|
||||
var calendar = new Calendar(2020,10);
|
||||
calendar.Culture("ja-JP");
|
||||
AnsiConsole.Render(calendar);
|
||||
calendar.Culture("sv-SE");
|
||||
AnsiConsole.Write(calendar);
|
||||
```
|
||||
|
||||
<?# AsciiCast cast="calendar-culture" /?>
|
||||
@@ -40,7 +40,7 @@ You can hide the calendar header.
|
||||
```csharp
|
||||
var calendar = new Calendar(2020,10);
|
||||
calendar.HideHeader();
|
||||
AnsiConsole.Render(calendar);
|
||||
AnsiConsole.Write(calendar);
|
||||
```
|
||||
|
||||
You can set the header style of the calendar.
|
||||
@@ -48,7 +48,7 @@ You can set the header style of the calendar.
|
||||
```csharp
|
||||
var calendar = new Calendar(2020, 10);
|
||||
calendar.HeaderStyle(Style.Parse("blue bold"));
|
||||
AnsiConsole.Render(calendar);
|
||||
AnsiConsole.Write(calendar);
|
||||
```
|
||||
|
||||
<?# AsciiCast cast="calendar-header" /?>
|
||||
|
||||
@@ -26,7 +26,7 @@ var image = new CanvasImage("cake.png");
|
||||
image.MaxWidth(16);
|
||||
|
||||
// Render the image to the console
|
||||
AnsiConsole.Render(image);
|
||||
AnsiConsole.Write(image);
|
||||
```
|
||||
|
||||
## Result
|
||||
@@ -50,7 +50,7 @@ image.BilinearResampler();
|
||||
image.Mutate(ctx => ctx.Grayscale().Rotate(-45).EntropyCrop());
|
||||
|
||||
// Render the image to the console
|
||||
AnsiConsole.Render(image);
|
||||
AnsiConsole.Write(image);
|
||||
```
|
||||
|
||||
## Result
|
||||
|
||||
@@ -28,7 +28,7 @@ for(var i = 0; i < canvas.Width; i++)
|
||||
}
|
||||
|
||||
// Render the canvas
|
||||
AnsiConsole.Render(canvas);
|
||||
AnsiConsole.Write(canvas);
|
||||
```
|
||||
|
||||
## Result
|
||||
|
||||
@@ -9,7 +9,7 @@ Spectre.Console can render [FIGlet](http://www.figlet.org/) text by using the `F
|
||||
## Default font
|
||||
|
||||
```csharp
|
||||
AnsiConsole.Render(
|
||||
AnsiConsole.Write(
|
||||
new FigletText("Hello")
|
||||
.LeftAligned()
|
||||
.Color(Color.Red));
|
||||
@@ -23,7 +23,7 @@ AnsiConsole.Render(
|
||||
```csharp
|
||||
var font = FigletFont.Load("starwars.flf");
|
||||
|
||||
AnsiConsole.Render(
|
||||
AnsiConsole.Write(
|
||||
new FigletText(font, "Hello")
|
||||
.LeftAligned()
|
||||
.Color(Color.Red));
|
||||
|
||||
@@ -18,7 +18,7 @@ To render a rule without a title:
|
||||
|
||||
```csharp
|
||||
var rule = new Rule();
|
||||
AnsiConsole.Render(rule);
|
||||
AnsiConsole.Write(rule);
|
||||
```
|
||||
|
||||
## Title
|
||||
@@ -27,7 +27,7 @@ You can set the rule title markup text.
|
||||
|
||||
```csharp
|
||||
var rule = new Rule("[red]Hello[/]");
|
||||
AnsiConsole.Render(rule);
|
||||
AnsiConsole.Write(rule);
|
||||
```
|
||||
|
||||
```text
|
||||
@@ -41,7 +41,7 @@ You can set the rule's title alignment.
|
||||
```csharp
|
||||
var rule = new Rule("[red]Hello[/]");
|
||||
rule.Alignment = Justify.Left;
|
||||
AnsiConsole.Render(rule);
|
||||
AnsiConsole.Write(rule);
|
||||
```
|
||||
|
||||
```text
|
||||
@@ -53,7 +53,7 @@ You can also specify it via an extension method:
|
||||
```csharp
|
||||
var rule = new Rule("[red]Hello[/]");
|
||||
rule.LeftAligned();
|
||||
AnsiConsole.Render(rule);
|
||||
AnsiConsole.Write(rule);
|
||||
```
|
||||
|
||||
```text
|
||||
@@ -66,12 +66,12 @@ AnsiConsole.Render(rule);
|
||||
```csharp
|
||||
var rule = new Rule("[red]Hello[/]");
|
||||
rule.Style = Style.Parse("red dim");
|
||||
AnsiConsole.Render(rule);
|
||||
AnsiConsole.Write(rule);
|
||||
```
|
||||
You can also specify it via an extension method
|
||||
|
||||
```csharp
|
||||
var rule = new Rule("[red]Hello[/]");
|
||||
rule.RuleStyle("red dim");
|
||||
AnsiConsole.Render(rule);
|
||||
AnsiConsole.Write(rule);
|
||||
```
|
||||
|
||||
@@ -35,7 +35,7 @@ table.AddRow("Baz", "[green]Qux[/]");
|
||||
table.AddRow(new Markup("[blue]Corgi[/]"), new Panel("Waldo"));
|
||||
|
||||
// Render the table to the console
|
||||
AnsiConsole.Render(table);
|
||||
AnsiConsole.Write(table);
|
||||
```
|
||||
|
||||
This will render the following output:
|
||||
|
||||
@@ -35,7 +35,7 @@ bar.AddNode(new Calendar(2020, 12)
|
||||
.HideHeader());
|
||||
|
||||
// Render the tree
|
||||
AnsiConsole.Render(root);
|
||||
AnsiConsole.Write(root);
|
||||
```
|
||||
|
||||
## Collapsing nodes
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"cake.tool": {
|
||||
"version": "1.1.0",
|
||||
"version": "2.0.0-rc0001",
|
||||
"commands": [
|
||||
"dotnet-cake"
|
||||
]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<ExampleName>Delegates</ExampleName>
|
||||
<ExampleDescription>Demonstrates how to specify commands as delegates.</ExampleDescription>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<ExampleName>Demo</ExampleName>
|
||||
<ExampleDescription>Demonstrates the most common use cases of Spectre.Cli.</ExampleDescription>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<ExampleName>Dynamic</ExampleName>
|
||||
<ExampleDescription>Demonstrates how to define dynamic commands.</ExampleDescription>
|
||||
|
||||
@@ -15,7 +15,12 @@ namespace Spectre.Console.Examples
|
||||
|
||||
public object Resolve(Type type)
|
||||
{
|
||||
return _provider.GetRequiredService(type);
|
||||
if (type == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _provider.GetService(type);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<ExampleName>Injection</ExampleName>
|
||||
<ExampleDescription>Demonstrates how to use dependency injection with Spectre.Cli.</ExampleDescription>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<ExampleName>Logging</ExampleName>
|
||||
<ExampleDescription>Demonstrates how to dynamically configure Serilog for logging using parameters from a command.</ExampleDescription>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Borders</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates the different kind of borders.</ExampleDescription>
|
||||
<ExampleGroup>Widgets</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Calendars</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render calendars.</ExampleDescription>
|
||||
<ExampleGroup>Widgets</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Canvas</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render pixels and images.</ExampleDescription>
|
||||
<ExampleGroup>Widgets</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Charts</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render charts in a console.</ExampleDescription>
|
||||
<ExampleGroup>Widgets</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Colors</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to use [yellow]c[/][red]o[/][green]l[/][blue]o[/][aqua]r[/][lime]s[/] in the console.</ExampleDescription>
|
||||
<ExampleGroup>Misc</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Columns</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render data into columns.</ExampleDescription>
|
||||
<ExampleGroup>Widgets</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Cursor</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to move the cursor.</ExampleDescription>
|
||||
<ExampleGroup>Misc</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Emojis</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render emojis.</ExampleDescription>
|
||||
<ExampleGroup>Misc</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Exceptions</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render formatted exceptions.</ExampleDescription>
|
||||
<ExampleGroup>Misc</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Figlet</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render FIGlet text.</ExampleDescription>
|
||||
<ExampleGroup>Widgets</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Grids</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render grids in a console.</ExampleDescription>
|
||||
<ExampleGroup>Widgets</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Info</ExampleTitle>
|
||||
<ExampleDescription>Displays the capabilities of the current console.</ExampleDescription>
|
||||
<ExampleGroup>Misc</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Links</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render links in a console.</ExampleDescription>
|
||||
<ExampleGroup>Misc</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Live</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to do live updates.</ExampleDescription>
|
||||
<ExampleGroup>Live</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>LiveTable</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to do live updates in a table.</ExampleDescription>
|
||||
<ExampleGroup>Live</ExampleGroup>
|
||||
|
||||
2
examples/Console/Minimal/GlobalUsings.cs
Normal file
2
examples/Console/Minimal/GlobalUsings.cs
Normal file
@@ -0,0 +1,2 @@
|
||||
global using Spectre.Console;
|
||||
global using static Spectre.Console.AnsiConsole;
|
||||
16
examples/Console/Minimal/Minimal.csproj
Normal file
16
examples/Console/Minimal/Minimal.csproj
Normal file
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<ExampleTitle>Minimal</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates a minimal console application.</ExampleDescription>
|
||||
<ExampleGroup>Live</ExampleGroup>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Shared\Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
13
examples/Console/Minimal/Program.cs
Normal file
13
examples/Console/Minimal/Program.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Write a markup line to the console
|
||||
MarkupLine("[yellow]Hello[/], [blue]World[/]!");
|
||||
|
||||
// Write text to the console
|
||||
WriteLine("Hello, World!");
|
||||
|
||||
// Write a table to the console
|
||||
Write(new Table()
|
||||
.RoundedBorder()
|
||||
.AddColumns("[red]Greeting[/]", "[red]Subject[/]")
|
||||
.AddRow("[yellow]Hello[/]", "World")
|
||||
.AddRow("[green]Oh hi[/]", "[blue u]Mark[/]"));
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Panels</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render items in panels.</ExampleDescription>
|
||||
<ExampleGroup>Widgets</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Progress</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to show progress bars.</ExampleDescription>
|
||||
<ExampleGroup>Status</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>9</LangVersion>
|
||||
<ExampleTitle>Prompt</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to get input from a user.</ExampleDescription>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Rules</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render horizontal rules (lines).</ExampleDescription>
|
||||
<ExampleGroup>Widgets</ExampleGroup>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Showcase</ExampleTitle>
|
||||
<ExampleDescription>Demonstation of Spectre.Console.</ExampleDescription>
|
||||
<ExampleGroup>Misc</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Status</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to show status updates.</ExampleDescription>
|
||||
<ExampleGroup>Status</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Tables</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render tables in a console.</ExampleDescription>
|
||||
<ExampleGroup>Widgets</ExampleGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleTitle>Trees</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to render trees in a console.</ExampleDescription>
|
||||
<ExampleGroup>Widgets</ExampleGroup>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30114.105
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{2571F1BD-6556-4F96-B27B-B6190E1BF13A}"
|
||||
EndProject
|
||||
@@ -65,6 +65,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Trees", "Console\Trees\Tree
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiveTable", "Console\LiveTable\LiveTable.csproj", "{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Minimal", "Console\Minimal\Minimal.csproj", "{1780A30A-397A-4CC3-B2A0-A385D9081FA2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -423,6 +425,18 @@ Global
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{1780A30A-397A-4CC3-B2A0-A385D9081FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1780A30A-397A-4CC3-B2A0-A385D9081FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1780A30A-397A-4CC3-B2A0-A385D9081FA2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{1780A30A-397A-4CC3-B2A0-A385D9081FA2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{1780A30A-397A-4CC3-B2A0-A385D9081FA2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{1780A30A-397A-4CC3-B2A0-A385D9081FA2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{1780A30A-397A-4CC3-B2A0-A385D9081FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1780A30A-397A-4CC3-B2A0-A385D9081FA2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1780A30A-397A-4CC3-B2A0-A385D9081FA2}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{1780A30A-397A-4CC3-B2A0-A385D9081FA2}.Release|x64.Build.0 = Release|Any CPU
|
||||
{1780A30A-397A-4CC3-B2A0-A385D9081FA2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{1780A30A-397A-4CC3-B2A0-A385D9081FA2}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExampleVisible>false</ExampleVisible>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"projects": [ "src", "tests" ],
|
||||
"sdk": {
|
||||
"version": "5.0.301",
|
||||
"version": "6.0.100",
|
||||
"rollForward": "latestFeature"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,6 @@
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="MinVer" PrivateAssets="All" Version="2.4.0" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" Version="1.0.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.312">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net5.0;netstandard2.0</TargetFrameworks>
|
||||
<TargetFrameworks>net6.0;net5.0;netstandard2.0</TargetFrameworks>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>true</IsPackable>
|
||||
<Description>A library that extends Spectre.Console with ImageSharp superpowers.</Description>
|
||||
|
||||
191
src/Spectre.Console.Testing/Cli/TypeRegistrarBaseTests.cs
Normal file
191
src/Spectre.Console.Testing/Cli/TypeRegistrarBaseTests.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
using System;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Testing
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a utility class for implementors of
|
||||
/// <see cref="ITypeRegistrar"/> and corresponding <see cref="ITypeResolver"/>.
|
||||
/// </summary>
|
||||
public sealed class TypeRegistrarBaseTests
|
||||
{
|
||||
private readonly Func<ITypeRegistrar> _registrarFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TypeRegistrarBaseTests"/> class.
|
||||
/// </summary>
|
||||
/// <param name="registrarFactory">The factory to create a new, clean <see cref="ITypeRegistrar"/> to be used for each test.</param>
|
||||
public TypeRegistrarBaseTests(Func<ITypeRegistrar> registrarFactory)
|
||||
{
|
||||
_registrarFactory = registrarFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs all tests.
|
||||
/// </summary>
|
||||
/// <exception cref="TestFailedException">This exception is raised, if a test fails.</exception>
|
||||
public void RunAllTests()
|
||||
{
|
||||
var testCases = new Action<ITypeRegistrar>[]
|
||||
{
|
||||
RegistrationsCanBeResolved,
|
||||
InstanceRegistrationsCanBeResolved,
|
||||
LazyRegistrationsCanBeResolved,
|
||||
ResolvingNotRegisteredServiceReturnsNull,
|
||||
ResolvingNullTypeReturnsNull,
|
||||
};
|
||||
|
||||
foreach (var test in testCases)
|
||||
{
|
||||
test(_registrarFactory());
|
||||
}
|
||||
}
|
||||
|
||||
private static void ResolvingNullTypeReturnsNull(ITypeRegistrar registrar)
|
||||
{
|
||||
// Given no registration
|
||||
var resolver = registrar.Build();
|
||||
|
||||
try
|
||||
{
|
||||
// When
|
||||
var actual = resolver.Resolve(null);
|
||||
|
||||
// Then
|
||||
if (actual != null)
|
||||
{
|
||||
throw new TestFailedException(
|
||||
$"Expected the resolver to resolve null, since null was requested as the service type. Actually resolved {actual.GetType().Name}.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new TestFailedException(
|
||||
$"Expected the resolver not to throw, but caught {ex.GetType().Name}.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ResolvingNotRegisteredServiceReturnsNull(ITypeRegistrar registrar)
|
||||
{
|
||||
// Given no registration
|
||||
var resolver = registrar.Build();
|
||||
|
||||
try
|
||||
{
|
||||
// When
|
||||
var actual = resolver.Resolve(typeof(IMockService));
|
||||
|
||||
// Then
|
||||
if (actual != null)
|
||||
{
|
||||
throw new TestFailedException(
|
||||
$"Expected the resolver to resolve null, since no service was registered. Actually resolved {actual.GetType().Name}.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new TestFailedException(
|
||||
$"Expected the resolver not to throw, but caught {ex.GetType().Name}.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegistrationsCanBeResolved(ITypeRegistrar registrar)
|
||||
{
|
||||
// Given
|
||||
registrar.Register(typeof(IMockService), typeof(MockService));
|
||||
var resolver = registrar.Build();
|
||||
|
||||
// When
|
||||
var actual = resolver.Resolve(typeof(IMockService));
|
||||
|
||||
// Then
|
||||
if (actual == null)
|
||||
{
|
||||
throw new TestFailedException(
|
||||
$"Expected the resolver to resolve an instance of {nameof(MockService)}. Actually resolved null.");
|
||||
}
|
||||
|
||||
if (actual is not MockService)
|
||||
{
|
||||
throw new TestFailedException(
|
||||
$"Expected the resolver to resolve an instance of {nameof(MockService)}. Actually resolved {actual.GetType().Name}.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void InstanceRegistrationsCanBeResolved(ITypeRegistrar registrar)
|
||||
{
|
||||
// Given
|
||||
var instance = new MockService();
|
||||
registrar.RegisterInstance(typeof(IMockService), instance);
|
||||
var resolver = registrar.Build();
|
||||
|
||||
// When
|
||||
var actual = resolver.Resolve(typeof(IMockService));
|
||||
|
||||
// Then
|
||||
if (!ReferenceEquals(actual, instance))
|
||||
{
|
||||
throw new TestFailedException(
|
||||
"Expected the resolver to resolve exactly the registered instance.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void LazyRegistrationsCanBeResolved(ITypeRegistrar registrar)
|
||||
{
|
||||
// Given
|
||||
var instance = new MockService();
|
||||
var factoryCalled = false;
|
||||
registrar.RegisterLazy(typeof(IMockService), () =>
|
||||
{
|
||||
factoryCalled = true;
|
||||
return instance;
|
||||
});
|
||||
var resolver = registrar.Build();
|
||||
|
||||
// When
|
||||
var actual = resolver.Resolve(typeof(IMockService));
|
||||
|
||||
// Then
|
||||
if (!factoryCalled)
|
||||
{
|
||||
throw new TestFailedException(
|
||||
"Expected the factory to be called, to resolve the lazy registration.");
|
||||
}
|
||||
|
||||
if (!ReferenceEquals(actual, instance))
|
||||
{
|
||||
throw new TestFailedException(
|
||||
"Expected the resolver to return exactly the result of the lazy-registered factory.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// internal use only.
|
||||
/// </summary>
|
||||
private interface IMockService
|
||||
{
|
||||
}
|
||||
|
||||
private class MockService : IMockService
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exception, to be raised when a test fails.
|
||||
/// </summary>
|
||||
public sealed class TestFailedException : Exception
|
||||
{
|
||||
/// <inheritdoc cref="Exception" />
|
||||
public TestFailedException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Exception" />
|
||||
public TestFailedException(string message, Exception inner)
|
||||
: base(message, inner)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net5.0;netstandard2.0</TargetFrameworks>
|
||||
<TargetFrameworks>net6.0;net5.0;netstandard2.0</TargetFrameworks>
|
||||
<IsTestProject>false</IsTestProject>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>true</IsPackable>
|
||||
|
||||
@@ -103,6 +103,11 @@ namespace Spectre.Console.Cli
|
||||
throw;
|
||||
}
|
||||
|
||||
if (_configurator.Settings.ExceptionHandler != null)
|
||||
{
|
||||
return _configurator.Settings.ExceptionHandler(ex);
|
||||
}
|
||||
|
||||
// Render the exception.
|
||||
var pretty = GetRenderableErrorMessage(ex);
|
||||
if (pretty != null)
|
||||
|
||||
@@ -224,5 +224,39 @@ namespace Spectre.Console.Cli
|
||||
|
||||
return configurator.AddDelegate<TSettings>(name, (c, _) => func(c));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ExceptionsHandler.
|
||||
/// <para>Setting <see cref="ICommandAppSettings.ExceptionHandler"/> this way will use the
|
||||
/// default exit code of -1.</para>
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="exceptionHandler">The Action that handles the exception.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Action<Exception> exceptionHandler)
|
||||
{
|
||||
return configurator.SetExceptionHandler(ex =>
|
||||
{
|
||||
exceptionHandler(ex);
|
||||
return -1;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ExceptionsHandler.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="exceptionHandler">The Action that handles the exception.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Func<Exception, int>? exceptionHandler)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.ExceptionHandler = exceptionHandler;
|
||||
return configurator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
{
|
||||
/// <summary>
|
||||
@@ -43,6 +45,8 @@ namespace Spectre.Console.Cli
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not exceptions should be propagated.
|
||||
/// <para>Setting this to <c>true</c> will disable default Exception handling and
|
||||
/// any <see cref="ExceptionHandler"/>, if set.</para>
|
||||
/// </summary>
|
||||
bool PropagateExceptions { get; set; }
|
||||
|
||||
@@ -50,5 +54,11 @@ namespace Spectre.Console.Cli
|
||||
/// Gets or sets a value indicating whether or not examples should be validated.
|
||||
/// </summary>
|
||||
bool ValidateExamples { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a handler for Exceptions.
|
||||
/// <para>This handler will not be called, if <see cref="PropagateExceptions"/> is set to <c>true</c>.</para>
|
||||
/// </summary>
|
||||
public Func<Exception, int>? ExceptionHandler { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace Spectre.Console.Cli
|
||||
/// Resolves an instance of the specified type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to resolve.</param>
|
||||
/// <returns>An instance of the specified type.</returns>
|
||||
/// <returns>An instance of the specified type, or <c>null</c> if no registration for the specified type exists.</returns>
|
||||
object? Resolve(Type? type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,18 +27,11 @@ namespace Spectre.Console.Cli
|
||||
}
|
||||
|
||||
private static CommandSettings CreateSettings(ITypeResolver resolver, Type settingsType)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (resolver.Resolve(settingsType) is CommandSettings settings)
|
||||
{
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (Activator.CreateInstance(settingsType) is CommandSettings instance)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace Spectre.Console.Cli
|
||||
public ParsingMode ParsingMode =>
|
||||
StrictParsing ? ParsingMode.Strict : ParsingMode.Relaxed;
|
||||
|
||||
public Func<Exception, int>? ExceptionHandler { get; set; }
|
||||
|
||||
public CommandAppSettings(ITypeRegistrar registrar)
|
||||
{
|
||||
Registrar = new TypeRegistrar(registrar);
|
||||
|
||||
@@ -19,9 +19,6 @@ namespace Spectre.Console.Cli
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
var keyConverter = GetConverter(keyType);
|
||||
var valueConverter = GetConverter(valueType);
|
||||
|
||||
var parts = value.Split(new[] { '=' }, StringSplitOptions.None);
|
||||
if (parts.Length < 1 || parts.Length > 2)
|
||||
{
|
||||
@@ -47,15 +44,16 @@ namespace Spectre.Console.Cli
|
||||
}
|
||||
}
|
||||
|
||||
return (Parse(keyConverter, keyType, stringkey),
|
||||
Parse(valueConverter, valueType, stringValue));
|
||||
return (Parse(stringkey, keyType),
|
||||
Parse(stringValue, valueType));
|
||||
}
|
||||
|
||||
private static object Parse(TypeConverter converter, Type type, string value)
|
||||
private static object? Parse(string value, Type targetType)
|
||||
{
|
||||
try
|
||||
{
|
||||
return converter.ConvertTo(value, type);
|
||||
var converter = GetConverter(targetType);
|
||||
return converter.ConvertFrom(value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Spectre.Console.Cli
|
||||
Type parameterType, ParameterKind parameterKind, PropertyInfo property,
|
||||
string? description, TypeConverterAttribute? converter,
|
||||
DefaultValueAttribute? defaultValue,
|
||||
PairDeconstructorAttribute? deconstuctor,
|
||||
PairDeconstructorAttribute? deconstructor,
|
||||
ParameterValueProviderAttribute? valueProvider,
|
||||
IEnumerable<ParameterValidationAttribute> validators, bool required)
|
||||
{
|
||||
@@ -39,7 +39,7 @@ namespace Spectre.Console.Cli
|
||||
Description = description;
|
||||
Converter = converter;
|
||||
DefaultValue = defaultValue;
|
||||
PairDeconstructor = deconstuctor;
|
||||
PairDeconstructor = deconstructor;
|
||||
ValueProvider = valueProvider;
|
||||
Validators = new List<ParameterValidationAttribute>(validators ?? Array.Empty<ParameterValidationAttribute>());
|
||||
Required = required;
|
||||
|
||||
@@ -20,14 +20,9 @@ namespace Spectre.Console.Cli
|
||||
|
||||
try
|
||||
{
|
||||
if (_resolver != null)
|
||||
var obj = _resolver?.Resolve(type);
|
||||
if (obj != null)
|
||||
{
|
||||
var obj = _resolver.Resolve(type);
|
||||
if (obj == null)
|
||||
{
|
||||
throw CommandRuntimeException.CouldNotResolveType(type);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Spectre.Console.Cli
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The key type.</typeparam>
|
||||
/// <typeparam name="TValue">The value type.</typeparam>
|
||||
public abstract class PairDeconstuctor<TKey, TValue> : IPairDeconstructor
|
||||
public abstract class PairDeconstructor<TKey, TValue> : IPairDeconstructor
|
||||
{
|
||||
/// <summary>
|
||||
/// Deconstructs the provided <see cref="string"/> into a pair.
|
||||
@@ -27,4 +27,15 @@ namespace Spectre.Console.Cli
|
||||
return Deconstruct(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base class for a pair deconstructor.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The key type.</typeparam>
|
||||
/// <typeparam name="TValue">The value type.</typeparam>
|
||||
/// <remarks>This class is misspelled, use <see cref="PairDeconstructor{TKey,TValue}"/> instead.</remarks>
|
||||
[Obsolete("Use PairDeconstructor instead")]
|
||||
public abstract class PairDeconstuctor<TKey, TValue> : PairDeconstructor<TKey, TValue>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -112,6 +112,41 @@ namespace Spectre.Console
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all parent items of the given <paramref name="item"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">The item for which to find the parents.</param>
|
||||
/// <returns>The parent items, or an empty list, if the given item has no parents.</returns>
|
||||
public IEnumerable<T> GetParents(T item)
|
||||
{
|
||||
var promptItem = Tree.Find(item);
|
||||
if (promptItem == null)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(item), "Item not found in tree.");
|
||||
}
|
||||
|
||||
var parents = new List<ListPromptItem<T>>();
|
||||
while (promptItem.Parent != null)
|
||||
{
|
||||
promptItem = promptItem.Parent;
|
||||
parents.Add(promptItem);
|
||||
}
|
||||
|
||||
return parents
|
||||
.ReverseEnumerable()
|
||||
.Select(x => x.Data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the parent item of the given <paramref name="item"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">The item for which to find the parent.</param>
|
||||
/// <returns>The parent item, or <c>null</c> if the given item has no parent.</returns>
|
||||
public T? GetParent(T item)
|
||||
{
|
||||
return GetParents(item).LastOrDefault();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
ListPromptInputResult IListPromptStrategy<T>.HandleInput(ConsoleKeyInfo key, ListPromptState<T> state)
|
||||
{
|
||||
@@ -218,7 +253,7 @@ namespace Spectre.Console
|
||||
var text = (Converter ?? TypeConverterHelper.ConvertToString)?.Invoke(item.Node.Data) ?? item.Node.Data.ToString() ?? "?";
|
||||
if (current)
|
||||
{
|
||||
text = text.RemoveMarkup();
|
||||
text = text.RemoveMarkup().EscapeMarkup();
|
||||
}
|
||||
|
||||
var checkbox = item.Node.IsSelected
|
||||
|
||||
@@ -167,7 +167,7 @@ namespace Spectre.Console
|
||||
var text = (Converter ?? TypeConverterHelper.ConvertToString)?.Invoke(item.Node.Data) ?? item.Node.Data.ToString() ?? "?";
|
||||
if (current)
|
||||
{
|
||||
text = text.RemoveMarkup();
|
||||
text = text.RemoveMarkup().EscapeMarkup();
|
||||
}
|
||||
|
||||
grid.AddRow(new Markup(indent + prompt + " " + text, style));
|
||||
|
||||
@@ -275,7 +275,7 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces prompt user input with asterixes in the console.
|
||||
/// Replaces prompt user input with asterisks in the console.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The prompt type.</typeparam>
|
||||
/// <param name="obj">The prompt.</param>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net5.0;netstandard2.0</TargetFrameworks>
|
||||
<TargetFrameworks>net6.0;net5.0;netstandard2.0</TargetFrameworks>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>true</IsPackable>
|
||||
<NoWarn>SA1633</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Wcwidth" Version="0.2.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.0" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<None Remove="Widgets\Figlet\Fonts\Standard.flf" />
|
||||
<None Include="../../resources/gfx/small-logo.png" Pack="true" PackagePath="\" Link="Properties/small-logo.png" />
|
||||
<None Include="..\.editorconfig" Link="Cli\.editorconfig" />
|
||||
<InternalsVisibleTo Include="$(AssemblyName).Tests" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -26,6 +27,9 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Wcwidth.Sources" Version="0.6.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
@@ -33,4 +37,8 @@
|
||||
<GenerateNullableAttributes>False</GenerateNullableAttributes>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DefineConstants>$(DefineConstants)TRACE;WCWIDTH_VISIBILITY_INTERNAL</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -96,6 +96,21 @@ namespace Spectre.Console
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (int.TryParse(part, out var number))
|
||||
{
|
||||
if (number < 0)
|
||||
{
|
||||
error = $"Color number must be greater than or equal to 0 (was {number})";
|
||||
return null;
|
||||
}
|
||||
else if (number > 255)
|
||||
{
|
||||
error = $"Color number must be less than or equal to 255 (was {number})";
|
||||
return null;
|
||||
}
|
||||
|
||||
color = number;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = !foreground
|
||||
|
||||
@@ -149,12 +149,12 @@ namespace Spectre.Console
|
||||
{
|
||||
builder.AppendWithStyle(
|
||||
settings.Style.NonEmphasized,
|
||||
type.Substring(0, index + 1).EscapeMarkup());
|
||||
type.Substring(0, index + 1));
|
||||
}
|
||||
|
||||
builder.AppendWithStyle(
|
||||
color,
|
||||
type.Substring(index + 1, type.Length - index - 1).EscapeMarkup());
|
||||
type.Substring(index + 1, type.Length - index - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
System.InvalidOperationException: Something threw!
|
||||
System.InvalidOperationException: Throwing!
|
||||
at Spectre.Console.Tests.Data.TestExceptions.GenericMethodThatThrows[[T0,T1,TRet]](Nullable`1 number) in /xyz/Exceptions.cs:nn
|
||||
at Spectre.Console.Tests.Data.TestExceptions.GenericMethodThatThrows[T0,T1,TRet](Nullable`1 number) in /xyz/Exceptions.cs:nn
|
||||
at Spectre.Console.Tests.Data.TestExceptions.ThrowWithGenericInnerException() in /xyz/Exceptions.cs:nn
|
||||
at Spectre.Console.Tests.Data.TestExceptions.ThrowWithGenericInnerException() in /xyz/Exceptions.cs:nn
|
||||
at Spectre.Console.Tests.Unit.ExceptionTests.<>c.<Should_Write_Exceptions_With_Generic_Type_Parameters_In_Callsite_As_Expected>b__4_0() in /xyz/ExceptionTests.cs:nn
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('Windows'))">net5.0;net48</TargetFrameworks>
|
||||
<TargetFramework Condition="!$([MSBuild]::IsOSPlatform('Windows'))">net5.0</TargetFramework>
|
||||
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('Windows'))">net6.0;net5.0;net48</TargetFrameworks>
|
||||
<TargetFrameworks Condition="!$([MSBuild]::IsOSPlatform('Windows'))">net6.0;net5.0</TargetFrameworks>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\src\Spectre.Console\Cli\Internal\Constants.cs" Link="Imported\Constants.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Data\starwars.flf" />
|
||||
</ItemGroup>
|
||||
@@ -24,7 +20,6 @@
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing.XUnit" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="2.6.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Shouldly" Version="4.0.3" />
|
||||
<PackageReference Include="Spectre.Verify.Extensions" Version="0.3.0" />
|
||||
<PackageReference Include="Verify.Xunit" Version="9.0.0-beta.1" />
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using Shouldly;
|
||||
using Spectre.Console.Cli;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using Spectre.Console.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public sealed class Exception_Handling
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Not_Propagate_Runtime_Exceptions_If_Not_Explicitly_Told_To_Do_So()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddCommand<DogCommand>("dog");
|
||||
animal.AddCommand<HorseCommand>("horse");
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[] { "animal", "4", "dog", "101", "--name", "Rufus" });
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(-1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Not_Propagate_Exceptions_If_Not_Explicitly_Told_To_Do_So()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.AddCommand<ThrowingCommand>("throw");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[] { "throw" });
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(-1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Handle_Exceptions_If_ExceptionHandler_Is_Set_Using_Action()
|
||||
{
|
||||
// Given
|
||||
var exceptionHandled = false;
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.AddCommand<ThrowingCommand>("throw");
|
||||
config.SetExceptionHandler(_ =>
|
||||
{
|
||||
exceptionHandled = true;
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[] { "throw" });
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(-1);
|
||||
exceptionHandled.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Handle_Exceptions_If_ExceptionHandler_Is_Set_Using_Function()
|
||||
{
|
||||
// Given
|
||||
var exceptionHandled = false;
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.AddCommand<ThrowingCommand>("throw");
|
||||
config.SetExceptionHandler(_ =>
|
||||
{
|
||||
exceptionHandled = true;
|
||||
return -99;
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[] { "throw" });
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(-99);
|
||||
exceptionHandled.ShouldBeTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,12 @@ namespace Spectre.Console.Tests.Unit.Cli
|
||||
public IDictionary<string, int> Values { get; set; }
|
||||
}
|
||||
|
||||
public sealed class DefaultPairDeconstructorEnumValueSettings : CommandSettings
|
||||
{
|
||||
[CommandOption("--var <VALUE>")]
|
||||
public IDictionary<string, DayOfWeek> Values { get; set; }
|
||||
}
|
||||
|
||||
public sealed class LookupSettings : CommandSettings
|
||||
{
|
||||
[CommandOption("--var <VALUE>")]
|
||||
@@ -56,7 +62,7 @@ namespace Spectre.Console.Tests.Unit.Cli
|
||||
public IReadOnlyDictionary<string, string> Values { get; set; }
|
||||
}
|
||||
|
||||
public sealed class StringIntDeconstructor : PairDeconstuctor<string, string>
|
||||
public sealed class StringIntDeconstructor : PairDeconstructor<string, string>
|
||||
{
|
||||
protected override (string Key, string Value) Deconstruct(string value)
|
||||
{
|
||||
@@ -153,6 +159,35 @@ namespace Spectre.Console.Tests.Unit.Cli
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Map_Pairs_With_Enum_Value_To_Pair_Deconstructable_Collection_Using_Default_Deconstructor()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorEnumValueSettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[]
|
||||
{
|
||||
"--var", "foo=Monday",
|
||||
"--var", "bar=Tuesday",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings.ShouldBeOfType<DefaultPairDeconstructorEnumValueSettings>().And(pair =>
|
||||
{
|
||||
pair.Values.ShouldNotBeNull();
|
||||
pair.Values.Count.ShouldBe(2);
|
||||
pair.Values["foo"].ShouldBe(DayOfWeek.Monday);
|
||||
pair.Values["bar"].ShouldBe(DayOfWeek.Tuesday);
|
||||
});
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("foo=1=2", "Error: The value 'foo=1=2' is not in a correct format")]
|
||||
[InlineData("foo=1=2=3", "Error: The value 'foo=1=2=3' is not in a correct format")]
|
||||
|
||||
@@ -816,46 +816,5 @@ namespace Spectre.Console.Tests.Unit.Cli
|
||||
result.Context.Remaining.Raw[4].ShouldBe("qux");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Exception_Handling
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Not_Propagate_Runtime_Exceptions_If_Not_Explicitly_Told_To_Do_So()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddCommand<DogCommand>("dog");
|
||||
animal.AddCommand<HorseCommand>("horse");
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[] { "animal", "4", "dog", "101", "--name", "Rufus" });
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(-1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Not_Propagate_Exceptions_If_Not_Explicitly_Told_To_Do_So()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.AddCommand<ThrowingCommand>("throw");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[] { "throw" });
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Spectre.Console.Cli;
|
||||
using Spectre.Console.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed class DefaultTypeRegistrarTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Pass_Base_Registrar_Tests()
|
||||
{
|
||||
var harness = new TypeRegistrarBaseTests(() => new DefaultTypeRegistrar());
|
||||
harness.RunAllTests();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,5 +82,75 @@ namespace Spectre.Console.Tests.Unit
|
||||
// Then
|
||||
choice.IsSelected.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Get_The_Direct_Parent()
|
||||
{
|
||||
// Given
|
||||
var prompt = new MultiSelectionPrompt<string>();
|
||||
prompt.AddChoice("root").AddChild("level-1").AddChild("level-2").AddChild("item");
|
||||
|
||||
// When
|
||||
var actual = prompt.GetParent("item");
|
||||
|
||||
// Then
|
||||
actual.ShouldBe("level-2");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Get_The_List_Of_All_Parents()
|
||||
{
|
||||
// Given
|
||||
var prompt = new MultiSelectionPrompt<string>();
|
||||
prompt.AddChoice("root").AddChild("level-1").AddChild("level-2").AddChild("item");
|
||||
|
||||
// When
|
||||
var actual = prompt.GetParents("item");
|
||||
|
||||
// Then
|
||||
actual.ShouldBe(new []{"root", "level-1", "level-2"});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Get_An_Empty_List_Of_Parents_For_Root_Node()
|
||||
{
|
||||
// Given
|
||||
var prompt = new MultiSelectionPrompt<string>();
|
||||
prompt.AddChoice("root");
|
||||
|
||||
// When
|
||||
var actual = prompt.GetParents("root");
|
||||
|
||||
// Then
|
||||
actual.ShouldBeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Get_Null_As_Direct_Parent_Of_Root_Node()
|
||||
{
|
||||
// Given
|
||||
var prompt = new MultiSelectionPrompt<string>();
|
||||
prompt.AddChoice("root");
|
||||
|
||||
// When
|
||||
var actual = prompt.GetParent("root");
|
||||
|
||||
// Then
|
||||
actual.ShouldBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_When_Getting_Parents_Of_Non_Existing_Node()
|
||||
{
|
||||
// Given
|
||||
var prompt = new MultiSelectionPrompt<string>();
|
||||
prompt.AddChoice("root").AddChild("level-1").AddChild("level-2").AddChild("item");
|
||||
|
||||
// When
|
||||
Action action = () => prompt.GetParents("non-existing");
|
||||
|
||||
// Then
|
||||
action.ShouldThrow<ArgumentOutOfRangeException>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using Shouldly;
|
||||
using Spectre.Console.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
public sealed class SelectionPromptTests
|
||||
{
|
||||
[Fact]
|
||||
[GitHubIssue(608)]
|
||||
public void Should_Not_Throw_When_Selecting_An_Item_With_Escaped_Markup()
|
||||
{
|
||||
// Given
|
||||
var console = new TestConsole();
|
||||
console.Profile.Capabilities.Interactive = true;
|
||||
console.Input.PushKey(ConsoleKey.Enter);
|
||||
var input = "[red]This text will never be red[/]".EscapeMarkup();
|
||||
|
||||
// When
|
||||
var prompt = new SelectionPrompt<string>()
|
||||
.Title("Select one")
|
||||
.AddChoices(input);
|
||||
prompt.Show(console);
|
||||
|
||||
// Then
|
||||
console.Output.ShouldContain(@"[red]This text will never be red[/]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,6 +275,31 @@ namespace Spectre.Console.Tests.Unit
|
||||
result.Background.ShouldBe(Color.Blue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("12 on 24")]
|
||||
public void Should_Parse_Colors_Numbers_Correctly(string style)
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.Parse(style);
|
||||
|
||||
// Then
|
||||
result.Foreground.ShouldBe(Color.Blue);
|
||||
result.Background.ShouldBe(Color.DeepSkyBlue4_1);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("-12", "Color number must be greater than or equal to 0 (was -12)")]
|
||||
[InlineData("256", "Color number must be less than or equal to 255 (was 256)")]
|
||||
public void Should_Return_Error_If_Color_Number_Is_Invalid(string style, string expected)
|
||||
{
|
||||
// Given, When
|
||||
var result = Record.Exception(() => Style.Parse(style));
|
||||
|
||||
// Then
|
||||
result.ShouldNotBeNull();
|
||||
result.Message.ShouldBe(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("rgb()", "Invalid RGB color 'rgb()'.")]
|
||||
[InlineData("rgb(", "Invalid RGB color 'rgb('.")]
|
||||
|
||||
Reference in New Issue
Block a user