Merge remote-tracking branch 'upstream/main' into blz/issues/1390

# Conflicts:
#	src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Three_And_One_Columns.Output.verified.txt
This commit is contained in:
BlazeFace 2024-10-25 17:47:02 -07:00
commit 444dbed259
722 changed files with 1450 additions and 6551 deletions

View File

@ -26,3 +26,6 @@ If applicable, add screenshots to help explain your problem.
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.
---
Please upvote :+1: this issue if you are interested in it.

View File

@ -18,3 +18,6 @@ A clear and concise description of any alternative solutions or features you've
**Additional context** **Additional context**
Add any other context or screenshots about the feature request here. Add any other context or screenshots about the feature request here.
---
Please upvote :+1: this issue if you are interested in it.

View File

@ -17,3 +17,6 @@ fixes #
## Changes ## Changes
<!-- describe the changes you made. --> <!-- describe the changes you made. -->
---
Please upvote :+1: this pull request if you are interested in it.

View File

@ -0,0 +1,24 @@
name: Top issues action.
on:
schedule:
- cron: '0 0 */1 * *'
jobs:
ShowAndLabelTopIssues:
name: Display and label top issues.
runs-on: ubuntu-latest
steps:
- name: Top Issues action
uses: rickstaa/top-issues-action@v1.3.101
env:
github_token: ${{ secrets.GITHUB_TOKEN }}
with:
top_list_size: 10
label: true
dashboard: true
dashboard_show_total_reactions: true
top_issues: true
top_bugs: true
top_features: true
feature_label: feature
top_pull_requests: true

View File

@ -39,7 +39,7 @@ What is generally considered trivial:
### Code style ### Code style
Normal .NET coding guidelines apply. Normal .NET coding guidelines apply.
See the [Framework Design Guidelines](https://msdn.microsoft.com/en-us/library/ms229042%28v=vs.110%29.aspx) for more information. See the [Framework Design Guidelines](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/) for more information.
### Dependencies ### Dependencies
@ -59,7 +59,7 @@ Any new code should also have reasonable unit test coverage.
information and a link back to the discussion. information and a link back to the discussion.
* Once you get a nod from someone in the Spectre.Console Team, you can start on the feature. * Once you get a nod from someone in the Spectre.Console Team, you can start on the feature.
* Alternatively, if a feature is on the issues list with the * Alternatively, if a feature is on the issues list with the
[Up For Grabs](https://github.com/spectreconsole/spectre.console/labels/up-for-grabs) label, [good first issue](https://github.com/spectreconsole/spectre.console/labels/good%20first%20issue) label,
it is open for a community member (contributor) to patch. You should comment that you are signing up for it on it is open for a community member (contributor) to patch. You should comment that you are signing up for it on
the issue so someone else doesn't also sign up for the work. the issue so someone else doesn't also sign up for the work.
@ -158,4 +158,4 @@ Harder for us roughly translates to a longer SLA for your pull request.
## Acknowledgement ## Acknowledgement
This contribution guide was taken from the [Chocolatey project](https://chocolatey.org/) This contribution guide was taken from the [Chocolatey project](https://chocolatey.org/)
with permission and was edited to follow Spectre.Console's conventions and processes. with permission and was edited to follow Spectre.Console's conventions and processes.

View File

@ -44,30 +44,13 @@ https://spectreconsole.net/
<h2 id="examples">مثال‌ها</h2> <h2 id="examples">مثال‌ها</h2>
برای بررسی `Spectre.Console` در عمل، ابزار سراسری To see `Spectre.Console` in action, please see the
[dotnet-example](https://github.com/patriksvensson/dotnet-example) [examples repository](https://github.com/spectreconsole/examples).
را نصب کنید.
<pre dir="ltr">
> dotnet tool restore
</pre>
حالا شما می‌توانید مثال‌های موجود در این مخزن را لیست کنید:
<pre dir="ltr">
> dotnet example
</pre>
و برای اجرای مثال:
<pre dir="ltr">
> dotnet example tables
</pre>
<h2 id="license">مجوز</h2> <h2 id="license">مجوز</h2>
<div dir="ltr"> <div dir="ltr">
Copyright © Patrik Svensson, Phil Scott Copyright © Patrik Svensson, Phil Scott, Nils Andresen, Cédric Luthi, Frank Ray
</div> </div>
همانطور که Spectre.Console تحت مجوز MIT ارائه شده است؛ برای کسب اطلاعات بیشتر به مجوز مراجعه کنید. همانطور که Spectre.Console تحت مجوز MIT ارائه شده است؛ برای کسب اطلاعات بیشتر به مجوز مراجعه کنید.

View File

@ -3,8 +3,7 @@
_[![Spectre.Console NuGet Version](https://img.shields.io/nuget/v/spectre.console.svg?style=flat&label=NuGet%3A%20Spectre.Console)](https://www.nuget.org/packages/spectre.console)_ _[![Spectre.Console CLI NuGet Version](https://img.shields.io/nuget/v/spectre.console.cli.svg?style=flat&label=NuGet%3A%20Spectre.Console.Cli)](https://www.nuget.org/packages/spectre.console.cli)_ [![Netlify Status](https://api.netlify.com/api/v1/badges/1eaf215a-eb9c-45e4-8c64-c90b62963149/deploy-status)](https://app.netlify.com/sites/spectreconsole/deploys) _[![Spectre.Console NuGet Version](https://img.shields.io/nuget/v/spectre.console.svg?style=flat&label=NuGet%3A%20Spectre.Console)](https://www.nuget.org/packages/spectre.console)_ _[![Spectre.Console CLI NuGet Version](https://img.shields.io/nuget/v/spectre.console.cli.svg?style=flat&label=NuGet%3A%20Spectre.Console.Cli)](https://www.nuget.org/packages/spectre.console.cli)_ [![Netlify Status](https://api.netlify.com/api/v1/badges/1eaf215a-eb9c-45e4-8c64-c90b62963149/deploy-status)](https://app.netlify.com/sites/spectreconsole/deploys)
A .NET library that makes it easier to create beautiful, cross platform, console applications. A .NET library that makes it easier to create beautiful, cross platform, console applications.
It is heavily inspired by the excellent [Rich library](https://github.com/willmcgugan/rich) It is heavily inspired by the excellent Python library, [Rich](https://github.com/willmcgugan/rich). Detailed instructions for using `Spectre.Console` are located on the project website, https://spectreconsole.net
for Python. For detailed usage instructions, [please refer to the documentation at https://spectreconsole.net/.](https://spectreconsole.net/)
## Table of Contents ## Table of Contents
@ -19,18 +18,22 @@ for Python. For detailed usage instructions, [please refer to the documentation
## Features ## Features
* Written with unit testing in mind. * Supports tables, grids, panels, and a [Rich](https://github.com/willmcgugan/rich) inspired markup language.
* Supports tables, grids, panels, and a [rich](https://github.com/willmcgugan/rich) inspired markup language.
* Supports the most common SRG parameters when it comes to text * Supports the most common SRG parameters when it comes to text
styling such as bold, dim, italic, underline, strikethrough, styling such as bold, dim, italic, underline, strikethrough,
and blinking text. and blinking text.
* Supports 3/4/8/24-bit colors in the terminal. * Supports 3/4/8/24-bit colors in the terminal.
The library will detect the capabilities of the current terminal The library will detect the capabilities of the current terminal
and downgrade colors as needed. and downgrade colors as needed.
* Written with unit testing in mind.
![Example](docs/input/assets/images/example.png) ![Example](docs/input/assets/images/example.png)
## Important Notices
> [!IMPORTANT]\
> We use the [Top Issues Dashboard](https://github.com/spectreconsole/spectre.console/issues/1517) for tracking community demand. Please upvote :+1: the issues and pull requests you are interested in.
## Installing ## Installing
The fastest way of getting started using `Spectre.Console` is to install the NuGet package. The fastest way of getting started using `Spectre.Console` is to install the NuGet package.
@ -42,34 +45,17 @@ dotnet add package Spectre.Console
## Documentation ## Documentation
The documentation for `Spectre.Console` can be found at The documentation for `Spectre.Console` can be found at
https://spectreconsole.net/ https://spectreconsole.net
## Examples ## Examples
To see `Spectre.Console` in action, install the To see `Spectre.Console` in action, please see the
[dotnet-example](https://github.com/patriksvensson/dotnet-example) [examples repository](https://github.com/spectreconsole/examples).
global tool.
```
> dotnet tool restore
```
Now you can list available examples in this repository:
```
> dotnet example
```
And to run an example:
```
> dotnet example tables
```
## Sponsors ## Sponsors
The following people are [sponsoring](https://github.com/sponsors/patriksvensson) The following people are [sponsoring](https://github.com/sponsors/patriksvensson)
Spectre.Console to show their support and to ensure the longevity of the project. `Spectre.Console` to show their support and to ensure the longevity of the project.
* [Rodney Littles II](https://github.com/RLittlesII) * [Rodney Littles II](https://github.com/RLittlesII)
* [Martin Björkström](https://github.com/bjorkstromm) * [Martin Björkström](https://github.com/bjorkstromm)
@ -97,8 +83,8 @@ This project is supported by the [.NET Foundation](https://dotnetfoundation.org)
## License ## License
Copyright © Patrik Svensson, Phil Scott, Nils Andresen Copyright © Patrik Svensson, Phil Scott, Nils Andresen, Cédric Luthi, Frank Ray
Spectre.Console is provided as-is under the MIT license. For more information see LICENSE. `Spectre.Console` is provided as-is under the MIT license. For more information see LICENSE.
* SixLabors.ImageSharp, a library which Spectre.Console relies upon, is licensed under Apache 2.0 when distributed as part of Spectre.Console. The Six Labors Split License covers all other usage, see: https://github.com/SixLabors/ImageSharp/blob/master/LICENSE * SixLabors.ImageSharp, a library which `Spectre.Console` relies upon, is licensed under Apache 2.0 when distributed as part of `Spectre.Console`. The Six Labors Split License covers all other usage, see: https://github.com/SixLabors/ImageSharp/blob/master/LICENSE

View File

@ -43,24 +43,8 @@ https://spectreconsole.net/
## Exemplos ## Exemplos
Para ver o `Spectre.Console` em ação, instale a ferramenta global To see `Spectre.Console` in action, please see the
[dotnet-example](https://github.com/patriksvensson/dotnet-example). [examples repository](https://github.com/spectreconsole/examples).
```
> dotnet tool restore
```
Agora você pode listar os exemplos disponíveis neste repositório:
```
> dotnet example
```
E para executar um exemplo:
```
> dotnet example tables
```
## Patrocinadores ## Patrocinadores
@ -83,7 +67,7 @@ Eu estou muito agradecido.
## Licença ## Licença
Copyright © Patrik Svensson, Phil Scott, Nils Andresen Copyright © Patrik Svensson, Phil Scott, Nils Andresen, Cédric Luthi, Frank Ray
Spectre.Console é fornecido no estado em que se encontra sob a licença do MIT. Para obter mais informações, consulte o arquivo [LICENSE](LICENSE.md). Spectre.Console é fornecido no estado em que se encontra sob a licença do MIT. Para obter mais informações, consulte o arquivo [LICENSE](LICENSE.md).

View File

@ -39,23 +39,8 @@ https://spectreconsole.net/
## 例子 ## 例子
如果想直接运行`Spectre.Console`的例子,则需要安装[dotnet-example](https://github.com/patriksvensson/dotnet-example)工具。 To see `Spectre.Console` in action, please see the
[examples repository](https://github.com/spectreconsole/examples).
```
> dotnet tool restore
```
然后你可以列出仓库里的所有例子:
```
> dotnet example
```
跑一个看看效果:
```
> dotnet example tables
```
## Sponsors ## Sponsors
@ -77,7 +62,7 @@ https://spectreconsole.net/
## 开源许可 ## 开源许可
版权所有 © Patrik Svensson, Phil Scott, Nils Andresen 版权所有 © Patrik Svensson, Phil Scott, Nils Andresen, Cédric Luthi, Frank Ray
Spectre.Console 基于 MIT 协议提供。查看 LICENSE 文件了解更多信息。 Spectre.Console 基于 MIT 协议提供。查看 LICENSE 文件了解更多信息。

View File

@ -35,41 +35,11 @@ Task("Build")
}); });
}); });
Task("Build-Analyzer")
.IsDependentOn("Build")
.Does(context =>
{
DotNetBuild("./src/Spectre.Console.Analyzer.sln", new DotNetBuildSettings {
Configuration = configuration,
Verbosity = DotNetVerbosity.Minimal,
NoLogo = true,
NoIncremental = context.HasArgument("rebuild"),
MSBuildSettings = new DotNetMSBuildSettings()
.TreatAllWarningsAs(MSBuildTreatAllWarningsAs.Error)
});
});
Task("Build-Examples")
.IsDependentOn("Build")
.Does(context =>
{
DotNetBuild("./examples/Examples.sln", new DotNetBuildSettings {
Configuration = configuration,
Verbosity = DotNetVerbosity.Minimal,
NoLogo = true,
NoIncremental = context.HasArgument("rebuild"),
MSBuildSettings = new DotNetMSBuildSettings()
.TreatAllWarningsAs(MSBuildTreatAllWarningsAs.Error)
});
});
Task("Test") Task("Test")
.IsDependentOn("Build") .IsDependentOn("Build")
.IsDependentOn("Build-Analyzer")
.IsDependentOn("Build-Examples")
.Does(context => .Does(context =>
{ {
DotNetTest("./test/Spectre.Console.Tests/Spectre.Console.Tests.csproj", new DotNetTestSettings { DotNetTest("./src/Tests/Spectre.Console.Tests/Spectre.Console.Tests.csproj", new DotNetTestSettings {
Configuration = configuration, Configuration = configuration,
Verbosity = DotNetVerbosity.Minimal, Verbosity = DotNetVerbosity.Minimal,
NoLogo = true, NoLogo = true,
@ -77,15 +47,7 @@ Task("Test")
NoBuild = true, NoBuild = true,
}); });
DotNetTest("./test/Spectre.Console.Cli.Tests/Spectre.Console.Cli.Tests.csproj", new DotNetTestSettings { DotNetTest("./src/Tests/Spectre.Console.Cli.Tests/Spectre.Console.Cli.Tests.csproj", new DotNetTestSettings {
Configuration = configuration,
Verbosity = DotNetVerbosity.Minimal,
NoLogo = true,
NoRestore = true,
NoBuild = true,
});
DotNetTest("./test/Spectre.Console.Analyzer.Tests/Spectre.Console.Analyzer.Tests.csproj", new DotNetTestSettings {
Configuration = configuration, Configuration = configuration,
Verbosity = DotNetVerbosity.Minimal, Verbosity = DotNetVerbosity.Minimal,
NoLogo = true, NoLogo = true,
@ -108,17 +70,6 @@ Task("Package")
MSBuildSettings = new DotNetMSBuildSettings() MSBuildSettings = new DotNetMSBuildSettings()
.TreatAllWarningsAs(MSBuildTreatAllWarningsAs.Error) .TreatAllWarningsAs(MSBuildTreatAllWarningsAs.Error)
}); });
context.DotNetPack($"./src/Spectre.Console.Analyzer.sln", new DotNetPackSettings {
Configuration = configuration,
Verbosity = DotNetVerbosity.Minimal,
NoLogo = true,
NoRestore = true,
NoBuild = true,
OutputDirectory = "./.artifacts",
MSBuildSettings = new DotNetMSBuildSettings()
.TreatAllWarningsAs(MSBuildTreatAllWarningsAs.Error)
});
}); });
Task("Publish-NuGet") Task("Publish-NuGet")

View File

@ -60,7 +60,7 @@ Spectre.Console will tell your terminal to use the color that is configured in t
If you are using an 8 or 24-bit color for the foreground text, it is recommended that you also set an appropriate If you are using an 8 or 24-bit color for the foreground text, it is recommended that you also set an appropriate
background color to match. background color to match.
**Do** escape data when outputting any user input or any external data via Markup using the [`EscapeMarkup`](xref:M:Spectre.Console.Markup.Escape(System.String)) method on the data. Any user input containing `[` or `]` will likely cause a runtime error while rendering otherwise. **Do** escape data when outputting any user input or any external data via Markup using the [`Markup.Escape`](xref:M:Spectre.Console.Markup.Escape(System.String)) method on the data. Any user input containing `[` or `]` will likely cause a runtime error while rendering otherwise.
**Consider** replacing `Markup` and `MarkupLine` with [`MarkupInterpolated`](xref:M:Spectre.Console.AnsiConsole.MarkupInterpolated(System.FormattableString)) and [`MarkupLineInterpolated`](xref:M:Spectre.Console.AnsiConsole.MarkupLineInterpolated(System.FormattableString)). Both these methods will automatically escape all data in the interpolated string holes. When working with widgets such as the Table and Tree, consider using [`Markup.FromInterpolated`](xref:M:Spectre.Console.Markup.FromInterpolated(System.FormattableString,Spectre.Console.Style)) to generate an `IRenderable` from an interpolated string. **Consider** replacing `Markup` and `MarkupLine` with [`MarkupInterpolated`](xref:M:Spectre.Console.AnsiConsole.MarkupInterpolated(System.FormattableString)) and [`MarkupLineInterpolated`](xref:M:Spectre.Console.AnsiConsole.MarkupLineInterpolated(System.FormattableString)). Both these methods will automatically escape all data in the interpolated string holes. When working with widgets such as the Table and Tree, consider using [`Markup.FromInterpolated`](xref:M:Spectre.Console.Markup.FromInterpolated(System.FormattableString,Spectre.Console.Style)) to generate an `IRenderable` from an interpolated string.
@ -119,4 +119,4 @@ For cmd.exe, the following steps are required to enable Unicode and Emoji suppor
5. Reboot. 5. Reboot.
You will also need to ensure that your Console application is configured to use a font that supports Unicode and Emoji, You will also need to ensure that your Console application is configured to use a font that supports Unicode and Emoji,
such as Cascadia Code. such as Cascadia Code.

View File

@ -0,0 +1,55 @@
Title: Spectre.Console 0.49 released!
Description: Bug fixes, bug fixes, bug fixes
Published: 2024-04-23
Category: Release Notes
Excluded: false
---
Version 0.49 of Spectre.Console has been released!
## New Contributors
* @baronfel made their first contribution in https://github.com/spectreconsole/spectre.console/pull/1425
* @DarqueWarrior made their first contribution in https://github.com/spectreconsole/spectre.console/pull/1431
* @tonycknight made their first contribution in https://github.com/spectreconsole/spectre.console/pull/1435
* @caesay made their first contribution in https://github.com/spectreconsole/spectre.console/pull/1439
* @jsheely made their first contribution in https://github.com/spectreconsole/spectre.console/pull/1414
* @danielcweber made their first contribution in https://github.com/spectreconsole/spectre.console/pull/1456
* @martincostello made their first contribution in https://github.com/spectreconsole/spectre.console/pull/1477
* @slang25 made their first contribution in https://github.com/spectreconsole/spectre.console/pull/1289
* @thomhurst made their first contribution in https://github.com/spectreconsole/spectre.console/pull/1250
* @gerardog made their first contribution in https://github.com/spectreconsole/spectre.console/pull/1489
* @yenneferofvengerberg made their first contribution in https://github.com/spectreconsole/spectre.console/pull/1503
* @BlazeFace made their first contribution in https://github.com/spectreconsole/spectre.console/pull/1509
## Changes
* Cleanup line endings by @nils-a in https://github.com/spectreconsole/spectre.console/pull/1381
* Added Spectre.Console.Cli to quick-start. by @nils-a in https://github.com/spectreconsole/spectre.console/pull/1413
* Fix rendering of ListPrompt for odd pageSizes by @nils-a in https://github.com/spectreconsole/spectre.console/pull/1365
* Remove mandelbrot example due to conflicting license by @patriksvensson in https://github.com/spectreconsole/spectre.console/pull/1426
* Allow specifying a property to ignore the use of build-time packages for versioning and analysis by @baronfel in https://github.com/spectreconsole/spectre.console/pull/1425
* Add the possibility to register multiple interceptors by @nils-a in https://github.com/spectreconsole/spectre.console/pull/1412
* Added the ITypeResolver to the ExceptionHandler by @nils-a in https://github.com/spectreconsole/spectre.console/pull/1411
* Updated typo in commandApp.md by @DarqueWarrior in https://github.com/spectreconsole/spectre.console/pull/1431
* Command with -v displays app version instead of executing the command by @FrankRay78 in https://github.com/spectreconsole/spectre.console/pull/1427
* HelpProvider colors should be configurable by @FrankRay78 in https://github.com/spectreconsole/spectre.console/pull/1408
* Direct contributors to the current CONTRIBUTING.md by @tonycknight in https://github.com/spectreconsole/spectre.console/pull/1435
* Fix deadlock when cancelling prompts by @caesay in https://github.com/spectreconsole/spectre.console/pull/1439
* Add progress bar value formatter by @jsheely in https://github.com/spectreconsole/spectre.console/pull/1414
* Update dependencies and do some clean-up by @patriksvensson in https://github.com/spectreconsole/spectre.console/pull/1440
* Delete [UsesVerify], which has become obsolete through the latest update. by @danielcweber in https://github.com/spectreconsole/spectre.console/pull/1456
* Don't erase secret prompt text upon backspace when mask is null by @danielcweber in https://github.com/spectreconsole/spectre.console/pull/1458
* Update dependencies to the latest version by @patriksvensson in https://github.com/spectreconsole/spectre.console/pull/1459
* Automatically register command settings by @patriksvensson in https://github.com/spectreconsole/spectre.console/pull/1463
* Remove [DebuggerDisplay] from Paragraph by @martincostello in https://github.com/spectreconsole/spectre.console/pull/1477
* Selection Prompt Search by @slang25 in https://github.com/spectreconsole/spectre.console/pull/1289
* Update dependency SixLabors.ImageSharp to v3.1.3 by @renovate in https://github.com/spectreconsole/spectre.console/pull/1486
* Positioned Progress Tasks - Before or After Other Tasks by @thomhurst in https://github.com/spectreconsole/spectre.console/pull/1250
* Added NoStackTrace to ExceptionFormats by @gerardog in https://github.com/spectreconsole/spectre.console/pull/1489
* Pipe character for listing options (issue 1434) by @FrankRay78 in https://github.com/spectreconsole/spectre.console/pull/1498
* Improve XmlDoc output by @yenneferofvengerberg in https://github.com/spectreconsole/spectre.console/pull/1503
* Revert 71a5d830 to undo flickering regression by @phil-scott-78 in https://github.com/spectreconsole/spectre.console/pull/1504
* AddDelegate uses an abstract type when used in a branch by @BlazeFace in https://github.com/spectreconsole/spectre.console/pull/1509
* Missing Separator When Headers are Hidden by @BlazeFace in https://github.com/spectreconsole/spectre.console/pull/1513
* Expose raw arguments on the command context by @patriksvensson in https://github.com/spectreconsole/spectre.console/pull/1523
* Add token representation to remaining arguments by @patriksvensson in https://github.com/spectreconsole/spectre.console/pull/1525

View File

@ -1,3 +1,3 @@
@{ @{
Layout = @$"_layout.cshtml"; Layout = "_layout.cshtml";
} }

View File

@ -71,5 +71,5 @@ public static class Program
} }
``` ```
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/examples/tree/main/examples/Cli/Help) demonstrating this.

View File

@ -75,7 +75,7 @@ var app = new CommandApp<DefaultCommand>(registrar);
return app.Run(args); 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. `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/examples/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, 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. 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.
@ -89,4 +89,4 @@ This provides an opportunity to modify the result and also to tear down any infr
The `Intercept`-Method of each interceptor is run before the command is executed and the `InterceptResult`-Method is run after it. These are typically used for configuring logging or other infrastructure concerns. The `Intercept`-Method of each interceptor is run before the command is executed and the `InterceptResult`-Method is run after it. These are typically used for configuring logging or other infrastructure concerns.
For an example of using the interceptor to configure logging, see the [Serilog demo](https://github.com/spectreconsole/spectre.console/tree/main/examples/Cli/Logging). For an example of using the interceptor to configure logging, see the [Serilog demo](https://github.com/spectreconsole/examples/tree/main/examples/Cli/Logging).

View File

@ -105,7 +105,7 @@ A `CommandOption` can be defined as an array like the following:
```csharp ```csharp
[CommandOption("-n|--name <VALUES>")] [CommandOption("-n|--name <VALUES>")]
public string[] Names { get; set; }, public string[] Names { get; set; }
``` ```
This would allow the user to run `app.exe --name Dwayne --name Elizondo --name "Mountain Dew" --name Herbert --name Camacho` and would result in a 5 element array consisting of Dwayne, Elizondo, Mountain Dew, Herbert and Camacho. This would allow the user to run `app.exe --name Dwayne --name Elizondo --name "Mountain Dew" --name Herbert --name Camacho` and would result in a 5 element array consisting of Dwayne, Elizondo, Mountain Dew, Herbert and Camacho.

View File

@ -27,6 +27,32 @@ you can use the `Prompt<TResult>`.
Run prompt example? [y/n] (y): _ Run prompt example? [y/n] (y): _
``` ```
### Usage
```csharp
// Ask the user to confirm
var confirmation = AnsiConsole.Prompt(
new TextPrompt<bool>("Run prompt example?")
.AddChoice(true)
.AddChoice(false)
.DefaultValue(true)
.WithConverter(choice => choice ? "y" : "n"));
// Echo the confirmation back to the terminal
Console.WriteLine(confirmation ? "Confirmed" : "Declined");
```
Otherwise it is possible to use the `ConfirmationPrompt`
```csharp
// Ask the user to confirm
var confirmation = AnsiConsole.Prompt(
new ConfirmationPrompt("Run prompt example?"));
// Echo the confirmation back to the terminal
Console.WriteLine(confirmation ? "Confirmed" : "Declined");
```
## Simple ## Simple
<?# Example symbol="M:Prompt.Program.AskName" project="Prompt" /?> <?# Example symbol="M:Prompt.Program.AskName" project="Prompt" /?>
@ -36,6 +62,30 @@ What's your name? Patrik
What's your age? 37 What's your age? 37
``` ```
### Usage
```csharp
// Ask the user a couple of simple questions
var name = AnsiConsole.Prompt(
new TextPrompt<string>("What's your name?"));
var age = AnsiConsole.Prompt(
new TextPrompt<int>("What's your age?"));
// Echo the name and age back to the terminal
AnsiConsole.WriteLine($"So you're {name} and you're {age} years old");
```
Otherwise it is possible to use the `Ask` method
```csharp
// Ask the user a couple of simple questions
var name = AnsiConsole.Ask<string>("What's your name?");
var age = AnsiConsole.Ask<int>("What's your age?");
// Echo the name and age back to the terminal
AnsiConsole.WriteLine($"So you're {name} and you're {age} years old");
```
## Choices ## Choices
<?# Example symbol="M:Prompt.Program.AskFruit" project="Prompt" /?> <?# Example symbol="M:Prompt.Program.AskFruit" project="Prompt" /?>
@ -44,6 +94,19 @@ What's your age? 37
What's your favorite fruit? [Apple/Banana/Orange] (Orange): _ What's your favorite fruit? [Apple/Banana/Orange] (Orange): _
``` ```
### Usage
```csharp
// Ask for the user's favorite fruit
var fruit = AnsiConsole.Prompt(
new TextPrompt<string>("What's your favorite fruit?")
.AddChoices(["Apple", "Banana", "Orange"])
.DefaultValue("Orange"));
// Echo the fruit back to the terminal
Console.WriteLine($"I agree. {fruit} is tasty!");
```
## Validation ## Validation
<?# Example symbol="M:Prompt.Program.AskAge" project="Prompt" /?> <?# Example symbol="M:Prompt.Program.AskAge" project="Prompt" /?>
@ -56,6 +119,23 @@ Too high
What's the secret number? _ What's the secret number? _
``` ```
### Usage
```csharp
// Ask the user to guess the secret number
var number = AnsiConsole.Prompt(
new TextPrompt<int>("What's the secret number?")
.Validate((n) => n switch
{
< 50 => ValidationResult.Error("Too low"),
50 => ValidationResult.Success(),
> 50 => ValidationResult.Error("Too high"),
}));
// Echo the user's success back to the terminal
Console.WriteLine($"Correct! The secret number is {number}.");
```
## Secrets ## Secrets
<?# Example symbol="M:Prompt.Program.AskPassword" project="Prompt" /?> <?# Example symbol="M:Prompt.Program.AskPassword" project="Prompt" /?>
@ -65,6 +145,18 @@ What's the secret number? _
Enter password: ************_ Enter password: ************_
``` ```
### Usage
```csharp
// Ask the user to enter the password
var password = AnsiConsole.Prompt(
new TextPrompt<string>("Enter password:")
.Secret());
// Echo the password back to the terminal
Console.WriteLine($"Your password is {password}");
```
## Masks ## Masks
<?# Example symbol="M:Prompt.Program.AskPasswordWithCustomMask" project="Prompt" /?> <?# Example symbol="M:Prompt.Program.AskPasswordWithCustomMask" project="Prompt" /?>
@ -82,10 +174,36 @@ You can utilize a null character to completely hide input.
Enter password: _ Enter password: _
``` ```
### Usage
```csharp
// Ask the user to enter the password
var password = AnsiConsole.Prompt(
new TextPrompt<string>("Enter password:")
.Secret('-'));
// Echo the password back to the terminal
Console.WriteLine($"Your password is {password}");
```
## Optional ## Optional
<?# Example symbol="M:Prompt.Program.AskColor" project="Prompt" /?> <?# Example symbol="M:Prompt.Program.AskColor" project="Prompt" /?>
```text ```text
[Optional] Favorite color? _ [Optional] Favorite color? _
```
### Usage
```csharp
// Ask the user to enter the password
var color = AnsiConsole.Prompt(
new TextPrompt<string>("[[Optional]] Favorite color?")
.AllowEmpty());
// Echo the color back to the terminal
Console.WriteLine(string.IsNullOrWhiteSpace(color)
? "You're right, all colors are beautiful"
: $"I agree. {color} is a very beautiful color");
``` ```

View File

@ -15,7 +15,7 @@
<div id="container"> <div id="container">
<div id="console"> <div id="console">
<div class="line"><span style="color:var(--brightBlack)">╭─</span><span style="color:var(--folder)">&#xe0b2;</span><span style="background-color:var(--folder);color:var(--black)"> ~/spectre.console</span><span style="color:var(--folder);background-color:var(--dotnet)">&#xe0b0;</span><span style="background-color:var(--blue)"> .NET 7.0 </span><span style="color:var(--dotnet);background-color:var(--git)">&#xe0b0;</span><span style="background-color:var(--git);color:var(--background)"> &#xe0a0; main </span><span style="color:var(--git)">&#xe0b4;</span></div> <div class="line"><span style="color:var(--brightBlack)">╭─</span><span style="color:var(--folder)">&#xe0b2;</span><span style="background-color:var(--folder);color:var(--black)"> ~/spectre.console</span><span style="color:var(--folder);background-color:var(--dotnet)">&#xe0b0;</span><span style="background-color:var(--blue)"> .NET 8.0 </span><span style="color:var(--dotnet);background-color:var(--git)">&#xe0b0;</span><span style="background-color:var(--git);color:var(--background)"> &#xe0a0; main </span><span style="color:var(--git)">&#xe0b4;</span></div>
<div class="line"><span style="color:var(--brightBlack)">╰─</span> dotnet run</div> <div class="line"><span style="color:var(--brightBlack)">╰─</span> dotnet run</div>
<div class="line"></div> <div class="line"></div>
<div class="line">╭────────────────────────────────────────────────────────╮</div> <div class="line">╭────────────────────────────────────────────────────────╮</div>

View File

@ -13,6 +13,12 @@
"commands": [ "commands": [
"dotnet-example" "dotnet-example"
] ]
},
"verify.tool": {
"version": "0.6.0",
"commands": [
"dotnet-verify"
]
} }
} }
} }

View File

@ -1,15 +0,0 @@
using System.ComponentModel;
using Spectre.Console.Cli;
namespace Delegates;
public static partial class Program
{
public sealed class BarSettings : CommandSettings
{
[CommandOption("--count")]
[Description("The number of bars to print")]
[DefaultValue(3)]
public int Count { get; set; }
}
}

View File

@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<ExampleName>Delegates</ExampleName>
<ExampleDescription>Demonstrates how to specify commands as delegates.</ExampleDescription>
<ExampleGroup>Cli</ExampleGroup>
<ExampleVisible>false</ExampleVisible>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,61 +0,0 @@
using System.Threading.Tasks;
using Spectre.Console;
using Spectre.Console.Cli;
namespace Delegates;
public static partial class Program
{
public static int Main(string[] args)
{
var app = new CommandApp();
app.Configure(config =>
{
config.AddDelegate("foo", Foo)
.WithDescription("Foos the bars");
config.AddDelegate<BarSettings>("bar", Bar)
.WithDescription("Bars the foos");
config.AddAsyncDelegate("fooAsync", FooAsync)
.WithDescription("Foos the bars asynchronously");
config.AddAsyncDelegate<BarSettings>("barAsync", BarAsync)
.WithDescription("Bars the foos asynchronously");
});
return app.Run(args);
}
private static int Foo(CommandContext context)
{
AnsiConsole.WriteLine("Foo");
return 0;
}
private static int Bar(CommandContext context, BarSettings settings)
{
for (var index = 0; index < settings.Count; index++)
{
AnsiConsole.WriteLine("Bar");
}
return 0;
}
private static Task<int> FooAsync(CommandContext context)
{
AnsiConsole.WriteLine("Foo");
return Task.FromResult(0);
}
private static Task<int> BarAsync(CommandContext context, BarSettings settings)
{
for (var index = 0; index < settings.Count; index++)
{
AnsiConsole.WriteLine("Bar");
}
return Task.FromResult(0);
}
}

View File

@ -1,46 +0,0 @@
using System.ComponentModel;
using Demo.Utilities;
using Spectre.Console.Cli;
namespace Demo.Commands.Add;
[Description("Add a NuGet package reference to the project.")]
public sealed class AddPackageCommand : Command<AddPackageCommand.Settings>
{
public sealed class Settings : AddSettings
{
[CommandArgument(0, "<PACKAGENAME>")]
[Description("The package reference to add.")]
public string PackageName { get; set; }
[CommandOption("-v|--version <VERSION>")]
[Description("The version of the package to add.")]
public string Version { get; set; }
[CommandOption("-f|--framework <FRAMEWORK>")]
[Description("Add the reference only when targeting a specific framework.")]
public string Framework { get; set; }
[CommandOption("--no-restore")]
[Description("Add the reference without performing restore preview and compatibility check.")]
public bool NoRestore { get; set; }
[CommandOption("--source <SOURCE>")]
[Description("The NuGet package source to use during the restore.")]
public string Source { get; set; }
[CommandOption("--package-directory <PACKAGEDIR>")]
[Description("The directory to restore packages to.")]
public string PackageDirectory { get; set; }
[CommandOption("--interactive")]
[Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")]
public bool Interactive { get; set; }
}
public override int Execute(CommandContext context, Settings settings)
{
SettingsDumper.Dump(settings);
return 0;
}
}

View File

@ -1,29 +0,0 @@
using System.ComponentModel;
using Demo.Utilities;
using Spectre.Console.Cli;
namespace Demo.Commands.Add;
public sealed class AddReferenceCommand : Command<AddReferenceCommand.Settings>
{
public sealed class Settings : AddSettings
{
[CommandArgument(0, "<PROJECTPATH>")]
[Description("The package reference to add.")]
public string ProjectPath { get; set; }
[CommandOption("-f|--framework <FRAMEWORK>")]
[Description("Add the reference only when targeting a specific framework.")]
public string Framework { get; set; }
[CommandOption("--interactive")]
[Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")]
public bool Interactive { get; set; }
}
public override int Execute(CommandContext context, Settings settings)
{
SettingsDumper.Dump(settings);
return 0;
}
}

View File

@ -1,11 +0,0 @@
using System.ComponentModel;
using Spectre.Console.Cli;
namespace Demo.Commands.Add;
public abstract class AddSettings : CommandSettings
{
[CommandArgument(0, "<PROJECT>")]
[Description("The project file to operate on. If a file is not specified, the command will search the current directory for one.")]
public string Project { get; set; }
}

View File

@ -1,69 +0,0 @@
using System.ComponentModel;
using Demo.Utilities;
using Spectre.Console.Cli;
namespace Demo.Commands.Run;
[Description("Build and run a .NET project output.")]
public sealed class RunCommand : Command<RunCommand.Settings>
{
public sealed class Settings : CommandSettings
{
[CommandOption("-c|--configuration <CONFIGURATION>")]
[Description("The configuration to run for. The default for most projects is '[grey]Debug[/]'.")]
[DefaultValue("Debug")]
public string Configuration { get; set; }
[CommandOption("-f|--framework <FRAMEWORK>")]
[Description("The target framework to run for. The target framework must also be specified in the project file.")]
public string Framework { get; set; }
[CommandOption("-r|--runtime <RUNTIMEIDENTIFIER>")]
[Description("The target runtime to run for.")]
public string RuntimeIdentifier { get; set; }
[CommandOption("-p|--project <PROJECTPATH>")]
[Description("The path to the project file to run (defaults to the current directory if there is only one project).")]
public string ProjectPath { get; set; }
[CommandOption("--launch-profile <LAUNCHPROFILE>")]
[Description("The name of the launch profile (if any) to use when launching the application.")]
public string LaunchProfile { get; set; }
[CommandOption("--no-launch-profile")]
[Description("Do not attempt to use [grey]launchSettings.json[/] to configure the application.")]
public bool NoLaunchProfile { get; set; }
[CommandOption("--no-build")]
[Description("Do not build the project before running. Implies [grey]--no-restore[/].")]
public bool NoBuild { get; set; }
[CommandOption("--interactive")]
[Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")]
public string Interactive { get; set; }
[CommandOption("--no-restore")]
[Description("Do not restore the project before building.")]
public bool NoRestore { get; set; }
[CommandOption("--verbosity <VERBOSITY>")]
[Description("Set the MSBuild verbosity level. Allowed values are q[grey]uiet[/], m[grey]inimal[/], n[grey]ormal[/], d[grey]etailed[/], and diag[grey]nostic[/].")]
[TypeConverter(typeof(VerbosityConverter))]
[DefaultValue(Verbosity.Normal)]
public Verbosity Verbosity { get; set; }
[CommandOption("--no-dependencies")]
[Description("Do not restore project-to-project references and only restore the specified project.")]
public bool NoDependencies { get; set; }
[CommandOption("--force")]
[Description("Force all dependencies to be resolved even if the last restore was successful. This is equivalent to deleting [grey]project.assets.json[/].")]
public bool Force { get; set; }
}
public override int Execute(CommandContext context, Settings settings)
{
SettingsDumper.Dump(settings);
return 0;
}
}

View File

@ -1,40 +0,0 @@
using System;
using System.ComponentModel;
using Demo.Utilities;
using Spectre.Console.Cli;
namespace Demo.Commands.Serve;
[Description("Launches a web server in the current working directory and serves all files in it.")]
public sealed class ServeCommand : Command<ServeCommand.Settings>
{
public sealed class Settings : CommandSettings
{
[CommandOption("-p|--port <PORT>")]
[Description("Port to use. Defaults to [grey]8080[/]. Use [grey]0[/] for a dynamic port.")]
public int Port { get; set; }
[CommandOption("-o|--open-browser [BROWSER]")]
[Description("Open a web browser when the server starts. You can also specify which browser to use. If none is specified, the default one will be used.")]
public FlagValue<string> OpenBrowser { get; set; }
}
public override int Execute(CommandContext context, Settings settings)
{
if (settings.OpenBrowser.IsSet)
{
var browser = settings.OpenBrowser.Value;
if (browser != null)
{
Console.WriteLine($"Open in {browser}");
}
else
{
Console.WriteLine($"Open in default browser.");
}
}
SettingsDumper.Dump(settings);
return 0;
}
}

View File

@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<ExampleName>Demo</ExampleName>
<ExampleDescription>Demonstrates the most common use cases of Spectre.Cli.</ExampleDescription>
<ExampleGroup>Cli</ExampleGroup>
<ExampleVisible>false</ExampleVisible>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Spectre.Console.Cli\Spectre.Console.Cli.csproj" />
</ItemGroup>
</Project>

View File

@ -1,39 +0,0 @@
using Demo.Commands;
using Demo.Commands.Add;
using Demo.Commands.Run;
using Demo.Commands.Serve;
using Spectre.Console.Cli;
namespace Demo;
public static class Program
{
public static int Main(string[] args)
{
var app = new CommandApp();
app.Configure(config =>
{
config.SetApplicationName("fake-dotnet");
config.ValidateExamples();
config.AddExample("run", "--no-build");
// Run
config.AddCommand<RunCommand>("run");
// Add
config.AddBranch<AddSettings>("add", add =>
{
add.SetDescription("Add a package or reference to a .NET project");
add.AddCommand<AddPackageCommand>("package");
add.AddCommand<AddReferenceCommand>("reference");
});
// Serve
config.AddCommand<ServeCommand>("serve")
.WithExample("serve", "-o", "firefox")
.WithExample("serve", "--port", "80", "-o", "firefox");
});
return app.Run(args);
}
}

View File

@ -1,28 +0,0 @@
using Spectre.Console;
using Spectre.Console.Cli;
namespace Demo.Utilities;
public static class SettingsDumper
{
public static void Dump(CommandSettings settings)
{
var table = new Table().RoundedBorder();
table.AddColumn("[grey]Name[/]");
table.AddColumn("[grey]Value[/]");
var properties = settings.GetType().GetProperties();
foreach (var property in properties)
{
var value = property.GetValue(settings)
?.ToString()
?.Replace("[", "[[");
table.AddRow(
property.Name,
value ?? "[grey]null[/]");
}
AnsiConsole.Write(table);
}
}

View File

@ -1,53 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
namespace Demo;
public enum Verbosity
{
Quiet,
Minimal,
Normal,
Detailed,
Diagnostic
}
public sealed class VerbosityConverter : TypeConverter
{
private readonly Dictionary<string, Verbosity> _lookup;
public VerbosityConverter()
{
_lookup = new Dictionary<string, Verbosity>(StringComparer.OrdinalIgnoreCase)
{
{ "q", Verbosity.Quiet },
{ "quiet", Verbosity.Quiet },
{ "m", Verbosity.Minimal },
{ "minimal", Verbosity.Minimal },
{ "n", Verbosity.Normal },
{ "normal", Verbosity.Normal },
{ "d", Verbosity.Detailed },
{ "detailed", Verbosity.Detailed },
{ "diag", Verbosity.Diagnostic },
{ "diagnostic", Verbosity.Diagnostic }
};
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string stringValue)
{
var result = _lookup.TryGetValue(stringValue, out var verbosity);
if (!result)
{
const string format = "The value '{0}' is not a valid verbosity.";
var message = string.Format(CultureInfo.InvariantCulture, format, value);
throw new InvalidOperationException(message);
}
return verbosity;
}
throw new NotSupportedException("Can't convert value to verbosity.");
}
}

View File

@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<ExampleName>Dynamic</ExampleName>
<ExampleDescription>Demonstrates how to define dynamic commands.</ExampleDescription>
<ExampleGroup>Cli</ExampleGroup>
<ExampleVisible>false</ExampleVisible>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,20 +0,0 @@
using System;
using Spectre.Console;
using Spectre.Console.Cli;
namespace Dynamic;
public sealed class MyCommand : Command
{
public override int Execute(CommandContext context)
{
if (!(context.Data is int data))
{
throw new InvalidOperationException("Command has no associated data.");
}
AnsiConsole.WriteLine("Value = {0}", data);
return 0;
}
}

View File

@ -1,23 +0,0 @@
using System.Linq;
using Spectre.Console.Cli;
namespace Dynamic;
public static class Program
{
public static int Main(string[] args)
{
var app = new CommandApp();
app.Configure(config =>
{
foreach (var index in Enumerable.Range(1, 10))
{
config.AddCommand<MyCommand>($"c{index}")
.WithDescription($"Prints the number {index}")
.WithData(index);
}
});
return app.Run(args);
}
}

View File

@ -1,30 +0,0 @@
using System.Linq;
using Spectre.Console;
using Spectre.Console.Cli;
using Spectre.Console.Cli.Help;
using Spectre.Console.Rendering;
namespace Help;
/// <summary>
/// Example showing how to extend the built-in Spectre.Console help provider
/// by rendering a custom banner at the top of the help information
/// </summary>
internal class CustomHelpProvider : HelpProvider
{
public CustomHelpProvider(ICommandAppSettings settings)
: base(settings)
{
}
public override IEnumerable<IRenderable> GetHeader(ICommandModel model, ICommandInfo? command)
{
return new[]
{
new Text("--------------------------------------"), Text.NewLine,
new Text("--- CUSTOM HELP PROVIDER ---"), Text.NewLine,
new Text("--------------------------------------"), Text.NewLine,
Text.NewLine,
};
}
}

View File

@ -1,20 +0,0 @@
using Spectre.Console;
using Spectre.Console.Cli;
namespace Help;
public sealed class DefaultCommand : Command
{
private IAnsiConsole _console;
public DefaultCommand(IAnsiConsole console)
{
_console = console;
}
public override int Execute(CommandContext context)
{
_console.WriteLine("Hello world");
return 0;
}
}

View File

@ -1,18 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<ExampleName>Help</ExampleName>
<ExampleDescription>Demonstrates how to extend the built-in Spectre.Console help provider to render a custom banner at the top of the help information.</ExampleDescription>
<ExampleGroup>Cli</ExampleGroup>
<ExampleVisible>false</ExampleVisible>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,23 +0,0 @@
using Spectre.Console.Cli;
using Spectre.Console.Cli.Help;
namespace Help;
public static class Program
{
public static int Main(string[] args)
{
var app = new CommandApp<DefaultCommand>();
app.Configure(config =>
{
// Register the custom help provider
config.SetHelpProvider(new CustomHelpProvider(config.Settings));
// Render an unstyled help text for maximum accessibility
config.Settings.HelpProviderStyles = null;
});
return app.Run(args);
}
}

View File

@ -1,29 +0,0 @@
using System;
using System.ComponentModel;
using Spectre.Console.Cli;
namespace Injection.Commands;
public sealed class DefaultCommand : Command<DefaultCommand.Settings>
{
private readonly IGreeter _greeter;
public sealed class Settings : CommandSettings
{
[CommandOption("-n|--name <NAME>")]
[Description("The person or thing to greet.")]
[DefaultValue("World")]
public string Name { get; set; }
}
public DefaultCommand(IGreeter greeter)
{
_greeter = greeter ?? throw new ArgumentNullException(nameof(greeter));
}
public override int Execute(CommandContext context, Settings settings)
{
_greeter.Greet(settings.Name);
return 0;
}
}

View File

@ -1,16 +0,0 @@
using Spectre.Console;
namespace Injection;
public interface IGreeter
{
void Greet(string name);
}
public sealed class HelloWorldGreeter : IGreeter
{
public void Greet(string name)
{
AnsiConsole.WriteLine($"Hello {name}!");
}
}

View File

@ -1,40 +0,0 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Spectre.Console.Cli;
namespace Injection.Infrastructure;
public sealed class TypeRegistrar : ITypeRegistrar
{
private readonly IServiceCollection _builder;
public TypeRegistrar(IServiceCollection builder)
{
_builder = builder;
}
public ITypeResolver Build()
{
return new TypeResolver(_builder.BuildServiceProvider());
}
public void Register(Type service, Type implementation)
{
_builder.AddSingleton(service, implementation);
}
public void RegisterInstance(Type service, object implementation)
{
_builder.AddSingleton(service, implementation);
}
public void RegisterLazy(Type service, Func<object> func)
{
if (func is null)
{
throw new ArgumentNullException(nameof(func));
}
_builder.AddSingleton(service, (provider) => func());
}
}

View File

@ -1,32 +0,0 @@
using System;
using Spectre.Console.Cli;
namespace Injection.Infrastructure;
public sealed class TypeResolver : ITypeResolver, IDisposable
{
private readonly IServiceProvider _provider;
public TypeResolver(IServiceProvider provider)
{
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
}
public object Resolve(Type type)
{
if (type == null)
{
return null;
}
return _provider.GetService(type);
}
public void Dispose()
{
if (_provider is IDisposable disposable)
{
disposable.Dispose();
}
}
}

View File

@ -1,21 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<ExampleName>Injection</ExampleName>
<ExampleDescription>Demonstrates how to use dependency injection with Spectre.Cli.</ExampleDescription>
<ExampleGroup>Cli</ExampleGroup>
<ExampleVisible>false</ExampleVisible>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,23 +0,0 @@
using Injection.Commands;
using Injection.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Spectre.Console.Cli;
namespace Injection;
public class Program
{
public static int Main(string[] args)
{
// Create a type registrar and register any dependencies.
// A type registrar is an adapter for a DI framework.
var registrations = new ServiceCollection();
registrations.AddSingleton<IGreeter, HelloWorldGreeter>();
var registrar = new TypeRegistrar(registrations);
// Create a new command app with the registrar
// and run it with the provided arguments.
var app = new CommandApp<DefaultCommand>(registrar);
return app.Run(args);
}
}

View File

@ -1,34 +0,0 @@
using Microsoft.Extensions.Logging;
using Spectre.Console;
using Spectre.Console.Cli;
namespace Logging.Commands;
public class HelloCommand : Command<HelloCommand.Settings>
{
private ILogger<HelloCommand> _logger;
private IAnsiConsole _console;
public HelloCommand(IAnsiConsole console, ILogger<HelloCommand> logger)
{
_console = console;
_logger = logger;
_logger.LogDebug("{0} initialized", nameof(HelloCommand));
}
public class Settings : LogCommandSettings
{
[CommandArgument(0, "[Name]")]
public string Name { get; set; }
}
public override int Execute(CommandContext context, Settings settings)
{
_logger.LogInformation("Starting my command");
AnsiConsole.MarkupLine($"Hello, [blue]{settings.Name}[/]");
_logger.LogInformation("Completed my command");
return 0;
}
}

View File

@ -1,55 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using Serilog.Events;
using Spectre.Console.Cli;
namespace Logging.Commands;
public class LogCommandSettings : CommandSettings
{
[CommandOption("--logFile")]
[Description("Path and file name for logging")]
public string LogFile { get; set; }
[CommandOption("--logLevel")]
[Description("Minimum level for logging")]
[TypeConverter(typeof(VerbosityConverter))]
[DefaultValue(LogEventLevel.Information)]
public LogEventLevel LogLevel { get; set; }
}
public sealed class VerbosityConverter : TypeConverter
{
private readonly Dictionary<string, LogEventLevel> _lookup;
public VerbosityConverter()
{
_lookup = new Dictionary<string, LogEventLevel>(StringComparer.OrdinalIgnoreCase)
{
{"d", LogEventLevel.Debug},
{"v", LogEventLevel.Verbose},
{"i", LogEventLevel.Information},
{"w", LogEventLevel.Warning},
{"e", LogEventLevel.Error},
{"f", LogEventLevel.Fatal}
};
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string stringValue)
{
var result = _lookup.TryGetValue(stringValue, out var verbosity);
if (!result)
{
const string format = "The value '{0}' is not a valid verbosity.";
var message = string.Format(CultureInfo.InvariantCulture, format, value);
throw new InvalidOperationException(message);
}
return verbosity;
}
throw new NotSupportedException("Can't convert value to verbosity.");
}
}

View File

@ -1,19 +0,0 @@
using Logging.Commands;
using Serilog.Core;
using Spectre.Console.Cli;
namespace Logging.Infrastructure;
public class LogInterceptor : ICommandInterceptor
{
public static readonly LoggingLevelSwitch LogLevel = new();
public void Intercept(CommandContext context, CommandSettings settings)
{
if (settings is LogCommandSettings logSettings)
{
LoggingEnricher.Path = logSettings.LogFile ?? "application.log";
LogLevel.MinimumLevel = logSettings.LogLevel;
}
}
}

View File

@ -1,37 +0,0 @@
using Serilog.Core;
using Serilog.Events;
namespace Logging.Infrastructure;
internal class LoggingEnricher : ILogEventEnricher
{
private string _cachedLogFilePath;
private LogEventProperty _cachedLogFilePathProperty;
// this path and level will be set by the LogInterceptor.cs after parsing the settings
public static string Path = string.Empty;
public const string LogFilePathPropertyName = "LogFilePath";
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
// the settings might not have a path or we might not be within a command in which case
// we won't have the setting so a default value for the log file will be required
LogEventProperty logFilePathProperty;
if (_cachedLogFilePathProperty != null && Path.Equals(_cachedLogFilePath))
{
// Path hasn't changed, so let's use the cached property
logFilePathProperty = _cachedLogFilePathProperty;
}
else
{
// We've got a new path for the log. Let's create a new property
// and cache it for future log events to use
_cachedLogFilePath = Path;
_cachedLogFilePathProperty = logFilePathProperty = propertyFactory.CreateProperty(LogFilePathPropertyName, Path);
}
logEvent.AddPropertyIfAbsent(logFilePathProperty);
}
}

View File

@ -1,40 +0,0 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Spectre.Console.Cli;
namespace Logging.Infrastructure;
public sealed class TypeRegistrar : ITypeRegistrar
{
private readonly IServiceCollection _builder;
public TypeRegistrar(IServiceCollection builder)
{
_builder = builder;
}
public ITypeResolver Build()
{
return new TypeResolver(_builder.BuildServiceProvider());
}
public void Register(Type service, Type implementation)
{
_builder.AddSingleton(service, implementation);
}
public void RegisterInstance(Type service, object implementation)
{
_builder.AddSingleton(service, implementation);
}
public void RegisterLazy(Type service, Func<object> func)
{
if (func is null)
{
throw new ArgumentNullException(nameof(func));
}
_builder.AddSingleton(service, _ => func());
}
}

View File

@ -1,24 +0,0 @@
using System;
using Spectre.Console.Cli;
namespace Logging.Infrastructure;
public sealed class TypeResolver : ITypeResolver
{
private readonly IServiceProvider _provider;
public TypeResolver(IServiceProvider provider)
{
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
}
public object Resolve(Type type)
{
if (type == null)
{
return null;
}
return _provider.GetService(type);
}
}

View File

@ -1,26 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<ExampleName>Logging</ExampleName>
<ExampleDescription>Demonstrates how to dynamically configure Serilog for logging using parameters from a command.</ExampleDescription>
<ExampleGroup>Cli</ExampleGroup>
<ExampleVisible>false</ExampleVisible>
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.Map" Version="1.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,54 +0,0 @@
using Logging.Commands;
using Logging.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Serilog;
using Spectre.Console.Cli;
/*
* Dynamically control serilog configuration via command line parameters
*
* This works around the chicken and egg situation with configuring serilog via the command line.
* The logger needs to be configured prior to executing the parser, but the logger needs the parsed values
* to be configured. By using serilog.sinks.map we can defer configuration. We use a LogLevelSwitch to control the
* logging levels dynamically, and then we use a serilog enricher that has its state populated via a
* Spectre.Console CommandInterceptor
*/
namespace Logging;
public class Program
{
static int Main(string[] args)
{
// to retrieve the log file name, we must first parse the command settings
// this will require us to delay setting the file path for the file writer.
// With serilog we can use an enricher and Serilog.Sinks.Map to dynamically
// pull this setting.
var serviceCollection = new ServiceCollection()
.AddLogging(configure =>
configure.AddSerilog(new LoggerConfiguration()
// log level will be dynamically be controlled by our log interceptor upon running
.MinimumLevel.ControlledBy(LogInterceptor.LogLevel)
// the log enricher will add a new property with the log file path from the settings
// that we can use to set the path dynamically
.Enrich.With<LoggingEnricher>()
// serilog.sinks.map will defer the configuration of the sink to be ondemand
// allowing us to look at the properties set by the enricher to set the path appropriately
.WriteTo.Map(LoggingEnricher.LogFilePathPropertyName,
(logFilePath, wt) => wt.File($"{logFilePath}"), 1)
.CreateLogger()
)
);
var registrar = new TypeRegistrar(serviceCollection);
var app = new CommandApp(registrar);
app.Configure(config =>
{
config.SetInterceptor(new LogInterceptor()); // add the interceptor
config.AddCommand<HelloCommand>("hello");
});
return app.Run(args);
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Screens</ExampleTitle>
<ExampleDescription>Demonstrates how to use alternate screens.</ExampleDescription>
<ExampleGroup>Widgets</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,26 +0,0 @@
// Check if we can use alternate screen buffers
using Spectre.Console;
if (!AnsiConsole.Profile.Capabilities.AlternateBuffer)
{
AnsiConsole.MarkupLine(
"[red]Alternate screen buffers are not supported " +
"by your terminal[/] [yellow]:([/]");
return;
}
// Write to the terminal
AnsiConsole.Write(new Rule("[yellow]Normal universe[/]"));
AnsiConsole.Write(new Panel("Hello World!"));
AnsiConsole.MarkupLine("[grey]Press a key to continue[/]");
AnsiConsole.Console.Input.ReadKey(true);
AnsiConsole.AlternateScreen(() =>
{
// Now we're in another terminal screen buffer
AnsiConsole.Write(new Rule("[red]Mirror universe[/]"));
AnsiConsole.Write(new Panel("[red]Welcome to the upside down![/]"));
AnsiConsole.MarkupLine("[grey]Press a key to return[/]");
AnsiConsole.Console.Input.ReadKey(true);
});

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Borders</ExampleTitle>
<ExampleDescription>Demonstrates the different kind of borders.</ExampleDescription>
<ExampleGroup>Widgets</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,86 +0,0 @@
using Spectre.Console;
using Spectre.Console.Rendering;
namespace Borders;
public static class Program
{
public static void Main()
{
// Render panel borders
HorizontalRule("PANEL BORDERS");
PanelBorders();
// Render table borders
HorizontalRule("TABLE BORDERS");
TableBorders();
}
private static void PanelBorders()
{
static IRenderable CreatePanel(string name, BoxBorder border)
{
return
new Panel($"This is a panel with\nthe [yellow]{name}[/] border.")
.Header($" [blue]{name}[/] ", Justify.Center)
.Border(border)
.BorderStyle(Style.Parse("grey"));
}
var items = new[]
{
CreatePanel("Ascii", BoxBorder.Ascii),
CreatePanel("Square", BoxBorder.Square),
CreatePanel("Rounded", BoxBorder.Rounded),
CreatePanel("Heavy", BoxBorder.Heavy),
CreatePanel("Double", BoxBorder.Double),
CreatePanel("None", BoxBorder.None),
};
AnsiConsole.Write(
new Padder(
new Columns(items).PadRight(2),
new Padding(2, 0, 0, 0)));
}
private static void TableBorders()
{
static IRenderable CreateTable(string name, TableBorder border)
{
var table = new Table().Border(border);
table.ShowRowSeparators();
table.AddColumn("[yellow]Header 1[/]", c => c.Footer("[grey]Footer 1[/]"));
table.AddColumn("[yellow]Header 2[/]", col => col.Footer("[grey]Footer 2[/]").RightAligned());
table.AddRow("Cell", "Cell");
table.AddRow("Cell", "Cell");
return new Panel(table)
.Header($" [blue]{name}[/] ", Justify.Center)
.PadBottom(1)
.NoBorder();
}
var items = new[]
{
CreateTable("Ascii", TableBorder.Ascii), CreateTable("Ascii2", TableBorder.Ascii2),
CreateTable("AsciiDoubleHead", TableBorder.AsciiDoubleHead),
CreateTable("Horizontal", TableBorder.Horizontal), CreateTable("Simple", TableBorder.Simple),
CreateTable("SimpleHeavy", TableBorder.SimpleHeavy), CreateTable("Minimal", TableBorder.Minimal),
CreateTable("MinimalHeavyHead", TableBorder.MinimalHeavyHead),
CreateTable("MinimalDoubleHead", TableBorder.MinimalDoubleHead),
CreateTable("Square", TableBorder.Square), CreateTable("Rounded", TableBorder.Rounded),
CreateTable("Heavy", TableBorder.Heavy), CreateTable("HeavyEdge", TableBorder.HeavyEdge),
CreateTable("HeavyHead", TableBorder.HeavyHead), CreateTable("Double", TableBorder.Double),
CreateTable("DoubleEdge", TableBorder.DoubleEdge), CreateTable("Markdown", TableBorder.Markdown),
};
AnsiConsole.Write(new Columns(items).Collapse());
}
private static void HorizontalRule(string title)
{
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule($"[white bold]{title}[/]").RuleStyle("grey").LeftJustified());
AnsiConsole.WriteLine();
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Calendars</ExampleTitle>
<ExampleDescription>Demonstrates how to render calendars.</ExampleDescription>
<ExampleGroup>Widgets</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,18 +0,0 @@
using Spectre.Console;
namespace Calendars;
public static class Program
{
public static void Main(string[] args)
{
AnsiConsole.WriteLine();
AnsiConsole.Write(new Calendar(2020, 10)
.RoundedBorder()
.HighlightStyle(Style.Parse("red"))
.HeaderStyle(Style.Parse("yellow"))
.AddCalendarEvent("An event", 2020, 9, 22)
.AddCalendarEvent("Another event", 2020, 10, 2)
.AddCalendarEvent("A third event", 2020, 10, 13));
}
}

View File

@ -1,22 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Canvas</ExampleTitle>
<ExampleDescription>Demonstrates how to render pixels and images.</ExampleDescription>
<ExampleGroup>Widgets</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
<ProjectReference Include="..\..\..\src\Spectre.Console.ImageSharp\Spectre.Console.ImageSharp.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="cake.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@ -1,43 +0,0 @@
using System.Diagnostics;
using System.Reflection;
using SixLabors.ImageSharp.Processing;
using Spectre.Console;
using Spectre.Console.Rendering;
namespace Canvas;
public static class Program
{
public static void Main()
{
// Draw an image using CanvasImage powered by ImageSharp.
// This requires the "Spectre.Console.ImageSharp" NuGet package.
var image = new CanvasImage("cake.png");
image.BilinearResampler();
image.MaxWidth(16);
Render(image, "Image from file (16 wide)");
// Draw image again, but without max width
image.NoMaxWidth();
image.Mutate(ctx => ctx.Grayscale().Rotate(-45).EntropyCrop());
Render(image, "Image from file (fit, greyscale, rotated)");
// Draw image again, but load from embedded resource rather than file
using (var fileStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Canvas.cake.png"))
{
Debug.Assert(fileStream != null);
var embeddedImage = new CanvasImage(fileStream);
embeddedImage.BilinearResampler();
embeddedImage.MaxWidth(16);
Render(embeddedImage, "Image from embedded resource (16 wide)");
}
}
private static void Render(IRenderable canvas, string title)
{
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule($"[yellow]{title}[/]").LeftJustified().RuleStyle("grey"));
AnsiConsole.WriteLine();
AnsiConsole.Write(canvas);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Charts</ExampleTitle>
<ExampleDescription>Demonstrates how to render charts in a console.</ExampleDescription>
<ExampleGroup>Widgets</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,42 +0,0 @@
using Spectre.Console;
using Spectre.Console.Rendering;
namespace Charts;
public static class Program
{
public static void Main()
{
// Render a bar chart
AnsiConsole.WriteLine();
Render("Fruits per month", new BarChart()
.Width(60)
.Label("[green bold underline]Number of fruits[/]")
.CenterLabel()
.AddItem("Apple", 12, Color.Yellow)
.AddItem("Orange", 54, Color.Green)
.AddItem("Banana", 33, Color.Red));
// Render a breakdown chart
AnsiConsole.WriteLine();
Render("Languages used", new BreakdownChart()
.FullSize()
.Width(60)
.ShowPercentage()
.WithValueColor(Color.Orange1)
.AddItem("SCSS", 37, Color.Red)
.AddItem("HTML", 28.3, Color.Blue)
.AddItem("C#", 22.6, Color.Green)
.AddItem("JavaScript", 6, Color.Yellow)
.AddItem("Ruby", 6, Color.LightGreen)
.AddItem("Shell", 0.1, Color.Aqua));
}
private static void Render(string title, IRenderable chart)
{
AnsiConsole.Write(
new Panel(chart)
.Padding(1, 1)
.Header(title));
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.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>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,105 +0,0 @@
using Spectre.Console;
using Spectre.Console.Examples;
namespace Colors;
public static class Program
{
public static void Main()
{
/////////////////////////////////////////////////////////////////
// No colors
/////////////////////////////////////////////////////////////////
if (AnsiConsole.Profile.Capabilities.ColorSystem == ColorSystem.NoColors)
{
AnsiConsole.WriteLine("No colors are supported.");
return;
}
/////////////////////////////////////////////////////////////////
// 3-BIT
/////////////////////////////////////////////////////////////////
if (AnsiConsole.Profile.Supports(ColorSystem.Legacy))
{
AnsiConsole.ResetColors();
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule("[yellow bold underline]3-bit Colors[/]").RuleStyle("grey").LeftJustified());
AnsiConsole.WriteLine();
for (var i = 0; i < 8; i++)
{
AnsiConsole.Background = Color.FromInt32(i);
AnsiConsole.Foreground = AnsiConsole.Background.GetInvertedColor();
AnsiConsole.Write(string.Format(" {0,-9}", AnsiConsole.Background.ToString()));
AnsiConsole.ResetColors();
if ((i + 1) % 8 == 0)
{
AnsiConsole.WriteLine();
}
}
}
/////////////////////////////////////////////////////////////////
// 4-BIT
/////////////////////////////////////////////////////////////////
if (AnsiConsole.Profile.Supports(ColorSystem.Standard))
{
AnsiConsole.ResetColors();
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule("[yellow bold underline]4-bit Colors[/]").RuleStyle("grey").LeftJustified());
AnsiConsole.WriteLine();
for (var i = 0; i < 16; i++)
{
AnsiConsole.Background = Color.FromInt32(i);
AnsiConsole.Foreground = AnsiConsole.Background.GetInvertedColor();
AnsiConsole.Write(string.Format(" {0,-9}", AnsiConsole.Background.ToString()));
AnsiConsole.ResetColors();
if ((i + 1) % 8 == 0)
{
AnsiConsole.WriteLine();
}
}
}
/////////////////////////////////////////////////////////////////
// 8-BIT
/////////////////////////////////////////////////////////////////
if (AnsiConsole.Profile.Supports(ColorSystem.EightBit))
{
AnsiConsole.ResetColors();
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule("[yellow bold underline]8-bit Colors[/]").RuleStyle("grey").LeftJustified());
AnsiConsole.WriteLine();
for (var i = 0; i < 16; i++)
{
for (var j = 0; j < 16; j++)
{
var number = i * 16 + j;
AnsiConsole.Background = Color.FromInt32(number);
AnsiConsole.Foreground = AnsiConsole.Background.GetInvertedColor();
AnsiConsole.Write(string.Format(" {0,-4}", number));
AnsiConsole.ResetColors();
if ((number + 1) % 16 == 0)
{
AnsiConsole.WriteLine();
}
}
}
}
/////////////////////////////////////////////////////////////////
// 24-BIT
/////////////////////////////////////////////////////////////////
if (AnsiConsole.Profile.Supports(ColorSystem.TrueColor))
{
AnsiConsole.ResetColors();
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule("[yellow bold underline]24-bit Colors[/]").RuleStyle("grey").LeftJustified());
AnsiConsole.WriteLine();
AnsiConsole.Write(new ColorBox(width: 80, height: 15));
}
}
}

View File

@ -1,19 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Columns</ExampleTitle>
<ExampleDescription>Demonstrates how to render data into columns.</ExampleDescription>
<ExampleGroup>Widgets</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,30 +0,0 @@
using System.Collections.Generic;
using Spectre.Console;
namespace Columns;
public static class Program
{
public static void Main()
{
var cards = new List<Panel>();
foreach (var user in User.LoadUsers())
{
cards.Add(
new Panel(GetCardContent(user))
.Header($"{user.Country}")
.RoundedBorder().Expand());
}
// Render all cards in columns
AnsiConsole.Write(new Spectre.Console.Columns(cards));
}
private static string GetCardContent(User user)
{
var name = $"{user.FirstName} {user.LastName}";
var city = $"{user.City}";
return $"[b]{name}[/]\n[yellow]{city}[/]";
}
}

View File

@ -1,88 +0,0 @@
using System.Collections.Generic;
namespace Columns;
public sealed class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
public string Country { get; set; }
public static List<User> LoadUsers()
{
return new List<User>
{
new User
{
FirstName = "Andrea",
LastName = "Johansen",
City = "Hornbæk",
Country = "Denmark",
},
new User
{
FirstName = "Phil",
LastName = "Scott",
City = "Dayton",
Country = "United States",
},
new User
{
FirstName = "Patrik",
LastName = "Svensson",
City = "Stockholm",
Country = "Sweden",
},
new User
{
FirstName = "Freya",
LastName = "Thompson",
City = "Rotorua",
Country = "New Zealand",
},
new User
{
FirstName = "طاها",
LastName = "رضایی",
City = "اهواز",
Country = "Iran",
},
new User
{
FirstName = "Yara",
LastName = "Simon",
City = "Develier",
Country = "Switzerland",
},
new User
{
FirstName = "Giray",
LastName = "Erbay",
City = "Karabük",
Country = "Turkey",
},
new User
{
FirstName = "Miodrag",
LastName = "Schaffer",
City = "Möckern",
Country = "Germany",
},
new User
{
FirstName = "Carmela",
LastName = "Lo Castro",
City = "Firenze",
Country = "Italy",
},
new User
{
FirstName = "Roberto",
LastName = "Sims",
City = "Mallow",
Country = "Ireland",
},
};
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Cursor</ExampleTitle>
<ExampleDescription>Demonstrates how to move the cursor.</ExampleDescription>
<ExampleGroup>Misc</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,19 +0,0 @@
using Spectre.Console;
namespace Cursor;
public static class Program
{
public static void Main(string[] args)
{
AnsiConsole.Write("Hello");
// Move the cursor 3 cells to the right
AnsiConsole.Cursor.Move(CursorDirection.Right, 3);
AnsiConsole.Write("World");
// Move the cursor 5 cells to the left.
AnsiConsole.Cursor.Move(CursorDirection.Left, 5);
AnsiConsole.WriteLine("Universe");
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Decorations</ExampleTitle>
<ExampleDescription>Demonstrates how to [italic]use[/] [bold]decorations[/] [dim]in[/] the console.</ExampleDescription>
<ExampleGroup>Misc</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,29 +0,0 @@
using Spectre.Console;
namespace Colors;
public static class Program
{
public static void Main()
{
AnsiConsole.ResetDecoration();
AnsiConsole.WriteLine();
if (AnsiConsole.Profile.Capabilities.Ansi)
{
AnsiConsole.Write(new Rule("[bold green]ANSI Decorations[/]"));
}
else
{
AnsiConsole.Write(new Rule("[bold red]Legacy Decorations (unsupported)[/]"));
}
var decorations = System.Enum.GetValues(typeof(Decoration));
foreach (var decoration in decorations)
{
var name = System.Enum.GetName(typeof(Decoration),decoration);
AnsiConsole.Write(name + ": ");
AnsiConsole.Write(new Markup(name+"\n", new Style(decoration: (Decoration)decoration)));
}
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Emojis</ExampleTitle>
<ExampleDescription>Demonstrates how to render emojis.</ExampleDescription>
<ExampleGroup>Misc</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,23 +0,0 @@
using Spectre.Console;
namespace Emojis;
public static class Program
{
public static void Main(string[] args)
{
// Show a known emoji
RenderEmoji();
// Show a remapped emoji
Emoji.Remap("globe_showing_europe_africa", Emoji.Known.GrinningFaceWithSmilingEyes);
RenderEmoji();
}
private static void RenderEmoji()
{
AnsiConsole.Write(
new Panel("[yellow]Hello :globe_showing_europe_africa:![/]")
.RoundedBorder());
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Exceptions</ExampleTitle>
<ExampleDescription>Demonstrates how to render formatted exceptions.</ExampleDescription>
<ExampleGroup>Misc</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,101 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Authentication;
using System.Threading.Tasks;
using Spectre.Console;
namespace Exceptions;
public static class Program
{
public static async Task Main(string[] args)
{
try
{
var foo = new List<string>();
DoMagic(42, null, ref foo);
}
catch (Exception ex)
{
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule("Default").LeftJustified());
AnsiConsole.WriteLine();
AnsiConsole.WriteException(ex);
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule("Compact").LeftJustified());
AnsiConsole.WriteLine();
AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks);
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule("Compact + Custom colors").LeftJustified());
AnsiConsole.WriteLine();
AnsiConsole.WriteException(ex, new ExceptionSettings
{
Format = ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks,
Style = new ExceptionStyle
{
Exception = new Style().Foreground(Color.Grey),
Message = new Style().Foreground(Color.White),
NonEmphasized = new Style().Foreground(Color.Cornsilk1),
Parenthesis = new Style().Foreground(Color.Cornsilk1),
Method = new Style().Foreground(Color.Red),
ParameterName = new Style().Foreground(Color.Cornsilk1),
ParameterType = new Style().Foreground(Color.Red),
Path = new Style().Foreground(Color.Red),
LineNumber = new Style().Foreground(Color.Cornsilk1),
}
});
}
try
{
await DoMagicAsync<int>(42, null);
}
catch (Exception ex)
{
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule("Async").LeftJustified());
AnsiConsole.WriteLine();
AnsiConsole.WriteException(ex, ExceptionFormats.ShortenPaths);
}
}
private static void DoMagic(int foo, string[,] bar, ref List<string> result)
{
try
{
CheckCredentials(foo, bar);
result = new List<string>();
}
catch (Exception ex)
{
throw new InvalidOperationException("Whaaat?", ex);
}
}
private static bool CheckCredentials(int? qux, string[,] corgi)
{
throw new InvalidCredentialException("The credentials are invalid.");
}
private static async Task DoMagicAsync<T>(T foo, string[,] bar)
{
try
{
await CheckCredentialsAsync(new[] { foo }.ToList(), new []{ foo }, bar);
}
catch (Exception ex)
{
throw new InvalidOperationException("Whaaat?", ex);
}
}
private static async Task<bool> CheckCredentialsAsync<T>(List<T> qux, T[] otherArray, string[,] corgi)
{
await Task.Delay(0);
throw new InvalidCredentialException("The credentials are invalid.");
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Figlet</ExampleTitle>
<ExampleDescription>Demonstrates how to render FIGlet text.</ExampleDescription>
<ExampleGroup>Widgets</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,13 +0,0 @@
using Spectre.Console;
namespace Figlet;
public static class Program
{
public static void Main(string[] args)
{
AnsiConsole.Write(new FigletText("Left aligned").LeftJustified().Color(Color.Red));
AnsiConsole.Write(new FigletText("Centered").Centered().Color(Color.Green));
AnsiConsole.Write(new FigletText("Right aligned").RightJustified().Color(Color.Blue));
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Grids</ExampleTitle>
<ExampleDescription>Demonstrates how to render grids in a console.</ExampleDescription>
<ExampleGroup>Widgets</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,23 +0,0 @@
using Spectre.Console;
namespace Grids;
public static class Program
{
public static void Main()
{
AnsiConsole.WriteLine();
AnsiConsole.MarkupLine("Usage: [grey]dotnet [blue]run[/] [[options]] [[[[--]] <additional arguments>...]]]][/]");
AnsiConsole.WriteLine();
var grid = new Grid();
grid.AddColumn(new GridColumn().NoWrap());
grid.AddColumn(new GridColumn().PadLeft(2));
grid.AddRow("Options:");
grid.AddRow(" [blue]-h[/], [blue]--help[/]", "Show command line help.");
grid.AddRow(" [blue]-c[/], [blue]--configuration[/] <CONFIGURATION>", "The configuration to run for.");
grid.AddRow(" [blue]-v[/], [blue]--verbosity[/] <LEVEL>", "Set the [grey]MSBuild[/] verbosity level.");
AnsiConsole.Write(grid);
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Info</ExampleTitle>
<ExampleDescription>Displays the capabilities of the current console.</ExampleDescription>
<ExampleGroup>Misc</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,33 +0,0 @@
using Spectre.Console;
namespace Info;
public static class Program
{
public static void Main()
{
var grid = new Grid()
.AddColumn(new GridColumn().NoWrap().PadRight(4))
.AddColumn()
.AddRow("[b]Enrichers[/]", string.Join(", ", AnsiConsole.Profile.Enrichers))
.AddRow("[b]Color system[/]", $"{AnsiConsole.Profile.Capabilities.ColorSystem}")
.AddRow("[b]Unicode?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Unicode)}")
.AddRow("[b]Supports ansi?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Ansi)}")
.AddRow("[b]Supports links?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Links)}")
.AddRow("[b]Legacy console?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Legacy)}")
.AddRow("[b]Interactive?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Interactive)}")
.AddRow("[b]Terminal?[/]", $"{YesNo(AnsiConsole.Profile.Out.IsTerminal)}")
.AddRow("[b]Buffer width[/]", $"{AnsiConsole.Console.Profile.Width}")
.AddRow("[b]Buffer height[/]", $"{AnsiConsole.Console.Profile.Height}")
.AddRow("[b]Encoding[/]", $"{AnsiConsole.Console.Profile.Encoding.EncodingName}");
AnsiConsole.Write(
new Panel(grid)
.Header("Information"));
}
private static string YesNo(bool value)
{
return value ? "Yes" : "No";
}
}

View File

@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Json</ExampleTitle>
<ExampleDescription>Demonstrates how to print syntax highlighted JSON.</ExampleDescription>
<ExampleGroup>Widgets</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Spectre.Console.Json\Spectre.Console.Json.csproj" />
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,36 +0,0 @@
using Spectre.Console;
using Spectre.Console.Json;
namespace Json;
public static class Program
{
public static void Main()
{
var json = new JsonText(
"""
{
"hello": 32,
"world": {
"foo": 21,
"bar": 255,
"baz": [
0.32, 0.33e-32,
0.42e32, 0.55e+32,
{
"hello": "world",
"lol": null
}
]
}
}
""");
AnsiConsole.Write(
new Panel(json)
.Header("Some JSON in a panel")
.Collapse()
.RoundedBorder()
.BorderColor(Color.Yellow));
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Layout</ExampleTitle>
<ExampleDescription>Demonstrates how to use layouts.</ExampleDescription>
<ExampleGroup>Widgets</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,60 +0,0 @@
using System;
using Spectre.Console;
namespace Layouts;
public static class Program
{
public static void Main()
{
var layout = CreateLayout();
AnsiConsole.Write(layout);
Console.ReadKey(true);
}
private static Layout CreateLayout()
{
var layout = new Layout();
layout.SplitRows(
new Layout("Top")
.SplitColumns(
new Layout("Left")
.SplitRows(
new Layout("LeftTop"),
new Layout("LeftBottom")),
new Layout("Right").Ratio(2),
new Layout("RightRight").Size(3)),
new Layout("Bottom"));
layout["LeftBottom"].Update(
new Panel("[blink]PRESS ANY KEY TO QUIT[/]")
.Expand()
.BorderColor(Color.Yellow)
.Padding(0, 0));
layout["Right"].Update(
new Panel(
new Table()
.AddColumns("[blue]Qux[/]", "[green]Corgi[/]")
.AddRow("9", "8")
.AddRow("7", "6")
.Expand())
.Header("A [yellow]Table[/] in a [blue]Panel[/] (Ratio=2)")
.Expand());
layout["RightRight"].Update(
new Panel("Explicit-size-is-[yellow]3[/]")
.BorderColor(Color.Yellow)
.Padding(0, 0));
layout["Bottom"].Update(
new Panel(
new FigletText("Hello World"))
.Header("Some [green]Figlet[/] text")
.Expand());
return layout;
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Links</ExampleTitle>
<ExampleDescription>Demonstrates how to render links in a console.</ExampleDescription>
<ExampleGroup>Misc</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,20 +0,0 @@
using Spectre.Console;
namespace Links;
public static class Program
{
public static void Main()
{
if (AnsiConsole.Profile.Capabilities.Links)
{
AnsiConsole.MarkupLine("[link=https://patriksvensson.se]Click to visit my blog[/]!");
}
else
{
AnsiConsole.MarkupLine("[red]It looks like your terminal doesn't support links[/]");
AnsiConsole.WriteLine();
AnsiConsole.MarkupLine("[yellow](╯°□°)╯[/]︵ [blue]┻━┻[/]");
}
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Live</ExampleTitle>
<ExampleDescription>Demonstrates how to do live updates.</ExampleDescription>
<ExampleGroup>Live</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,81 +0,0 @@
using System;
using System.Threading;
using Spectre.Console;
namespace Live;
public static class Program
{
public static void Main()
{
var table = new Table().Centered();
// Animate
AnsiConsole.Live(table)
.AutoClear(false)
.Overflow(VerticalOverflow.Ellipsis)
.Cropping(VerticalOverflowCropping.Top)
.Start(ctx =>
{
void Update(int delay, Action action)
{
action();
ctx.Refresh();
Thread.Sleep(delay);
}
// Columns
Update(230, () => table.AddColumn("Release date"));
Update(230, () => table.AddColumn("Title"));
Update(230, () => table.AddColumn("Budget"));
Update(230, () => table.AddColumn("Opening Weekend"));
Update(230, () => table.AddColumn("Box office"));
// Rows
Update(70, () => table.AddRow("May 25, 1977", "[yellow]Star Wars[/] [grey]Ep.[/] [u]IV[/]", "$11,000,000", "$1,554,475", "$775,398,007"));
Update(70, () => table.AddRow("May 21, 1980", "[yellow]Star Wars[/] [grey]Ep.[/] [u]V[/]", "$18,000,000", "$4,910,483", "$547,969,004"));
Update(70, () => table.AddRow("May 25, 1983", "[yellow]Star Wars[/] [grey]Ep.[/] [u]VI[/]", "$32,500,000", "$23,019,618", "$475,106,177"));
Update(70, () => table.AddRow("May 19, 1999", "[yellow]Star Wars[/] [grey]Ep.[/] [u]I[/]", "$115,000,000", "$64,810,870", "$1,027,044,677"));
Update(70, () => table.AddRow("May 16, 2002", "[yellow]Star Wars[/] [grey]Ep.[/] [u]II[/]", "$115,000,000", "$80,027,814", "$649,436,358"));
Update(70, () => table.AddRow("May 19, 2005", "[yellow]Star Wars[/] [grey]Ep.[/] [u]III[/]", "$113,000,000", "$108,435,841", "$850,035,635"));
Update(70, () => table.AddRow("Dec 18, 2015", "[yellow]Star Wars[/] [grey]Ep.[/] [u]VII[/]", "$245,000,000", "$247,966,675", "$2,068,223,624"));
Update(70, () => table.AddRow("Dec 15, 2017", "[yellow]Star Wars[/] [grey]Ep.[/] [u]VIII[/]", "$317,000,000", "$220,009,584", "$1,333,539,889"));
Update(70, () => table.AddRow("Dec 20, 2019", "[yellow]Star Wars[/] [grey]Ep.[/] [u]IX[/]", "$245,000,000", "$177,383,864", "$1,074,114,248"));
// Column footer
Update(230, () => table.Columns[2].Footer("$1,633,000,000"));
Update(230, () => table.Columns[3].Footer("$928,119,224"));
Update(400, () => table.Columns[4].Footer("$10,318,030,576"));
// Column alignment
Update(230, () => table.Columns[2].RightAligned());
Update(230, () => table.Columns[3].RightAligned());
Update(400, () => table.Columns[4].RightAligned());
// Column titles
Update(70, () => table.Columns[0].Header("[bold]Release date[/]"));
Update(70, () => table.Columns[1].Header("[bold]Title[/]"));
Update(70, () => table.Columns[2].Header("[red bold]Budget[/]"));
Update(70, () => table.Columns[3].Header("[green bold]Opening Weekend[/]"));
Update(400, () => table.Columns[4].Header("[blue bold]Box office[/]"));
// Footers
Update(70, () => table.Columns[2].Footer("[red bold]$1,633,000,000[/]"));
Update(70, () => table.Columns[3].Footer("[green bold]$928,119,224[/]"));
Update(400, () => table.Columns[4].Footer("[blue bold]$10,318,030,576[/]"));
// Title
Update(500, () => table.Title("Star Wars Movies"));
Update(400, () => table.Title("[[ [yellow]Star Wars Movies[/] ]]"));
// Borders
Update(230, () => table.BorderColor(Color.Yellow));
Update(230, () => table.MinimalBorder());
Update(230, () => table.SimpleBorder());
Update(230, () => table.SimpleHeavyBorder());
// Caption
Update(400, () => table.Caption("[[ [blue]THE END[/] ]]"));
});
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>LiveTable</ExampleTitle>
<ExampleDescription>Demonstrates how to do live updates in a table.</ExampleDescription>
<ExampleGroup>Live</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,86 +0,0 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Spectre.Console;
namespace LiveTable;
public static class Program
{
private const int NumberOfRows = 10;
private static readonly Random _random = new();
private static readonly string[] _exchanges = new string[]
{
"SGD", "SEK", "PLN",
"MYR", "EUR", "USD",
"AUD", "JPY", "CNH",
"HKD", "CAD", "INR",
"DKK", "GBP", "RUB",
"NZD", "MXN", "IDR",
"TWD", "THB", "VND",
};
public static async Task Main(string[] args)
{
var table = new Table().Expand().BorderColor(Color.Grey);
table.AddColumn("[yellow]Source currency[/]");
table.AddColumn("[yellow]Destination currency[/]");
table.AddColumn("[yellow]Exchange rate[/]");
AnsiConsole.MarkupLine("Press [yellow]CTRL+C[/] to exit");
await AnsiConsole.Live(table)
.AutoClear(false)
.Overflow(VerticalOverflow.Ellipsis)
.Cropping(VerticalOverflowCropping.Bottom)
.StartAsync(async ctx =>
{
// Add some initial rows
foreach (var _ in Enumerable.Range(0, NumberOfRows))
{
AddExchangeRateRow(table);
}
// Continously update the table
while (true)
{
// More rows than we want?
if (table.Rows.Count > NumberOfRows)
{
// Remove the first one
table.Rows.RemoveAt(0);
}
// Add a new row
AddExchangeRateRow(table);
// Refresh and wait for a while
ctx.Refresh();
await Task.Delay(400);
}
});
}
private static void AddExchangeRateRow(Table table)
{
var (source, destination, rate) = GetExchangeRate();
table.AddRow(
source, destination,
_random.NextDouble() > 0.35D ? $"[green]{rate}[/]" : $"[red]{rate}[/]");
}
private static (string Source, string Destination, double Rate) GetExchangeRate()
{
var source = _exchanges[_random.Next(0, _exchanges.Length)];
var dest = _exchanges[_random.Next(0, _exchanges.Length)];
var rate = 200 / ((_random.NextDouble() * 320) + 1);
while (source == dest)
{
dest = _exchanges[_random.Next(0, _exchanges.Length)];
}
return (source, dest, rate);
}
}

View File

@ -1,2 +0,0 @@
global using Spectre.Console;
global using static Spectre.Console.AnsiConsole;

View File

@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.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>

View File

@ -1,12 +0,0 @@
// 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[/]"));

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Panels</ExampleTitle>
<ExampleDescription>Demonstrates how to render items in panels.</ExampleDescription>
<ExampleGroup>Widgets</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,41 +0,0 @@
using Spectre.Console;
namespace Panels;
public static class Program
{
public static void Main()
{
var content = new Markup(
"[underline]I[/] heard [underline on blue]you[/] like panels\n\n\n\n" +
"So I put a panel in a panel").Centered();
AnsiConsole.Write(
new Panel(
new Panel(content)
.Border(BoxBorder.Rounded)));
// Left adjusted panel with text
AnsiConsole.Write(
new Panel(new Text("Left adjusted\nLeft").LeftJustified())
.Expand()
.SquareBorder()
.Header("[red]Left[/]"));
// Centered ASCII panel with text
AnsiConsole.Write(
new Panel(new Text("Centered\nCenter").Centered())
.Expand()
.AsciiBorder()
.Header("[green]Center[/]")
.HeaderAlignment(Justify.Center));
// Right adjusted, rounded panel with text
AnsiConsole.Write(
new Panel(new Text("Right adjusted\nRight").RightJustified())
.Expand()
.RoundedBorder()
.Header("[blue]Right[/]")
.HeaderAlignment(Justify.Right));
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ExampleTitle>Paths</ExampleTitle>
<ExampleDescription>Demonstrates how to render paths.</ExampleDescription>
<ExampleGroup>Widgets</ExampleGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,67 +0,0 @@
using System;
using System.Threading;
using Spectre.Console;
namespace Paths;
public static class Program
{
public static void Main()
{
var windowsPath = @"C:\This is\A\Super Long\Windows\Path\That\Goes\On And On\And\Never\Seems\To\Stop\But\At\Some\Point\It\Must\I\Guess.txt";
var unixPath = @"//This is/A/Super Long/Unix/Path/That/Goes/On And On/And/Never/Seems/To/Stop/But/At/Some/Point/It/Must/I/Guess.txt";
AnsiConsole.WriteLine();
WritePlain(windowsPath, unixPath);
AnsiConsole.WriteLine();
WriteColorized(windowsPath, unixPath);
AnsiConsole.WriteLine();
WriteAligned(windowsPath);
}
private static void WritePlain(string windowsPath, string unixPath)
{
var table = new Table().BorderColor(Color.Grey).Title("Plain").RoundedBorder();
table.AddColumns("[grey]OS[/]", "[grey]Path[/]");
table.AddRow(new Text("Windows"), new TextPath(windowsPath));
table.AddRow(new Text("Unix"), new TextPath(unixPath));
AnsiConsole.Write(table);
}
private static void WriteColorized(string windowsPath, string unixPath)
{
var table = new Table().BorderColor(Color.Grey).Title("Colorized").RoundedBorder();
table.AddColumns("[grey]OS[/]", "[grey]Path[/]");
table.AddRow(new Text("Windows"),
new TextPath(windowsPath)
.RootColor(Color.Blue)
.SeparatorColor(Color.Yellow)
.StemColor(Color.Red)
.LeafColor(Color.Green));
table.AddRow(new Text("Unix"),
new TextPath(unixPath)
.RootColor(Color.Blue)
.SeparatorColor(Color.Yellow)
.StemColor(Color.Red)
.LeafColor(Color.Green));
AnsiConsole.Write(table);
}
private static void WriteAligned(string path)
{
var table = new Table().BorderColor(Color.Grey).Title("Aligned").RoundedBorder();
table.AddColumns("[grey]Alignment[/]", "[grey]Path[/]");
table.AddRow(new Text("Left"), new TextPath(path).LeftJustified());
table.AddRow(new Text("Center"), new TextPath(path).Centered());
table.AddRow(new Text("Right"), new TextPath(path).RightJustified());
AnsiConsole.Write(table);
}
}

View File

@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
namespace Progress;
public static class DescriptionGenerator
{
private static readonly string[] _verbs = new[] { "Downloading", "Rerouting", "Retriculating", "Collapsing", "Folding", "Solving", "Colliding", "Measuring" };
private static readonly string[] _nouns = new[] { "internet", "splines", "space", "capacitators", "quarks", "algorithms", "data structures", "spacetime" };
private static readonly Random _random;
private static readonly HashSet<string> _used;
static DescriptionGenerator()
{
_random = new Random(DateTime.Now.Millisecond);
_used = new HashSet<string>();
}
public static bool TryGenerate(out string name)
{
var iterations = 0;
while (iterations < 25)
{
name = Generate();
if (!_used.Contains(name))
{
_used.Add(name);
return true;
}
iterations++;
}
name = Generate();
return false;
}
public static string Generate()
{
return _verbs[_random.Next(0, _verbs.Length)]
+ " " + _nouns[_random.Next(0, _nouns.Length)];
}
}

Some files were not shown because too many files have changed in this diff Show More