Compare commits

...

161 Commits

Author SHA1 Message Date
renovate[bot]
5a4e379a1d chore: Update dotnet monorepo 2025-10-14 23:41:20 +00:00
Patrik Svensson
749f0fded8 Update Verify to 31.0.1 2025-10-11 20:54:48 +02:00
Cédric Luthi
f5f61ca610 Add top-level CancellationToken support to Spectre.Console.Cli
Also raise CA2016 (forward the CancellationToken parameter to methods that take one) to warning

Fixes #701
2025-10-11 20:51:01 +02:00
Patrik Svensson
d90e94dbb3 Fix spacing in blog post 2025-10-10 21:27:37 +02:00
Patrik Svensson
169abca986 Add blog post for 0.52.0 2025-10-10 21:12:54 +02:00
Patrik Svensson
3c2156268c Remove global.json for docs project 2025-10-10 20:36:13 +02:00
Patrik Svensson
6fb81103f0 Update more dependencies 2025-10-10 20:32:48 +02:00
Patrik Svensson
880e83b27c Update Cake to 5.1.0 2025-10-10 20:20:50 +02:00
Patrik Svensson
0b270e1ccd Update dependencies 2025-10-10 20:13:21 +02:00
Mattias Karlsson
2d9e8069fd Fix OPENCLI_VISIBILITY_INTERNAL to DefineConstants concat 2025-10-06 23:19:10 +02:00
Patrik Svensson
b551bbd244 Add OpenCLI integration to Spectre.Console.Cli 2025-10-02 02:05:46 +02:00
Patrik Svensson
3a70fbec75 Update the blog post with info about 0.51.1 2025-09-07 01:04:05 +02:00
Patrik Svensson
c67b3df3ba Fix package references 2025-09-07 00:44:00 +02:00
Patrik Svensson
8e474f514c Add blog post for 0.51 release 2025-09-07 00:29:44 +02:00
Patrik Svensson
097f740bbd Revert back to using a single solution
Also migrates solution format from sln to slnx.
2025-09-06 23:59:53 +02:00
Patrik Svensson
ba7299adcf Build and package Spectre.Console.Cli as part of build script 2025-09-06 23:33:54 +02:00
mattfennerom
d84f9ae713 fix bug setting Header (#1890) 2025-09-05 15:42:18 +02:00
Mitch Denny
3a6d3e4520 Fix space triggering selection when items in selection list have a space. (#1881)
* Changes Search in SelectionPrompt to accept Space Key as text

---------

Co-authored-by: Philipp <30900810+DerReparator@users.noreply.github.com>
2025-08-19 20:09:12 +02:00
Tobias Tengler
a8b2f1f1e0 Support J and K for navigating list prompts (#1877) 2025-08-13 18:23:26 +02:00
FroggieFrog
0889c2f97c Update spinners (#1873)
Update spinners from https://github.com/sindresorhus/cli-spinners
2025-08-03 13:19:22 +02:00
Patrik Svensson
f4782d9916 Update dependencies 2025-08-03 13:13:12 +02:00
Frank Ray
8b59ddfd41 Separate Spectre.Console.Cli from Spectre.Console (#1850) 2025-07-23 23:11:07 +02:00
Mustafa Al-Janabi
6ad814cab0 Corrects comment for optional text prompt (#1857) 2025-07-16 00:00:29 +02:00
Daniel
f32f80dc57 Fix resizing of Live views with reduced size. (#1840) 2025-06-21 12:30:18 +02:00
Pannoniae
7f3ebe02c4 Reduce memory usage for rune width cache. (#1756) 2025-06-20 12:49:45 +02:00
renovate[bot]
d77bfb6391 chore: Update dependency AngleSharp to 1.3.0 (#1809)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-18 18:05:15 +02:00
renovate[bot]
7819f0693d chore: Update dependency SixLabors.ImageSharp to 3.1.10 (#1812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-18 18:01:14 +02:00
renovate[bot]
465be9391b chore: Update dependency Microsoft.Playwright to 1.52.0 (#1816)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-18 18:00:41 +02:00
renovate[bot]
7e5ddb1efe chore: Update dependency Verify.Xunit to v30 (#1818)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-18 17:57:36 +02:00
renovate[bot]
aabe8eeaf8 chore: Update dependency Scriban to 6.2.1 (#1808)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-18 17:56:33 +02:00
renovate[bot]
108b23fca8 chore: Update dependency xunit.runner.visualstudio to 3.1.1 (#1820)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-18 17:55:15 +02:00
renovate[bot]
7051bc9e2d chore: Update dependency Microsoft.NET.Test.Sdk to 17.14.1 (#1822)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-18 17:52:31 +02:00
Weihan Li
65bab890f2 Update System.Memory dependency 2025-06-05 10:34:24 +02:00
Elementttto
bd0e2d3e22 Fixed link not dispalyed in markup in Style.cs and added unit test cases (#1750) 2025-06-02 10:19:53 +02:00
Elemento
9efc426eb9 Added documentation for align widget 2025-06-01 13:54:15 +02:00
Patrik Svensson
2570202990 Fix build errors 2025-05-25 16:42:43 +02:00
Patrik Svensson
e4b5b56d93 Update help output for required options 2025-05-25 16:42:43 +02:00
Patrik Svensson
67c3909bbb Add support for required options 2025-05-25 16:42:43 +02:00
Bartosz Ogiński
d836ad1805 Add ShowRowSeparators in Table Widget docs (#1807) 2025-04-14 18:34:09 +02:00
Marek
57dd8ee410 #1718 TestConsole can now be configured and accessed in CommandAppTester (#1803)
* TestConsole can now be configured and accessed in CommandAppTester
* Add test with mocked user inputs for interactive command
* Add documentation for using the CommandAppTester

Co-authored-by: Patrik Svensson <patriksvensson@users.noreply.github.com>
Co-authored-by: Marek Magath <Marek.Magath@solarwinds.com>
2025-04-14 10:38:03 +02:00
martincostello
6105ee2a86 Fix IndexOutOfRangeException
Fix `IndexOutOfRangeException` if an exception does not have an associated stack trace.

Resolves #1798.
2025-04-09 12:36:53 +02:00
Patrik Svensson
b5c839030c Blog post: Fix broken PR links 2025-04-08 20:45:50 +02:00
Patrik Svensson
b08ca1c4d7 Add blog post 2025-04-08 18:29:25 +02:00
Patrik Svensson
68fcfe0de4 Update dependencies and .NET SDK 2025-04-08 17:30:03 +02:00
Frank Ray
b0f82d787d Documentation improvements for 1.0 release (#1620)
* Rewrote the Dependency Injection section for better clarity and readability.
* Syntax fix: Should reference interfaces, not implementation
* Renamed TypeRegistrar to MyTypeRegistrar, making it more obvious it is a custom class the user must provide.
2025-04-08 17:01:17 +02:00
Frank Ray
1dabf25e1c Add testing documentation (#1631) 2025-04-08 16:58:25 +02:00
Frank Ray
958820dd66 Tighten up when to show/hide the application "-v|--version" option. 2025-04-08 16:53:43 +02:00
Frank Ray
c4a97f3c89 Improved unit test coverage using Spectre.Console.Tests.Data.VersionCommand 2025-04-08 16:53:43 +02:00
Frank Ray
4ac88b5d3f Help writer unit tests; including coverage of when the -v|--version should (and shouldn't) appear in the help output 2025-04-08 16:53:43 +02:00
Frank Ray
c937c8800a Updated test names for better self-documentation 2025-04-08 16:43:49 +02:00
Frank Ray
349eac1e22 Bug fix: Tests with remaining args should not be expected to pass strict parsing 2025-04-08 16:43:49 +02:00
Frank Ray
2f8a38f169 Add strict parsing to all version tests, an obvious omission in main 2025-04-08 16:43:49 +02:00
Frank Ray
e9f9f56189 Check if the command has a version option on its setting class 2025-04-08 16:43:49 +02:00
Frank Ray
cefb51df7b Unit tests to ensure VersionCommand executes when -v|--version is specified, rather than showing the ApplicationVersion number 2025-04-08 16:43:49 +02:00
Frank Ray
75b3b83210 Removed unnecessary using directive 2025-04-08 16:43:49 +02:00
Frank Ray
dfdd129dd0 Display the application version (if set) when a version flag is the first argument, even if a default command has been set. 2025-04-08 16:43:49 +02:00
Frank Ray
17c7a4f7d6 Cover -v and --version options in unit tests 2025-04-08 16:43:49 +02:00
Frank Ray
520efe07e2 Significant improvement to the command line parsing 2025-04-08 16:38:37 +02:00
Frank Ray
c81bc5fe1d Fix tests with incorrect validation that were in the main branch
Tests had incorrect expectations for the parsing of branch + default command arguments
2025-04-08 16:38:37 +02:00
Frank Ray
edf7f23957 Add strict parsing to almost all branches tests, an obvious omission 2025-04-08 16:38:37 +02:00
Frank Ray
80a8b0e406 Cosmetic: Remove ugly looking variable naming 2025-04-08 16:38:37 +02:00
Frank Ray
dca67da8cd New unit tests to ensure unknown flags are added to remaining args 2025-04-08 16:38:37 +02:00
Patrik Svensson
78272e62e6 Merge pull request #1779 from Moustafaa91/bug/1776 2025-03-24 00:05:14 +01:00
Mostafa Attia
540fb0195f Upgrade SixLabors.ImageSharp to 3.1.7 2025-03-23 13:44:18 +00:00
Melvin Dommer
93668e92b6 Changed IConfigurator to return IConfigurator instead of void for (#1762) 2025-02-24 20:57:23 +00:00
Tonttu
11a320c7c9 Conditionally trim trailing periods of argument and option descriptions (#1740) 2025-02-11 21:13:30 +00:00
Patrik Svensson
c1eb94c1db Merge pull request #1755 from 0xced/fix-generic-exception-formatting 2025-02-05 18:39:38 +01:00
Cédric Luthi
9d8d3c1d6d Fix generic exception formatting with shortened types
Fixes #1754
2025-02-05 18:20:21 +01:00
Cédric Luthi
7e1142df58 Add tests for generic exception formatting 2025-02-05 18:20:21 +01:00
Eduardo Tolino
a6b96e9297 Include resource files for additional cultures in HelpProvider. (#1717)
* Creation of Resource files for HelpProvider in the following cultures: it, ja, ko, pt, ru, and zh-Hans.
* Add unit test files and update InlineData for new cultures.
* Include --version option in CommandAppTests.Help.cs and update related output files
2025-01-31 21:23:40 +00:00
Patrik Svensson
f1f633cc72 Merge pull request #1747 from phil-scott-78/spinner-extension 2025-01-28 18:41:34 +01:00
Phil Scott
05ce33615e Add async spinner extension methods and related documentation 2025-01-28 10:20:24 -05:00
Patrik Svensson
97715f2553 Merge pull request #1743 from spectreconsole/FrankRay78-disable-blank-issue 2025-01-25 20:20:59 +01:00
Frank Ray
039553efbb Disable the GitHub 'Blank issue' option offered to users 2025-01-25 18:30:02 +00:00
Patrik Svensson
f704f2a0e8 Merge pull request #1739 from FrankRay78/1738-CommandAppTester-is-trimming-TestConsole-output 2025-01-21 10:33:25 +01:00
Frank Ray
8c5264d117 Trimming of TestConsole output by CommandAppTester is configurable 2025-01-21 08:39:31 +00:00
Martijn Straathof
58bf89a56a Implement 3 digit hex parsing (#1708) 2024-12-04 16:31:21 +01:00
Tom Deseyn
29ab313bb9 Async overloads for AnsiConsole Prompt/Ask/Confirm. (#1194)
* Add async overloads for Prompt/Ask/Confirm.

* Added unit test coverage - AskAsync, ConfirmAsync

* Reordered methods to group non-async/async of the same tests together

---------

Co-authored-by: Frank Ray <52075808+FrankRay78@users.noreply.github.com>
2024-11-28 10:56:19 +00:00
Phil Scott
92daeb739d Update Docs SDK version to 9.0.100, disable NuGetAudit temporarily, and upgrade Scriban to version 5.12.0 for generator 2024-11-23 21:05:36 +01:00
Phil Scott
43e9669395 Update documentation packages to latest versions
* HighlightService was modified to support GetClassifiedSpansAsync method
* Updated Program.cs to pull in the proper location of the Json and ImageSharp extension projects
* Statiq must have changed how they are doing xrefs, so I adjusted those to be more specific with a few links
2024-11-23 14:48:46 +01:00
Phil Scott
ab8384acf6 Update PolySharp to version 1.15.0 and remove Nullable package references 2024-11-23 14:47:01 +01:00
Phil Scott
b2689be3ed Enhance ExceptionFormatter for AOT compatibility by adding fallback handling for stack frames. 2024-11-22 22:55:01 +01:00
Phil Scott
835143d95f Add Native AOT support documentation and update project files for AOT compatibility 2024-11-22 22:55:01 +01:00
Phil Scott
8f2a859087 Fallback to using GetConverter if GetIntrinsicConverter doesn't find one. 2024-11-22 22:55:01 +01:00
Phil Scott
2be8e8da4e Adds fallback for ExceptionFormatter in AOT 2024-11-22 22:55:01 +01:00
Phil Scott
2a8810affd Explicitly marks Spectre.Console.Cli as not trimmable and not appropriate for AOT scenarios. Additionally adds a warning to CommandApp for users who may try it. 2024-11-22 22:55:01 +01:00
Phil Scott
e1d21e7e61 Adding polysharp properly 2024-11-22 22:55:01 +01:00
Phil Scott
c7c3ebdf57 Fix assembly name retrieval for FSharp.Core in TypeNameHelper to work better in AOT scenarios 2024-11-22 22:55:01 +01:00
Phil Scott
b67af32423 Add RequiresDynamicCode attribute to exception formatter to indicate incompatability with AOT 2024-11-22 22:55:01 +01:00
Phil Scott
10773a5625 Refactor enum value retrieval to use EnumUtils for better compatibility with NetStandard 2.0 and AOT 2024-11-22 22:55:01 +01:00
Phil Scott
4802751357 Add AOT compatibility and PolySharp package support 2024-11-22 22:55:01 +01:00
Frank Ray
4515d89705 ProgressTask.GetPercentage() returns 100 when max value is 0 (#1694) 2024-11-22 12:44:00 +01:00
Patrik Svensson
be45494d6e Merge pull request #1691 from phil-scott-78/emoji-perf 2024-11-21 00:30:24 +01:00
Phil Scott
69689d2ba1 Changes Emoji dictionary to OrdinalIgnoreCase for performance
This code is ran on startup, and instantiating a new InvariantCultureIgnoreCase was taking up 11ms, which was half the time in AOT.
2024-11-20 17:55:33 -05:00
Tim Pilius
aa9e5c48c6 Adding TransferSpeedColumn configuration to display bits/bytes + binary/decimal prefixes (#904)
* Adding configuration to TransferSpeedColumn to be able to display in both bytes/bits, as well as using binary/decimal prefix definitions.

---------

Co-authored-by: Frank Ray <52075808+FrankRay78@users.noreply.github.com>
2024-11-19 15:41:49 +00:00
PascalSenn
8d06daf355 Fixed typo in Segment description (#1687) 2024-11-19 06:09:22 +01:00
Mattias Karlsson
cecfdc386c Fix typos (#1684) 2024-11-13 15:00:21 +01:00
Patrik Svensson
375a708c43 Add net9.0 support, remove legacy TFM:s (#1682)
* Update .NET SDK to 9.0.100
* Remove net6.0
* Remove net7.0
* Update dependencies
* Install correct .NET SDK:s in GitHub Actions
2024-11-13 14:54:01 +01:00
Jonathan Sheely
574ead6d46 Added hex color conversion (#1432)
* Added hex color conversion

---------

Co-authored-by: Frank Ray <52075808+FrankRay78@users.noreply.github.com>
Co-authored-by: Nils Andresen <nils@nils-andresen.de>
2024-11-13 13:35:26 +01:00
BlazeFace
a87277e859 Adding Enricher for Azure Pipelines (#1675) 2024-11-04 16:30:35 +01:00
Patrik Svensson
fdc03f2081 Merge pull request #1514 from BlazeFace/blz/issues/1390 2024-10-30 01:36:05 +01:00
BlazeFace
3eb620a44e Fix typo 2024-10-26 07:27:31 -07:00
BlazeFace
bc88da8056 Added last file and used fluent style, relocated test 2024-10-26 07:25:38 -07:00
BlazeFace
00b9aecb4f Add new test files 2024-10-26 07:18:52 -07:00
BlazeFace
444dbed259 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
2024-10-25 17:47:02 -07:00
Arman Ossi Loko
a32dc8030b Fixed docs examples URLs redirecting to the examples repository 2024-10-18 11:33:23 +02:00
renovate[bot]
75547b2436 chore: Update dependency Verify.Xunit to 26.4.5 2024-09-14 14:47:38 +02:00
renovate[bot]
22d1cbe01f chore: Update dependency Roslynator.Analyzers to 4.12.5 2024-09-14 14:36:40 +02:00
Patrik Svensson
7f8ed509bb Fix strange sentence in docs 2024-09-14 14:15:32 +02:00
Cédric Luthi
c70a8b8fc5 Improve exception if a (multi)selection prompt is used incorrectly
Before this commit, the selection prompt would throw an `InvalidOperationException` (Sequence contains no elements) and the multi selection prompt would throw an `ArgumentOutOfRangeException` (Index was out of range. Must be non-negative and less than the size of the collection.)

Both would occur because the prompts were never meant to be empty.
2024-09-11 10:16:21 +02:00
renovate[bot]
b470af11f7 chore: Update dependency Microsoft.NET.Test.Sdk to 17.11.1 (#1630)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-11 09:00:27 +02:00
renovate[bot]
23b160a3f5 chore: Update dependency Verify.Xunit to 26.4.4 (#1624)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-11 08:57:27 +02:00
renovate[bot]
1345a6347a chore: Update dependency MinVer to v6 (#1629)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-11 08:52:25 +02:00
Davide Piccinini
78f3f80b17 Update documentation: add example for the Text Prompt usage (#1636) 2024-09-10 09:03:20 +02:00
Davide Piccinini
a55b80220d Enhance the style of the checkboxes for multi-selection (#1244)
* Enhance the checkboxes' style for multi-selection by applying the selected style, if available, to the checkboxes currently selected.
2024-09-09 16:35:01 +02:00
Davide Piccinini
f8a4b2271d Add unit test to ensure code coverage 2024-09-09 14:28:13 +02:00
Davide Piccinini
dba7ad0875 Fix SA1513 line 38 Tree.cs 2024-09-09 14:28:13 +02:00
Davide Piccinini
322ed2efbb Fix error SA1300 in full property creation 2024-09-09 14:28:13 +02:00
Davide Piccinini
156d254208 Fix issue 1153 on expanded tree 2024-09-09 14:28:13 +02:00
d.piccinini
3437130bf0 Removed blank line 2024-09-09 10:21:00 +02:00
d.piccinini
32384f7b8d Add custom highligh style for single calendar event 2024-09-09 10:21:00 +02:00
Cédric Luthi
32361d3f15 Cleanup prompt tests (#1635)
* Move Should_Search_In_Remapped_Result into the SelectionPromptTests class where it belongs
* Use file sealed class for CustomItem, like it's done with CustomSelectionItem in the selection prompt tests
2024-09-07 15:19:55 +01:00
Daniel Cazzulino
b9d2d2df6d Add spanish translation for help strings 2024-09-06 20:36:30 +02:00
Daniel Cazzulino
8e44a83737 Simplify InternalsVisibleTo
If the $(PublicKey) property is used, the SDK targets will automatically use it for the assembly attributes.

See https://github.com/dotnet/sdk/pull/3439

Simplifies https://github.com/spectreconsole/spectre.console/pull/1623
2024-09-06 20:31:18 +02:00
Patrik Svensson
fd69ad0b01 Fix search bug in prompt related to custom item types
Closes #1626
2024-09-03 00:46:18 +02:00
Kirill Osenkov
753894de94 Bump Spectre.Verify.Extensions to strong-named version
Remove NoWarn now that Spectre.Verify.Extensions is strong-named
2024-09-02 02:49:21 +02:00
renovate[bot]
dc2cb40b79 chore: Update rickstaa/top-issues-action action to v1.3.101 2024-08-30 09:40:24 +02:00
renovate[bot]
511f798f0f chore: Update dependency Microsoft.NET.Test.Sdk to 17.11.0 2024-08-30 09:34:15 +02:00
renovate[bot]
2081c0fd9a chore: Update dependency dotnet-sdk to v8.0.401 2024-08-30 09:30:53 +02:00
Patrik Svensson
96512f353f Fix regression in Razor syntax 2024-08-30 09:18:07 +02:00
Patrik Svensson
56feea11a1 Fix the workflow. Third time the charm? 2024-08-30 09:01:52 +02:00
Patrik Svensson
45c24055fa (Hopefully) fix workflow 2024-08-30 09:01:03 +02:00
Patrik Svensson
d56139756c Lock SDK for documentation for now 2024-08-30 08:59:15 +02:00
Patrik Svensson
7af1eedca7 Merge pull request #1623 from KirillOsenkov/dev/kirillo/snk 2024-08-30 07:45:19 +02:00
Kirill Osenkov
6116af3844 Strong name the assemblies 2024-08-29 16:52:55 -07:00
Patrik Svensson
2cc6c457ad Merge pull request #1603 from spectreconsole/renovate/verify.xunit-26.x
chore: Update dependency Verify.Xunit to v26.2.0
2024-08-10 13:07:40 +02:00
renovate[bot]
f02b46107e chore: Update dependency Verify.Xunit to v26.2.0 2024-08-10 10:41:25 +00:00
Patrik Svensson
42fd801876 Preparations for the 1.0 release
* Less cluttered solution layout.
* Move examples to a repository of its own.
* Move Roslyn analyzer to a repository of its own.
* Enable central package management.
* Clean up csproj files.
* Add README file to NuGet packages.
2024-08-06 15:38:28 +02:00
tonwin618
bb72b44d60 Delete based on character width when pressing Backspace. 2024-08-01 11:07:16 +02:00
ymqn
d79e6adc5f Updated test expectations to match changes in HtmlEncoder 2024-07-25 23:13:06 +02:00
ymqn
64b9ef582d Fixed incorrect decoration check from Bold to Italic in HtmlEncoder.BuildCss 2024-07-25 23:13:06 +02:00
renovate[bot]
a19c84e25a chore: Update dependency SixLabors.ImageSharp to v3.1.5 [SECURITY] 2024-07-22 19:50:33 +02:00
Jan Klass
b61fff042b Make method reference to Markup.Escape more obvious
best-practices refers and links to the `Markup.Escape` method but labeled it `EscapeMarkup`.

I got quite confused trying to find EscapeMarkup. Using the typical *class dot method* pattern seems preferable. It also matches what you write in code.
2024-06-23 14:29:25 +02:00
Jan Klass
ca441dbe7a Fix outdated issue label reference 'up for grabs' -> 'good first issue' 2024-06-23 14:28:52 +02:00
Jan Klass
f6bcf67cbe Update MSDN link to learn.microsoft.com 2024-06-23 14:27:33 +02:00
Daniel Cazzulino
5c87d7fa04 Allow using -? as a shorthand for -h
Given that it's quite a common switch and extremely unlikely to be already in use for something else, we can just consider it to be the same as having entered `-h` as an arg.

This adds the `?` as a valid option character name.

Fixes #1547
2024-05-29 08:38:55 +02:00
renovate[bot]
0e2ed511a5 chore: Update dependency Microsoft.NET.Test.Sdk to v17.10.0 2024-05-22 18:18:50 +02:00
Mattias Karlsson
7b13148773 Trim trailing comma in settings 2024-05-17 16:51:45 +02:00
renovate[bot]
e5a6459c52 chore: Update rickstaa/top-issues-action action to v1.3.100 2024-04-27 16:43:19 +02:00
renovate[bot]
68b28b57f2 chore: Update dependency Roslynator.Analyzers to v4.12.2 2024-04-27 16:42:58 +02:00
renovate[bot]
43b5ac99f9 chore: Update dependency dotnet-sdk to v8.0.204 2024-04-27 11:34:51 +02:00
Sean Fausett
b1b50a21f7 Remove redundant explain settings ctor 2024-04-27 07:41:08 +02:00
Patrik Svensson
5d4b2c88e5 Add extension method to use automatic application version 2024-04-25 20:28:13 +02:00
Patrik Svensson
3acc90e47c Make -v|--version opt-in
We added an automatic version option in 0.49. We did this with good
intentions, but forgot that people might already use --version
as an option for a root command.

This commit makes -v|--version completely opt-in.
2024-04-25 20:28:13 +02:00
Patrik Svensson
88515b7d7f Add Verify.Tool dotnet tool 2024-04-25 20:28:13 +02:00
Patrik Svensson
c5e11626b5 Add blog post for 0.49 release 2024-04-23 15:18:52 +02:00
Patrik Svensson
2ead177404 Update social card to show .NET 8.0 2024-04-23 15:18:42 +02:00
BlazeFace
d52d14e848 Undo debug change and add method group 2024-04-13 17:23:26 -07:00
BlazeFace
a62e79992b Undo debug changes 2024-04-13 17:20:12 -07:00
BlazeFace
4f22f5b7c3 Add Reference File 2024-04-13 17:19:19 -07:00
BlazeFace
20a2f727f7 Updating test and Ratio calculation 2024-04-09 06:03:45 -07:00
878 changed files with 8357 additions and 7769 deletions

View File

@@ -8,7 +8,7 @@ indent_size = 4
insert_final_newline = false insert_final_newline = false
trim_trailing_whitespace = true trim_trailing_whitespace = true
[*.sln] [*.{sln,slnx}]
indent_style = tab indent_style = tab
[*.{csproj,vbproj,vcxproj,vcxproj.filters}] [*.{csproj,vbproj,vcxproj,vcxproj.filters}]

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1 @@
blank_issues_enabled: false

View File

@@ -18,17 +18,16 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup .NET SDK - name: Setup .NET SDK
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v5
with: with:
dotnet-version: | dotnet-version: |
6.0.x
7.0.x
8.0.x 8.0.x
9.0.x
- name: Build - name: Build
shell: bash shell: bash

View File

@@ -24,17 +24,16 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup .NET SDK - name: Setup .NET SDK
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v5
with: with:
dotnet-version: | dotnet-version: |
6.0.x
7.0.x
8.0.x 8.0.x
9.0.x
- name: Publish - name: Publish
shell: bash shell: bash
@@ -54,17 +53,17 @@ jobs:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup .NET SDK - name: Setup .NET SDK
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v5
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v5
with: with:
node-version: '16' node-version: '22'
- name: Cache dependencies - name: Cache dependencies
uses: actions/cache@v4 uses: actions/cache@v4

View File

@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Top Issues action - name: Top Issues action
uses: rickstaa/top-issues-action@v1.3.99 uses: rickstaa/top-issues-action@v1.3.101
env: env:
github_token: ${{ secrets.GITHUB_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }}
with: with:

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

@@ -49,25 +49,8 @@ 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
@@ -100,7 +83,7 @@ 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.

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

@@ -12,10 +12,11 @@ Task("Clean")
Task("Build") Task("Build")
.IsDependentOn("Clean") .IsDependentOn("Clean")
.Does(context => .Does(context =>
{ {
Information("Compiling generator..."); Information("Compiling generator...");
DotNetBuild("./resources/scripts/Generator/Generator.sln", new DotNetBuildSettings { DotNetBuild("./resources/scripts/Generator/Generator.slnx", new DotNetBuildSettings
{
Configuration = configuration, Configuration = configuration,
Verbosity = DotNetVerbosity.Minimal, Verbosity = DotNetVerbosity.Minimal,
NoLogo = true, NoLogo = true,
@@ -25,35 +26,8 @@ Task("Build")
}); });
Information("\nCompiling Spectre.Console..."); Information("\nCompiling Spectre.Console...");
DotNetBuild("./src/Spectre.Console.sln", new DotNetBuildSettings { DotNetBuild("./src/Spectre.Console.slnx", new DotNetBuildSettings
Configuration = configuration, {
Verbosity = DotNetVerbosity.Minimal,
NoLogo = true,
NoIncremental = context.HasArgument("rebuild"),
MSBuildSettings = new DotNetMSBuildSettings()
.TreatAllWarningsAs(MSBuildTreatAllWarningsAs.Error)
});
});
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, Configuration = configuration,
Verbosity = DotNetVerbosity.Minimal, Verbosity = DotNetVerbosity.Minimal,
NoLogo = true, NoLogo = true,
@@ -65,11 +39,9 @@ Task("Build-Examples")
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 +49,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,
@@ -96,20 +60,10 @@ Task("Test")
Task("Package") Task("Package")
.IsDependentOn("Test") .IsDependentOn("Test")
.Does(context => .Does(context =>
{ {
context.DotNetPack($"./src/Spectre.Console.sln", new DotNetPackSettings { context.DotNetPack($"./src/Spectre.Console.slnx", new DotNetPackSettings
Configuration = configuration, {
Verbosity = DotNetVerbosity.Minimal,
NoLogo = true,
NoRestore = true,
NoBuild = true,
OutputDirectory = "./.artifacts",
MSBuildSettings = new DotNetMSBuildSettings()
.TreatAllWarningsAs(MSBuildTreatAllWarningsAs.Error)
});
context.DotNetPack($"./src/Spectre.Console.Analyzer.sln", new DotNetPackSettings {
Configuration = configuration, Configuration = configuration,
Verbosity = DotNetVerbosity.Minimal, Verbosity = DotNetVerbosity.Minimal,
NoLogo = true, NoLogo = true,
@@ -155,4 +109,4 @@ Task("Default")
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Execution // Execution
RunTarget(target) RunTarget(target);

View File

@@ -7,6 +7,11 @@
<DefaultItemExcludes>$(DefaultItemExcludes);output\**;.gitignore</DefaultItemExcludes> <DefaultItemExcludes>$(DefaultItemExcludes);output\**;.gitignore</DefaultItemExcludes>
<NoWarn>MVC1000</NoWarn> <NoWarn>MVC1000</NoWarn>
<MinVerSkip>true</MinVerSkip> <MinVerSkip>true</MinVerSkip>
<!--
Disable NuGetAudit for now, there is an in progress PR with Statiq regarding these packages,
but since since this is just a generator we are safe to ignore this for now.
-->
<NuGetAudit>false</NuGetAudit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -33,13 +38,13 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Playwright" Version="1.19.0" /> <PackageReference Include="Microsoft.Playwright" Version="1.55.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="Statiq.CodeAnalysis" Version="1.0.0-beta.58" /> <PackageReference Include="Statiq.CodeAnalysis" Version="1.0.0-beta.72" />
<PackageReference Include="Statiq.Common" Version="1.0.0-beta.58" /> <PackageReference Include="Statiq.Common" Version="1.0.0-beta.72" />
<PackageReference Include="Statiq.Web" Version="1.0.0-beta.44" /> <PackageReference Include="Statiq.Web" Version="1.0.0-beta.60" />
<PackageReference Include="MinVer" PrivateAssets="All" Version="2.5.0" /> <PackageReference Include="MinVer" PrivateAssets="All" Version="6.0.0" />
<PackageReference Include="Statiq.Web.Netlify" Version="1.0.0-beta.44" /> <PackageReference Include="Statiq.Web.Netlify" Version="1.0.0-beta.60" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,25 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30011.22
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Docs", "Docs.csproj", "{C337F609-A890-4E52-BDA3-91658039B0E3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C337F609-A890-4E52-BDA3-91658039B0E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C337F609-A890-4E52-BDA3-91658039B0E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C337F609-A890-4E52-BDA3-91658039B0E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C337F609-A890-4E52-BDA3-91658039B0E3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2FB3922B-494A-45EB-A479-FC507B8E107C}
EndGlobalSection
EndGlobal

3
docs/Docs.slnx Normal file
View File

@@ -0,0 +1,3 @@
<Solution>
<Project Path="Docs.csproj" />
</Solution>

View File

@@ -23,8 +23,9 @@ namespace Docs
{ {
"../../src/Spectre.Console/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs", "../../src/Spectre.Console/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
"../../src/Spectre.Console.Cli/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs", "../../src/Spectre.Console.Cli/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
"../../src/Spectre.Console.ImageSharp/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs", "../../src/Spectre.Console.Testing/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
"../../src/Spectre.Console.Json/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs" "../../src/Extensions/Spectre.Console.ImageSharp/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs",
"../../src/Extensions/Spectre.Console.Json/**/{!bin,!obj,!packages,!*.Tests,}/**/*.cs"
}) })
.AddSetting(Constants.ExampleSourceFiles, new List<string> .AddSetting(Constants.ExampleSourceFiles, new List<string>
{ {

View File

@@ -3,7 +3,7 @@
"isRoot": true, "isRoot": true,
"tools": { "tools": {
"microsoft.playwright.cli": { "microsoft.playwright.cli": {
"version": "1.2.2", "version": "1.2.3",
"commands": [ "commands": [
"playwright" "playwright"
] ]

View File

@@ -1,6 +0,0 @@
{
"sdk": {
"version": "8.0.100",
"rollForward": "latestFeature"
}
}

View File

@@ -29,7 +29,7 @@ Optional: Embed an asciicast. The cast parameter should be the base name of the
one suffixed with -rich.cast and a second named -plain.cast. The cast attribute should be the name without one suffixed with -rich.cast and a second named -plain.cast. The cast attribute should be the name without
the suffix. the suffix.
To generate a new cast file, open the \resources\scripts\Generator\Generator.sln project and add a new sample in the To generate a new cast file, open the \resources\scripts\Generator\Generator.slnx project and add a new sample in the
Commands/AsciiCast/Samples/ folder. If the widget is static such as a tree or a table, try and animate the widget Commands/AsciiCast/Samples/ folder. If the widget is static such as a tree or a table, try and animate the widget
using the Live widget to change the content or styling. using the Live widget to change the content or styling.

View File

@@ -10,7 +10,7 @@ For all available spinners, see https://jsfiddle.net/sindresorhus/2eLtsbey/embed
## Usage ## Usage
Spinners can be used with [Progress](xref:progress) and [Status](xref:status). Spinners can be used with [Progress](xref:live-progress) and [Status](xref:live-status).
```csharp ```csharp
AnsiConsole.Status() AnsiConsole.Status()

View File

@@ -6,6 +6,7 @@ Highlights:
- Dim, Invert - Dim, Invert
- Conceal, slowblink, rapidblink - Conceal, slowblink, rapidblink
- Links - Links
Xref: appendix-styles
--- ---
Note that what styles that can be used is defined by the system or your terminal software, and may not appear as they should. Note that what styles that can be used is defined by the system or your terminal software, and may not appear as they should.
@@ -48,7 +49,7 @@ Note that what styles that can be used is defined by the system or your terminal
<td>Shows text with a horizontal line through the center</td> <td>Shows text with a horizontal line through the center</td>
</tr> </tr>
<tr> <tr>
<td><code>link</link></td> <td><code>link</code></td>
<td>Creates a clickable link within text</td> <td>Creates a clickable link within text</td>
</tr> </tr>
</table> </table>

View File

@@ -0,0 +1,2 @@
{"version": 2, "width": 40, "height": 3, "timestamp": 1667342769, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
[0.0, "o", "\u001b[H\u001b[2B\u001b[38;5;9;48;5;0mSpectre!\u001b[0m"]

View File

@@ -0,0 +1,332 @@
{"version": 2, "width": 42, "height": 4, "title": "await-spinner (plain)", "env": {"TERM": "Spectre.Console"}}
[0, "o", "Loading the rocket ship "]
[0, "o", "\u001B[?25l"]
[0, "o", "\u280B"]
[0, "o", "\u001B[1D"]
[0.094, "o", "\u001B[?25l"]
[0.094, "o", "\u2819"]
[0.094, "o", "\u001B[1D"]
[0.188, "o", "\u001B[?25l"]
[0.188, "o", "\u2839"]
[0.188, "o", "\u001B[1D"]
[0.266, "o", "\u001B[?25l"]
[0.266, "o", "\u2838"]
[0.266, "o", "\u001B[1D"]
[0.36, "o", "\u001B[?25l"]
[0.36, "o", "\u283C"]
[0.36, "o", "\u001B[1D"]
[0.453, "o", "\u001B[?25l"]
[0.453, "o", "\u2834"]
[0.453, "o", "\u001B[1D"]
[0.563, "o", "\u001B[?25l"]
[0.563, "o", "\u2826"]
[0.563, "o", "\u001B[1D"]
[0.656, "o", "\u001B[?25l"]
[0.656, "o", "\u2827"]
[0.656, "o", "\u001B[1D"]
[0.75, "o", "\u001B[?25l"]
[0.75, "o", "\u2807"]
[0.75, "o", "\u001B[1D"]
[0.844, "o", "\u001B[?25l"]
[0.844, "o", "\u280F"]
[0.844, "o", "\u001B[1D"]
[0.922, "o", "\u001B[?25l"]
[0.922, "o", "\u280B"]
[0.922, "o", "\u001B[1D"]
[1.016, "o", "\u001B[?25l"]
[1.016, "o", "\u2819"]
[1.016, "o", "\u001B[1D"]
[1.11, "o", "\u001B[?25l"]
[1.11, "o", "\u2839"]
[1.11, "o", "\u001B[1D"]
[1.203, "o", "\u001B[?25l"]
[1.203, "o", "\u2838"]
[1.203, "o", "\u001B[1D"]
[1.297, "o", "\u001B[?25l"]
[1.297, "o", "\u283C"]
[1.297, "o", "\u001B[1D"]
[1.391, "o", "\u001B[?25l"]
[1.391, "o", "\u2834"]
[1.391, "o", "\u001B[1D"]
[1.485, "o", "\u001B[?25l"]
[1.485, "o", "\u2826"]
[1.485, "o", "\u001B[1D"]
[1.578, "o", "\u001B[?25l"]
[1.578, "o", "\u2827"]
[1.578, "o", "\u001B[1D"]
[1.672, "o", "\u001B[?25l"]
[1.672, "o", "\u2807"]
[1.672, "o", "\u001B[1D"]
[1.75, "o", "\u001B[?25l"]
[1.75, "o", "\u280F"]
[1.75, "o", "\u001B[1D"]
[1.828, "o", "\u001B[?25l"]
[1.828, "o", "\u280B"]
[1.828, "o", "\u001B[1D"]
[1.906, "o", "\u001B[?25l"]
[1.906, "o", "\u2819"]
[1.906, "o", "\u001B[1D"]
[2, "o", "\u001B[?25l"]
[2, "o", "\u2839"]
[2, "o", "\u001B[1D"]
[2.11, "o", "\u001B[?25l"]
[2.11, "o", "\u2838"]
[2.11, "o", "\u001B[1D"]
[2.203, "o", "\u001B[?25l"]
[2.203, "o", "\u283C"]
[2.203, "o", "\u001B[1D"]
[2.297, "o", "\u001B[?25l"]
[2.297, "o", "\u2834"]
[2.297, "o", "\u001B[1D"]
[2.391, "o", "\u001B[?25l"]
[2.391, "o", "\u2826"]
[2.391, "o", "\u001B[1D"]
[2.485, "o", "\u001B[?25l"]
[2.485, "o", "\u2827"]
[2.485, "o", "\u001B[1D"]
[2.578, "o", "\u001B[?25l"]
[2.578, "o", "\u2807"]
[2.578, "o", "\u001B[1D"]
[2.656, "o", "\u001B[?25l"]
[2.656, "o", "\u280F"]
[2.656, "o", "\u001B[1D"]
[2.735, "o", "\u001B[?25l"]
[2.735, "o", "\u280B"]
[2.735, "o", "\u001B[1D"]
[2.828, "o", "\u001B[?25l"]
[2.828, "o", "\u2819"]
[2.828, "o", "\u001B[1D"]
[2.922, "o", "\u001B[?25l"]
[2.922, "o", "\u2839"]
[2.922, "o", "\u001B[1D"]
[3.016, "o", "\u001B[?25l"]
[3.016, "o", "\u2838"]
[3.016, "o", "\u001B[1D"]
[3.094, "o", "\u001B[?25l"]
[3.094, "o", "\u283C"]
[3.094, "o", "\u001B[1D"]
[3.188, "o", "\u001B[?25l"]
[3.188, "o", "\u2834"]
[3.188, "o", "\u001B[1D"]
[3.281, "o", "\u001B[?25l"]
[3.281, "o", "\u2826"]
[3.281, "o", "\u001B[1D"]
[3.375, "o", "\u001B[?25l"]
[3.375, "o", "\u2827"]
[3.375, "o", "\u001B[1D"]
[3.453, "o", "\u001B[?25l"]
[3.453, "o", "\u2807"]
[3.453, "o", "\u001B[1D"]
[3.516, "o", " "]
[3.516, "o", "\u001B[1D"]
[3.516, "o", "\u001B[?25h"]
[3.516, "o", "\u001B[32mDone\u001B[0m\r\n"]
[3.516, "o", "Firing up the engines "]
[3.516, "o", "\u001B[?25l"]
[3.516, "o", "[ ]"]
[3.516, "o", "\u001B[6D"]
[3.61, "o", "\u001B[?25l"]
[3.61, "o", "[= ]"]
[3.61, "o", "\u001B[6D"]
[3.703, "o", "\u001B[?25l"]
[3.703, "o", "[== ]"]
[3.703, "o", "\u001B[6D"]
[3.797, "o", "\u001B[?25l"]
[3.797, "o", "[=== ]"]
[3.797, "o", "\u001B[6D"]
[3.875, "o", "\u001B[?25l"]
[3.875, "o", "[ ===]"]
[3.875, "o", "\u001B[6D"]
[3.953, "o", "\u001B[?25l"]
[3.953, "o", "[ ==]"]
[3.953, "o", "\u001B[6D"]
[4.063, "o", "\u001B[?25l"]
[4.063, "o", "[ =]"]
[4.063, "o", "\u001B[6D"]
[4.156, "o", "\u001B[?25l"]
[4.156, "o", "[ ]"]
[4.156, "o", "\u001B[6D"]
[4.25, "o", "\u001B[?25l"]
[4.25, "o", "[ =]"]
[4.25, "o", "\u001B[6D"]
[4.328, "o", "\u001B[?25l"]
[4.328, "o", "[ ==]"]
[4.328, "o", "\u001B[6D"]
[4.406, "o", "\u001B[?25l"]
[4.406, "o", "[ ===]"]
[4.406, "o", "\u001B[6D"]
[4.5, "o", "\u001B[?25l"]
[4.5, "o", "[====]"]
[4.5, "o", "\u001B[6D"]
[4.594, "o", "\u001B[?25l"]
[4.594, "o", "[=== ]"]
[4.594, "o", "\u001B[6D"]
[4.688, "o", "\u001B[?25l"]
[4.688, "o", "[== ]"]
[4.688, "o", "\u001B[6D"]
[4.781, "o", "\u001B[?25l"]
[4.781, "o", "[= ]"]
[4.781, "o", "\u001B[6D"]
[4.86, "o", "\u001B[?25l"]
[4.86, "o", "[ ]"]
[4.86, "o", "\u001B[6D"]
[4.953, "o", "\u001B[?25l"]
[4.953, "o", "[= ]"]
[4.953, "o", "\u001B[6D"]
[5.031, "o", "\u001B[?25l"]
[5.031, "o", "[== ]"]
[5.031, "o", "\u001B[6D"]
[5.125, "o", "\u001B[?25l"]
[5.125, "o", "[=== ]"]
[5.125, "o", "\u001B[6D"]
[5.219, "o", "\u001B[?25l"]
[5.219, "o", "[ ===]"]
[5.219, "o", "\u001B[6D"]
[5.313, "o", "\u001B[?25l"]
[5.313, "o", "[ ==]"]
[5.313, "o", "\u001B[6D"]
[5.422, "o", "\u001B[?25l"]
[5.422, "o", "[ =]"]
[5.422, "o", "\u001B[6D"]
[5.5, "o", "\u001B[?25l"]
[5.5, "o", "[ ]"]
[5.5, "o", "\u001B[6D"]
[5.594, "o", "\u001B[?25l"]
[5.594, "o", "[ =]"]
[5.594, "o", "\u001B[6D"]
[5.672, "o", "\u001B[?25l"]
[5.672, "o", "[ ==]"]
[5.672, "o", "\u001B[6D"]
[5.766, "o", "\u001B[?25l"]
[5.766, "o", "[ ===]"]
[5.766, "o", "\u001B[6D"]
[5.86, "o", "\u001B[?25l"]
[5.86, "o", "[====]"]
[5.86, "o", "\u001B[6D"]
[5.953, "o", "\u001B[?25l"]
[5.969, "o", "[=== ]"]
[5.969, "o", "\u001B[6D"]
[6.063, "o", "\u001B[?25l"]
[6.063, "o", "[== ]"]
[6.063, "o", "\u001B[6D"]
[6.156, "o", "\u001B[?25l"]
[6.156, "o", "[= ]"]
[6.156, "o", "\u001B[6D"]
[6.25, "o", "\u001B[?25l"]
[6.25, "o", "[ ]"]
[6.25, "o", "\u001B[6D"]
[6.328, "o", "\u001B[?25l"]
[6.328, "o", "[= ]"]
[6.328, "o", "\u001B[6D"]
[6.422, "o", "\u001B[?25l"]
[6.422, "o", "[== ]"]
[6.422, "o", "\u001B[6D"]
[6.516, "o", "\u001B[?25l"]
[6.516, "o", "[=== ]"]
[6.516, "o", "\u001B[6D"]
[6.61, "o", "\u001B[?25l"]
[6.61, "o", "[ ===]"]
[6.61, "o", "\u001B[6D"]
[6.703, "o", "\u001B[?25l"]
[6.703, "o", "[ ==]"]
[6.703, "o", "\u001B[6D"]
[6.797, "o", "\u001B[?25l"]
[6.797, "o", "[ =]"]
[6.797, "o", "\u001B[6D"]
[6.891, "o", "\u001B[?25l"]
[6.891, "o", "[ ]"]
[6.891, "o", "\u001B[6D"]
[6.922, "o", " "]
[6.922, "o", "\u001B[6D"]
[6.922, "o", "\u001B[?25h"]
[6.922, "o", "\u001B[32mDone\u001B[0m\r\n"]
[6.922, "o", "Blasting into orbit "]
[6.922, "o", "\u001B[?25l"]
[6.922, "o", "\u2631"]
[6.922, "o", "\u001B[1D"]
[7.031, "o", "\u001B[?25l"]
[7.031, "o", "\u2632"]
[7.031, "o", "\u001B[1D"]
[7.141, "o", "\u001B[?25l"]
[7.141, "o", "\u2634"]
[7.141, "o", "\u001B[1D"]
[7.25, "o", "\u001B[?25l"]
[7.25, "o", "\u2631"]
[7.25, "o", "\u001B[1D"]
[7.36, "o", "\u001B[?25l"]
[7.36, "o", "\u2632"]
[7.36, "o", "\u001B[1D"]
[7.485, "o", "\u001B[?25l"]
[7.485, "o", "\u2634"]
[7.485, "o", "\u001B[1D"]
[7.594, "o", "\u001B[?25l"]
[7.594, "o", "\u2631"]
[7.594, "o", "\u001B[1D"]
[7.703, "o", "\u001B[?25l"]
[7.703, "o", "\u2632"]
[7.703, "o", "\u001B[1D"]
[7.813, "o", "\u001B[?25l"]
[7.813, "o", "\u2634"]
[7.813, "o", "\u001B[1D"]
[7.922, "o", "\u001B[?25l"]
[7.922, "o", "\u2631"]
[7.922, "o", "\u001B[1D"]
[8.031, "o", "\u001B[?25l"]
[8.031, "o", "\u2632"]
[8.031, "o", "\u001B[1D"]
[8.141, "o", "\u001B[?25l"]
[8.141, "o", "\u2634"]
[8.141, "o", "\u001B[1D"]
[8.25, "o", "\u001B[?25l"]
[8.25, "o", "\u2631"]
[8.25, "o", "\u001B[1D"]
[8.375, "o", "\u001B[?25l"]
[8.375, "o", "\u2632"]
[8.375, "o", "\u001B[1D"]
[8.485, "o", "\u001B[?25l"]
[8.485, "o", "\u2634"]
[8.485, "o", "\u001B[1D"]
[8.594, "o", "\u001B[?25l"]
[8.594, "o", "\u2631"]
[8.594, "o", "\u001B[1D"]
[8.703, "o", "\u001B[?25l"]
[8.703, "o", "\u2632"]
[8.703, "o", "\u001B[1D"]
[8.813, "o", "\u001B[?25l"]
[8.813, "o", "\u2634"]
[8.813, "o", "\u001B[1D"]
[8.938, "o", "\u001B[?25l"]
[8.938, "o", "\u2631"]
[8.938, "o", "\u001B[1D"]
[9.047, "o", "\u001B[?25l"]
[9.047, "o", "\u2632"]
[9.047, "o", "\u001B[1D"]
[9.156, "o", "\u001B[?25l"]
[9.156, "o", "\u2634"]
[9.156, "o", "\u001B[1D"]
[9.266, "o", "\u001B[?25l"]
[9.266, "o", "\u2631"]
[9.266, "o", "\u001B[1D"]
[9.375, "o", "\u001B[?25l"]
[9.375, "o", "\u2632"]
[9.375, "o", "\u001B[1D"]
[9.485, "o", "\u001B[?25l"]
[9.485, "o", "\u2634"]
[9.485, "o", "\u001B[1D"]
[9.594, "o", "\u001B[?25l"]
[9.594, "o", "\u2631"]
[9.594, "o", "\u001B[1D"]
[9.719, "o", "\u001B[?25l"]
[9.719, "o", "\u2632"]
[9.719, "o", "\u001B[1D"]
[9.828, "o", "\u001B[?25l"]
[9.828, "o", "\u2634"]
[9.828, "o", "\u001B[1D"]
[9.938, "o", "\u001B[?25l"]
[9.938, "o", "\u2631"]
[9.938, "o", "\u001B[1D"]
[9.953, "o", " "]
[9.953, "o", "\u001B[1D"]
[9.953, "o", "\u001B[?25h"]
[9.953, "o", "\u001B[31mOh no\u001B[0m\r\n"]

View File

@@ -0,0 +1,326 @@
{"version": 2, "width": 42, "height": 4, "title": "await-spinner (rich)", "env": {"TERM": "Spectre.Console"}}
[0, "o", "Loading the rocket ship "]
[0, "o", "\u001B[?25l"]
[0, "o", "\u280B"]
[0, "o", "\u001B[1D"]
[0.094, "o", "\u001B[?25l"]
[0.094, "o", "\u2819"]
[0.094, "o", "\u001B[1D"]
[0.172, "o", "\u001B[?25l"]
[0.172, "o", "\u2839"]
[0.172, "o", "\u001B[1D"]
[0.266, "o", "\u001B[?25l"]
[0.266, "o", "\u2838"]
[0.266, "o", "\u001B[1D"]
[0.36, "o", "\u001B[?25l"]
[0.36, "o", "\u283C"]
[0.36, "o", "\u001B[1D"]
[0.453, "o", "\u001B[?25l"]
[0.453, "o", "\u2834"]
[0.453, "o", "\u001B[1D"]
[0.547, "o", "\u001B[?25l"]
[0.547, "o", "\u2826"]
[0.547, "o", "\u001B[1D"]
[0.641, "o", "\u001B[?25l"]
[0.641, "o", "\u2827"]
[0.641, "o", "\u001B[1D"]
[0.719, "o", "\u001B[?25l"]
[0.719, "o", "\u2807"]
[0.719, "o", "\u001B[1D"]
[0.797, "o", "\u001B[?25l"]
[0.797, "o", "\u280F"]
[0.797, "o", "\u001B[1D"]
[0.891, "o", "\u001B[?25l"]
[0.891, "o", "\u280B"]
[0.891, "o", "\u001B[1D"]
[0.969, "o", "\u001B[?25l"]
[0.969, "o", "\u2819"]
[0.969, "o", "\u001B[1D"]
[1.078, "o", "\u001B[?25l"]
[1.078, "o", "\u2839"]
[1.094, "o", "\u001B[1D"]
[1.25, "o", "\u001B[?25l"]
[1.25, "o", "\u2838"]
[1.266, "o", "\u001B[1D"]
[1.407, "o", "\u001B[?25l"]
[1.407, "o", "\u283C"]
[1.422, "o", "\u001B[1D"]
[1.532, "o", "\u001B[?25l"]
[1.532, "o", "\u2834"]
[1.532, "o", "\u001B[1D"]
[1.61, "o", "\u001B[?25l"]
[1.61, "o", "\u2826"]
[1.61, "o", "\u001B[1D"]
[1.703, "o", "\u001B[?25l"]
[1.703, "o", "\u2827"]
[1.703, "o", "\u001B[1D"]
[1.782, "o", "\u001B[?25l"]
[1.782, "o", "\u2807"]
[1.782, "o", "\u001B[1D"]
[1.86, "o", "\u001B[?25l"]
[1.86, "o", "\u280F"]
[1.86, "o", "\u001B[1D"]
[1.953, "o", "\u001B[?25l"]
[1.953, "o", "\u280B"]
[1.953, "o", "\u001B[1D"]
[2.047, "o", "\u001B[?25l"]
[2.047, "o", "\u2819"]
[2.047, "o", "\u001B[1D"]
[2.125, "o", "\u001B[?25l"]
[2.125, "o", "\u2839"]
[2.125, "o", "\u001B[1D"]
[2.219, "o", "\u001B[?25l"]
[2.219, "o", "\u2838"]
[2.219, "o", "\u001B[1D"]
[2.313, "o", "\u001B[?25l"]
[2.313, "o", "\u283C"]
[2.313, "o", "\u001B[1D"]
[2.407, "o", "\u001B[?25l"]
[2.407, "o", "\u2834"]
[2.407, "o", "\u001B[1D"]
[2.5, "o", "\u001B[?25l"]
[2.5, "o", "\u2826"]
[2.5, "o", "\u001B[1D"]
[2.594, "o", "\u001B[?25l"]
[2.594, "o", "\u2827"]
[2.594, "o", "\u001B[1D"]
[2.688, "o", "\u001B[?25l"]
[2.688, "o", "\u2807"]
[2.688, "o", "\u001B[1D"]
[2.782, "o", "\u001B[?25l"]
[2.782, "o", "\u280F"]
[2.782, "o", "\u001B[1D"]
[2.875, "o", "\u001B[?25l"]
[2.875, "o", "\u280B"]
[2.875, "o", "\u001B[1D"]
[2.969, "o", "\u001B[?25l"]
[2.969, "o", "\u2819"]
[2.969, "o", "\u001B[1D"]
[3.063, "o", "\u001B[?25l"]
[3.063, "o", "\u2839"]
[3.063, "o", "\u001B[1D"]
[3.157, "o", "\u001B[?25l"]
[3.157, "o", "\u2838"]
[3.157, "o", "\u001B[1D"]
[3.25, "o", "\u001B[?25l"]
[3.25, "o", "\u283C"]
[3.25, "o", "\u001B[1D"]
[3.344, "o", "\u001B[?25l"]
[3.344, "o", "\u2834"]
[3.344, "o", "\u001B[1D"]
[3.469, "o", "\u001B[?25l"]
[3.469, "o", "\u2826"]
[3.469, "o", "\u001B[1D"]
[3.563, "o", "\u001B[?25l"]
[3.563, "o", "\u2827"]
[3.563, "o", "\u001B[1D"]
[3.563, "o", " "]
[3.563, "o", "\u001B[1D"]
[3.563, "o", "\u001B[?25h"]
[3.563, "o", "\u001B[38;5;2mDone\u001B[0m\r\n"]
[3.563, "o", "Firing up the engines "]
[3.563, "o", "\u001B[?25l"]
[3.563, "o", "[ ]"]
[3.563, "o", "\u001B[6D"]
[3.672, "o", "\u001B[?25l"]
[3.672, "o", "[= ]"]
[3.672, "o", "\u001B[6D"]
[3.75, "o", "\u001B[?25l"]
[3.75, "o", "[== ]"]
[3.75, "o", "\u001B[6D"]
[3.844, "o", "\u001B[?25l"]
[3.844, "o", "[=== ]"]
[3.844, "o", "\u001B[6D"]
[3.953, "o", "\u001B[?25l"]
[3.953, "o", "[ ===]"]
[3.953, "o", "\u001B[6D"]
[4.047, "o", "\u001B[?25l"]
[4.047, "o", "[ ==]"]
[4.047, "o", "\u001B[6D"]
[4.157, "o", "\u001B[?25l"]
[4.157, "o", "[ =]"]
[4.157, "o", "\u001B[6D"]
[4.25, "o", "\u001B[?25l"]
[4.25, "o", "[ ]"]
[4.25, "o", "\u001B[6D"]
[4.344, "o", "\u001B[?25l"]
[4.344, "o", "[ =]"]
[4.344, "o", "\u001B[6D"]
[4.438, "o", "\u001B[?25l"]
[4.438, "o", "[ ==]"]
[4.438, "o", "\u001B[6D"]
[4.532, "o", "\u001B[?25l"]
[4.532, "o", "[ ===]"]
[4.532, "o", "\u001B[6D"]
[4.625, "o", "\u001B[?25l"]
[4.625, "o", "[====]"]
[4.625, "o", "\u001B[6D"]
[4.719, "o", "\u001B[?25l"]
[4.719, "o", "[=== ]"]
[4.719, "o", "\u001B[6D"]
[4.828, "o", "\u001B[?25l"]
[4.844, "o", "[== ]"]
[4.86, "o", "\u001B[6D"]
[4.953, "o", "\u001B[?25l"]
[4.953, "o", "[= ]"]
[4.953, "o", "\u001B[6D"]
[5.047, "o", "\u001B[?25l"]
[5.047, "o", "[ ]"]
[5.047, "o", "\u001B[6D"]
[5.141, "o", "\u001B[?25l"]
[5.141, "o", "[= ]"]
[5.141, "o", "\u001B[6D"]
[5.235, "o", "\u001B[?25l"]
[5.235, "o", "[== ]"]
[5.235, "o", "\u001B[6D"]
[5.328, "o", "\u001B[?25l"]
[5.328, "o", "[=== ]"]
[5.328, "o", "\u001B[6D"]
[5.422, "o", "\u001B[?25l"]
[5.422, "o", "[ ===]"]
[5.422, "o", "\u001B[6D"]
[5.532, "o", "\u001B[?25l"]
[5.532, "o", "[ ==]"]
[5.532, "o", "\u001B[6D"]
[5.625, "o", "\u001B[?25l"]
[5.625, "o", "[ =]"]
[5.625, "o", "\u001B[6D"]
[5.719, "o", "\u001B[?25l"]
[5.719, "o", "[ ]"]
[5.719, "o", "\u001B[6D"]
[5.813, "o", "\u001B[?25l"]
[5.813, "o", "[ =]"]
[5.813, "o", "\u001B[6D"]
[5.907, "o", "\u001B[?25l"]
[5.907, "o", "[ ==]"]
[5.907, "o", "\u001B[6D"]
[6, "o", "\u001B[?25l"]
[6, "o", "[ ===]"]
[6, "o", "\u001B[6D"]
[6.094, "o", "\u001B[?25l"]
[6.094, "o", "[====]"]
[6.094, "o", "\u001B[6D"]
[6.188, "o", "\u001B[?25l"]
[6.188, "o", "[=== ]"]
[6.188, "o", "\u001B[6D"]
[6.282, "o", "\u001B[?25l"]
[6.282, "o", "[== ]"]
[6.282, "o", "\u001B[6D"]
[6.375, "o", "\u001B[?25l"]
[6.375, "o", "[= ]"]
[6.375, "o", "\u001B[6D"]
[6.453, "o", "\u001B[?25l"]
[6.453, "o", "[ ]"]
[6.453, "o", "\u001B[6D"]
[6.547, "o", "\u001B[?25l"]
[6.547, "o", "[= ]"]
[6.547, "o", "\u001B[6D"]
[6.625, "o", "\u001B[?25l"]
[6.625, "o", "[== ]"]
[6.625, "o", "\u001B[6D"]
[6.703, "o", "\u001B[?25l"]
[6.703, "o", "[=== ]"]
[6.703, "o", "\u001B[6D"]
[6.797, "o", "\u001B[?25l"]
[6.797, "o", "[ ===]"]
[6.797, "o", "\u001B[6D"]
[6.891, "o", "\u001B[?25l"]
[6.891, "o", "[ ==]"]
[6.891, "o", "\u001B[6D"]
[6.969, "o", " "]
[6.969, "o", "\u001B[6D"]
[6.969, "o", "\u001B[?25h"]
[6.969, "o", "\u001B[38;5;2mDone\u001B[0m\r\n"]
[6.969, "o", "Blasting into orbit "]
[6.969, "o", "\u001B[?25l"]
[6.969, "o", "\u2631"]
[6.969, "o", "\u001B[1D"]
[7.078, "o", "\u001B[?25l"]
[7.078, "o", "\u2632"]
[7.078, "o", "\u001B[1D"]
[7.172, "o", "\u001B[?25l"]
[7.172, "o", "\u2634"]
[7.172, "o", "\u001B[1D"]
[7.282, "o", "\u001B[?25l"]
[7.282, "o", "\u2631"]
[7.282, "o", "\u001B[1D"]
[7.375, "o", "\u001B[?25l"]
[7.375, "o", "\u2632"]
[7.375, "o", "\u001B[1D"]
[7.485, "o", "\u001B[?25l"]
[7.485, "o", "\u2634"]
[7.485, "o", "\u001B[1D"]
[7.594, "o", "\u001B[?25l"]
[7.594, "o", "\u2631"]
[7.594, "o", "\u001B[1D"]
[7.703, "o", "\u001B[?25l"]
[7.703, "o", "\u2632"]
[7.703, "o", "\u001B[1D"]
[7.813, "o", "\u001B[?25l"]
[7.813, "o", "\u2634"]
[7.813, "o", "\u001B[1D"]
[7.922, "o", "\u001B[?25l"]
[7.922, "o", "\u2631"]
[7.922, "o", "\u001B[1D"]
[8.032, "o", "\u001B[?25l"]
[8.032, "o", "\u2632"]
[8.032, "o", "\u001B[1D"]
[8.125, "o", "\u001B[?25l"]
[8.125, "o", "\u2634"]
[8.125, "o", "\u001B[1D"]
[8.235, "o", "\u001B[?25l"]
[8.235, "o", "\u2631"]
[8.235, "o", "\u001B[1D"]
[8.344, "o", "\u001B[?25l"]
[8.344, "o", "\u2632"]
[8.344, "o", "\u001B[1D"]
[8.453, "o", "\u001B[?25l"]
[8.453, "o", "\u2634"]
[8.453, "o", "\u001B[1D"]
[8.563, "o", "\u001B[?25l"]
[8.563, "o", "\u2631"]
[8.563, "o", "\u001B[1D"]
[8.657, "o", "\u001B[?25l"]
[8.657, "o", "\u2632"]
[8.657, "o", "\u001B[1D"]
[8.766, "o", "\u001B[?25l"]
[8.766, "o", "\u2634"]
[8.766, "o", "\u001B[1D"]
[8.86, "o", "\u001B[?25l"]
[8.86, "o", "\u2631"]
[8.86, "o", "\u001B[1D"]
[8.969, "o", "\u001B[?25l"]
[8.969, "o", "\u2632"]
[8.969, "o", "\u001B[1D"]
[9.078, "o", "\u001B[?25l"]
[9.078, "o", "\u2634"]
[9.078, "o", "\u001B[1D"]
[9.203, "o", "\u001B[?25l"]
[9.203, "o", "\u2631"]
[9.203, "o", "\u001B[1D"]
[9.313, "o", "\u001B[?25l"]
[9.313, "o", "\u2632"]
[9.313, "o", "\u001B[1D"]
[9.407, "o", "\u001B[?25l"]
[9.407, "o", "\u2634"]
[9.407, "o", "\u001B[1D"]
[9.516, "o", "\u001B[?25l"]
[9.516, "o", "\u2631"]
[9.516, "o", "\u001B[1D"]
[9.625, "o", "\u001B[?25l"]
[9.625, "o", "\u2632"]
[9.625, "o", "\u001B[1D"]
[9.719, "o", "\u001B[?25l"]
[9.719, "o", "\u2634"]
[9.735, "o", "\u001B[1D"]
[9.828, "o", "\u001B[?25l"]
[9.828, "o", "\u2631"]
[9.828, "o", "\u001B[1D"]
[9.938, "o", "\u001B[?25l"]
[9.938, "o", "\u2632"]
[9.938, "o", "\u001B[1D"]
[10, "o", " "]
[10, "o", "\u001B[1D"]
[10, "o", "\u001B[?25h"]
[10, "o", "\u001B[38;5;9mOh no\u001B[0m\r\n"]

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.
@@ -85,10 +85,8 @@ on the main thread.
### Unit Testing Best Practices ### Unit Testing Best Practices
For testing of console output, Spectre.Console has [`IAnsiConsole`](xref:T:Spectre.Console.IAnsiConsole) that can be For testing of console output, Spectre.Console has [`IAnsiConsole`](xref:T:Spectre.Console.IAnsiConsole) that can be
injected into your application. injected into your application. The [Spectre.Console.Test](https://www.nuget.org/packages/Spectre.Console.Testing/)
The [Spectre.Console.Test](https://www.nuget.org/packages/Spectre.Console.Testing/) contains a set of utilities for NuGet package contains utilities for capturing the console output for verification. See the [Unit Testing](cli/unit-testing) page for further guidance.
capturing the output for verification, either manually or via a tool such
as [Verify](https://github.com/VerifyTests/Verify).
### Analyzer for Best Practices ### Analyzer for Best Practices
@@ -96,6 +94,31 @@ Spectre.Console has an [analyzer](https://www.nuget.org/packages/Spectre.Console
common errors in writing console output from above such as using multiple live rendering widgets simultaneously, common errors in writing console output from above such as using multiple live rendering widgets simultaneously,
or using the static `AnsiConsole` class when `IAnsiConsole` is available. or using the static `AnsiConsole` class when `IAnsiConsole` is available.
### Native AOT Support
Publishing your app as Native AOT with Spectre.Console produces an app that's self-contained and has been ahead-of-time (AOT) compiled to native code. Native AOT apps have faster startup time and smaller memory footprints. These apps can run on machines that don't have the .NET runtime installed.
To enable AOT support on your application, Add `<PublishAot>true</PublishAot>` to your project file.
```xml
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>
```
Current Spectre.Console support for AOT:
* &#9745;&#65039; Spectre.Console
* &#10060; Spectre.Console.Cli
* &#9745;&#65039; Spectre.Console.Json
* &#9745;&#65039; Spectre.Console.ImageSharp
Spectre.Console.Cli relies on reflection and discovering types at runtime, preventing it from currently supporting AOT.
Spectre.Console supports AOT, but with the following limitations
* `WriteException` will output a simple stacktrace and ignore any `ExceptionFormats` set.
### Configuring the Windows Terminal For Unicode and Emoji Support ### Configuring the Windows Terminal For Unicode and Emoji Support
Windows Terminal supports Unicode and Emoji. However, the shells such as Powershell and cmd.exe do not. Windows Terminal supports Unicode and Emoji. However, the shells such as Powershell and cmd.exe do not.
@@ -119,4 +142,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

@@ -26,9 +26,9 @@ New features have been added, such as the ability to show separators between tab
## Rendering ## Rendering
* Add .NET 8 support by [@patriksvensson](https://github.com/patriksvensson) in [#1367](https://github.com/spectreconsole/spectre.console/pull/1367) * Add .NET 8 support by [@patriksvensson](https://github.com/patriksvensson) in [#1367](https://github.com/spectreconsole/spectre.console/pull/1367)
* Fixed render issue where writeline inside status caused corrupt output #415 #694 by [@fredrikbentzen](https://github.com/fredrikbentzen) in [#1132]([#1132](https://github.com/spectreconsole/spectre.console/pull/1132)) * Fixed render issue where writeline inside status caused corrupt output #415 #694 by [@fredrikbentzen](https://github.com/fredrikbentzen) in [#1132](https://github.com/spectreconsole/spectre.console/pull/1132)
* Relax the SDK requirements by rolling forward to the latest feature by [@0xced](https://github.com/0xced) in [#1237]([#1237](https://github.com/spectreconsole/spectre.console/pull/1237)) * Relax the SDK requirements by rolling forward to the latest feature by [@0xced](https://github.com/0xced) in [#1237](https://github.com/spectreconsole/spectre.console/pull/1237)
* Add fix to avoid exception on rows with no children by [@jeppevammenkristensen](https://github.com/jeppevammenkristensen) in [#1241]([#1241](https://github.com/spectreconsole/spectre.console/pull/1241)) * Add fix to avoid exception on rows with no children by [@jeppevammenkristensen](https://github.com/jeppevammenkristensen) in [#1241](https://github.com/spectreconsole/spectre.console/pull/1241)
* Set `end_of_line` to `LF` instead of `CRLF` by [@0xced](https://github.com/0xced) in [#1256](https://github.com/spectreconsole/spectre.console/pull/1256) * Set `end_of_line` to `LF` instead of `CRLF` by [@0xced](https://github.com/0xced) in [#1256](https://github.com/spectreconsole/spectre.console/pull/1256)
* Fix `Rule` widget docs by [@tomaszprasolek](https://github.com/tomaszprasolek) in [#1257](https://github.com/spectreconsole/spectre.console/pull/1257) * Fix `Rule` widget docs by [@tomaszprasolek](https://github.com/tomaszprasolek) in [#1257](https://github.com/spectreconsole/spectre.console/pull/1257)
* Added the missing columns-cast by [@nils](https://github.com/nils)-a in [#1294](https://github.com/spectreconsole/spectre.console/pull/1294) * Added the missing columns-cast by [@nils](https://github.com/nils)-a in [#1294](https://github.com/spectreconsole/spectre.console/pull/1294)
@@ -46,7 +46,7 @@ New features have been added, such as the ability to show separators between tab
## CLI ## CLI
* Add async command unit tests by [@FrankRay78](https://github.com/FrankRay78) in [#1228](https://github.com/spectreconsole/spectre.console/pull/1228) * Add async command unit tests by [@FrankRay78](https://github.com/FrankRay78) in [#1228](https://github.com/spectreconsole/spectre.console/pull/1228)
* Add support for async delegate by [@icalvo](https://github.com/icalvo) in [#1215]([#1215](https://github.com/spectreconsole/spectre.console/pull/1215)) * Add support for async delegate by [@icalvo](https://github.com/icalvo) in [#1215](https://github.com/spectreconsole/spectre.console/pull/1215)
* Remove unnecessary `[NotNull]` attributes by [@0xced](https://github.com/0xced) in [#1255](https://github.com/spectreconsole/spectre.console/pull/1255) * Remove unnecessary `[NotNull]` attributes by [@0xced](https://github.com/0xced) in [#1255](https://github.com/spectreconsole/spectre.console/pull/1255)
* Allow custom help providers by [@FrankRay78](https://github.com/FrankRay78) in [#1259](https://github.com/spectreconsole/spectre.console/pull/1259) * Allow custom help providers by [@FrankRay78](https://github.com/FrankRay78) in [#1259](https://github.com/spectreconsole/spectre.console/pull/1259)
* Specified details for settings for the argument vector by [@nils](https://github.com/nils)-a in [#1301](https://github.com/spectreconsole/spectre.console/pull/1301) * Specified details for settings for the argument vector by [@nils](https://github.com/nils)-a in [#1301](https://github.com/spectreconsole/spectre.console/pull/1301)

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

@@ -0,0 +1,71 @@
Title: Spectre.Console 0.50 released!
Description: Now with 25% less lead!
Published: 2025-04-08
Category: Release Notes
Excluded: false
---
Version 0.50 of Spectre.Console has been released!
## New Contributors
* [@Kissaki](https://github.com/Kissaki) made their first contribution in [#1575](https://github.com/spectreconsole/spectre.console/pull/1575)
* [@z4ryy](https://github.com/z4ryy) made their first contribution in [#1590](https://github.com/spectreconsole/spectre.console/pull/1590)
* [@TonWin618](https://github.com/TonWin618) made their first contribution in [#1595](https://github.com/spectreconsole/spectre.console/pull/1595)
* [@KirillOsenkov](https://github.com/KirillOsenkov) made their first contribution in [#1623](https://github.com/spectreconsole/spectre.console/pull/1623)
* [@davide-pi](https://github.com/davide-pi) made their first contribution in [#1246](https://github.com/spectreconsole/spectre.console/pull/1246)
* [@armanossiloko](https://github.com/armanossiloko) made their first contribution in [#1668](https://github.com/spectreconsole/spectre.console/pull/1668)
* [@PascalSenn](https://github.com/PascalSenn) made their first contribution in [#1687](https://github.com/spectreconsole/spectre.console/pull/1687)
* [@tpill90](https://github.com/tpill90) made their first contribution in [#904](https://github.com/spectreconsole/spectre.console/pull/904)
* [@tmds](https://github.com/tmds) made their first contribution in [#1194](https://github.com/spectreconsole/spectre.console/pull/1194)
* [@TheMarteh](https://github.com/TheMarteh) made their first contribution in [#1708](https://github.com/spectreconsole/spectre.console/pull/1708)
* [@Tolitech](https://github.com/Tolitech) made their first contribution in [#1717](https://github.com/spectreconsole/spectre.console/pull/1717)
* [@TheTonttu](https://github.com/TheTonttu) made their first contribution in [#1740](https://github.com/spectreconsole/spectre.console/pull/1740)
* [@byte2pixel](https://github.com/byte2pixel) made their first contribution in [#1762](https://github.com/spectreconsole/spectre.console/pull/1762)
* [@Moustafaa91](https://github.com/Moustafaa91) made their first contribution in [#1779](https://github.com/spectreconsole/spectre.console/pull/1779)
### General
* Strong name the assemblies by [@KirillOsenkov](https://github.com/KirillOsenkov) in [#1623](https://github.com/spectreconsole/spectre.console/pull/1623)
* Update MSDN link to learn.microsoft.com by [@Kissaki](https://github.com/Kissaki) in [#1575](https://github.com/spectreconsole/spectre.console/pull/1575)
* Add spanish translation for help strings by [@kzu](https://github.com/kzu) in [#1597](https://github.com/spectreconsole/spectre.console/pull/1597)
* Update documentation: add example for the Text Prompt usage by [@davide-pi](https://github.com/davide-pi) in [#1636](https://github.com/spectreconsole/spectre.console/pull/1636)
* Fix typos xml docs by [@devlead](https://github.com/devlead) in [#1684](https://github.com/spectreconsole/spectre.console/pull/1684)
* Upgrade SixLabors.ImageSharp to 3.1.7 by [@Moustafaa91](https://github.com/Moustafaa91) in [#1779](https://github.com/spectreconsole/spectre.console/pull/1779)
### Console
* AOT Support for Spectre.Console by [@phil-scott-78](https://github.com/phil-scott-78) in [#1690](https://github.com/spectreconsole/spectre.console/pull/1690)
* Make method reference to Markup.Escape more obvious by [@Kissaki](https://github.com/Kissaki) in [#1574](https://github.com/spectreconsole/spectre.console/pull/1574)
* Fix `HtmlEncoder` Incorrectly Applying Italics to Bold Text by [@z4ryy](https://github.com/z4ryy) in [#1590](https://github.com/spectreconsole/spectre.console/pull/1590)
* Fix Console Display Issue with Deleting Wide Characters by [@TonWin618](https://github.com/TonWin618) in [#1595](https://github.com/spectreconsole/spectre.console/pull/1595)
* Fix search bug in prompt related to custom item types by [@patriksvensson](https://github.com/patriksvensson) in [#1627](https://github.com/spectreconsole/spectre.console/pull/1627)
* Cleanup the prompt tests by [@0xced](https://github.com/0xced) in [#1635](https://github.com/spectreconsole/spectre.console/pull/1635)
* Add custom style for each calendar event by [@davide-pi](https://github.com/davide-pi) in [#1246](https://github.com/spectreconsole/spectre.console/pull/1246)
* Fix tree expansion bug by [@davide-pi](https://github.com/davide-pi) in [#1245](https://github.com/spectreconsole/spectre.console/pull/1245)
* Enhance the style of the checkboxes for multi-selection by [@davide-pi](https://github.com/davide-pi) in [#1244](https://github.com/spectreconsole/spectre.console/pull/1244)
* Improve exception if a (multi)selection prompt is used incorrectly by [@0xced](https://github.com/0xced) in [#1637](https://github.com/spectreconsole/spectre.console/pull/1637)
* Fix incorrect panel height calculation in complex layout by [@BlazeFace](https://github.com/BlazeFace) in [#1514](https://github.com/spectreconsole/spectre.console/pull/1514)
* Adding Enricher for Azure Pipelines by [@BlazeFace](https://github.com/BlazeFace) in [#1675](https://github.com/spectreconsole/spectre.console/pull/1675)
* Added hex color conversion by [@jsheely](https://github.com/jsheely) in [#1432](https://github.com/spectreconsole/spectre.console/pull/1432)
* Fixed type in Segment description by [@PascalSenn](https://github.com/PascalSenn) in [#1687](https://github.com/spectreconsole/spectre.console/pull/1687)
* Adding TransferSpeedColumn configuration to display bits/bytes + binary/decimal prefixes by [@tpill90](https://github.com/tpill90) in [#904](https://github.com/spectreconsole/spectre.console/pull/904)
* Changes Emoji dictionary to OrdinalIgnoreCase for performance by [@phil-scott-78](https://github.com/phil-scott-78) in [#1691](https://github.com/spectreconsole/spectre.console/pull/1691)
* ProgressTask.GetPercentage() returns 100 when max value is 0 by [@FrankRay78](https://github.com/FrankRay78) in [#1694](https://github.com/spectreconsole/spectre.console/pull/1694)
* Async overloads for AnsiConsole Prompt/Ask/Confirm. by [@tmds](https://github.com/tmds) in [#1194](https://github.com/spectreconsole/spectre.console/pull/1194)
* Support 3-digit hex codes in markup by [@TheMarteh](https://github.com/TheMarteh) in [#1708](https://github.com/spectreconsole/spectre.console/pull/1708)
* Add async spinner extension methods and related documentation by [@phil-scott-78](https://github.com/phil-scott-78) in [#1747](https://github.com/spectreconsole/spectre.console/pull/1747)
* Fix generic exception formatting by [@0xced](https://github.com/0xced) in [#1755](https://github.com/spectreconsole/spectre.console/pull/1755)
### CLI
* Remove redundant explain settings ctor by [@gitfool](https://github.com/gitfool) in [#1534](https://github.com/spectreconsole/spectre.console/pull/1534)
* Trim trailing comma in settings by [@devlead](https://github.com/devlead) in [#1550](https://github.com/spectreconsole/spectre.console/pull/1550)
* Consider -? as an alias to -h by [@kzu](https://github.com/kzu) in [#1552](https://github.com/spectreconsole/spectre.console/pull/1552)
* Trimming of TestConsole output by CommandAppTester is user configurable. by [@FrankRay78](https://github.com/FrankRay78) in [#1739](https://github.com/spectreconsole/spectre.console/pull/1739)
* Include resource files for additional cultures in HelpProvider. by [@Tolitech](https://github.com/Tolitech) in [#1717](https://github.com/spectreconsole/spectre.console/pull/1717)
* Conditionally trim trailing periods of argument and option descriptions by [@TheTonttu](https://github.com/TheTonttu) in [#1740](https://github.com/spectreconsole/spectre.console/pull/1740)
* Changed IConfigurator to return IConfigurator instead of void by [@byte2pixel](https://github.com/byte2pixel) in [#1762](https://github.com/spectreconsole/spectre.console/pull/1762)
* Add parsed unknown flag to remaining arguments for a branch with a default command by [@FrankRay78](https://github.com/FrankRay78) in [#1660](https://github.com/spectreconsole/spectre.console/pull/1660)
* Correctly show application version; execution of command with version option by [@FrankRay78](https://github.com/FrankRay78) in [#1663](https://github.com/spectreconsole/spectre.console/pull/1663)
* Help output correctly decides when to show the version option by [@FrankRay78](https://github.com/FrankRay78) in [#1664](https://github.com/spectreconsole/spectre.console/pull/1664)

View File

@@ -0,0 +1,43 @@
Title: Spectre.Console 0.51.1 released!
Description: Not a substitute for human interaction.
Published: 2025-09-07
Category: Release Notes
Excluded: false
---
Version `0.51.1` of Spectre.Console has been released!
_Note: Due to an issue discovered after the release of version 0.51.0, that version has now been unlisted. Lets all pretend it never existed 😅_
## What's Changed
* Fix IndexOutOfRangeException in ExceptionFormatter by [@martincostello](https://github.com/martincostello) in [#1800](https://github.com/spectreconsole/spectre.console/pull/1800)
* TestConsole can now be configured and accessed in CommandAppTester by [@magiino](https://github.com/magiino) in [#1803](https://github.com/spectreconsole/spectre.console/pull/1803)
* Add ShowRowSeparators in Table Widget docs by [@bartoginski](https://github.com/bartoginski) in [#1807](https://github.com/spectreconsole/spectre.console/pull/1807)
* Add support for required options by [@patriksvensson](https://github.com/patriksvensson) in [#1825](https://github.com/spectreconsole/spectre.console/pull/1825)
* Added documentation for align widget by [@Elementttto](https://github.com/Elementttto) in [#1746](https://github.com/spectreconsole/spectre.console/pull/1746)
* Fixed link not displayed in markup in Style.cs and added unit test cases by [@Elementttto](https://github.com/Elementttto) in [#1750](https://github.com/spectreconsole/spectre.console/pull/1750)
* Update System.Memory dependency by [@WeihanLi](https://github.com/WeihanLi) in [#1832](https://github.com/spectreconsole/spectre.console/pull/1832)
* Reduce memory usage for rune width cache. by [@Pannoniae](https://github.com/Pannoniae) in [#1756](https://github.com/spectreconsole/spectre.console/pull/1756)
* Fix resizing of Live views with reduced size. by [@belucha](https://github.com/belucha) in [#1840](https://github.com/spectreconsole/spectre.console/pull/1840)
* Corrects comment for optional text prompt by [@aljanabim](https://github.com/aljanabim) in [#1857](https://github.com/spectreconsole/spectre.console/pull/1857)
* Update spinners by [@FroggieFrog](https://github.com/FroggieFrog) in [#1873](https://github.com/spectreconsole/spectre.console/pull/1873)
* Support J and K for navigating list prompts by [@tobias-tengler](https://github.com/tobias-tengler) in [#1877](https://github.com/spectreconsole/spectre.console/pull/1877)
* Fix space triggering selection when items in the selection list have a space. by [@mitchdenny](https://github.com/mitchdenny) in [#1881](https://github.com/spectreconsole/spectre.console/pull/1881)
* Fix bug setting Header by [@mattfennerom](https://github.com/mattfennerom) in [#1890](https://github.com/spectreconsole/spectre.console/pull/1890)
## New Contributors
* [@magiino](https://github.com/magiino) made their first contribution in [#1803](https://github.com/spectreconsole/spectre.console/pull/1803)
* [@bartoginski](https://github.com/bartoginski) made their first contribution in [#1807](https://github.com/spectreconsole/spectre.console/pull/1807)
* [@Elementttto](https://github.com/Elementttto) made their first contribution in [#1746](https://github.com/spectreconsole/spectre.console/pull/1746)
* [@WeihanLi](https://github.com/WeihanLi) made their first contribution in [#1832](https://github.com/spectreconsole/spectre.console/pull/1832)
* [@Pannoniae](https://github.com/Pannoniae) made their first contribution in [#1756](https://github.com/spectreconsole/spectre.console/pull/1756)
* [@belucha](https://github.com/belucha) made their first contribution in [#1840](https://github.com/spectreconsole/spectre.console/pull/1840)
* [@aljanabim](https://github.com/aljanabim) made their first contribution in [#1857](https://github.com/spectreconsole/spectre.console/pull/1857)
* [@FroggieFrog](https://github.com/FroggieFrog) made their first contribution in [#1873](https://github.com/spectreconsole/spectre.console/pull/1873)
* [@tobias-tengler](https://github.com/tobias-tengler) made their first contribution in [#1877](https://github.com/spectreconsole/spectre.console/pull/1877)
* [@mitchdenny](https://github.com/mitchdenny) made their first contribution in [#1881](https://github.com/spectreconsole/spectre.console/pull/1881)
* [@mattfennerom](https://github.com/mattfennerom) made their first contribution in [#1890](https://github.com/spectreconsole/spectre.console/pull/1890)
**Full Changelog**: [0.50.0...0.51.0](https://github.com/spectreconsole/spectre.console/compare/0.50.0...0.51.1)

View File

@@ -0,0 +1,17 @@
Title: Spectre.Console 0.52.0 released!
Description: Don't eat (too much) glue.
Published: 2025-10-10
Category: Release Notes
Excluded: false
---
Version `0.52.0` of Spectre.Console has been released!
Exciting things are happening. Weve merged support for my love child, OpenCli, in this release. That means you can now pass the parameter `--help-dump-opencli` to your application to get an [OpenCli](https://opencli.org) description dumped to stdout.
## What's Changed
* Add OpenCLI integration to Spectre.Console.Cli by [@patriksvensson](https://github.com/patriksvensson) in [#1909](https://github.com/spectreconsole/spectre.console/pull/1909)
* Fix OPENCLI_VISIBILITY_INTERNAL to DefineConstants concat by [@devlead](https://github.com/devlead) in [#1912](https://github.com/spectreconsole/spectre.console/pull/1912)
**Full Changelog**: https://github.com/spectreconsole/spectre.console/compare/0.51.1...0.52.0

View File

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

View File

@@ -41,7 +41,7 @@ Removing all styling from help text is also possible, a good choice for ensuring
config.Settings.HelpProviderStyles = null; config.Settings.HelpProviderStyles = null;
``` ```
See [Markup](../markup) for information about the use of markup in Spectre.Console, and [Styles](xref:styles) for a listing of supported styles. See [Markup](../markup) for information about the use of markup in Spectre.Console, and [Styles](xref:appendix-styles) for a listing of supported styles.
## Custom help providers ## Custom help providers
@@ -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

@@ -67,7 +67,7 @@ registrations.AddSingleton<IGreeter, HelloWorldGreeter>();
// Create a type registrar and register any dependencies. // Create a type registrar and register any dependencies.
// A type registrar is an adapter for a DI framework. // A type registrar is an adapter for a DI framework.
var registrar = new TypeRegistrar(registrations); var registrar = new MyTypeRegistrar(registrations);
// Create a new command app with the registrar // Create a new command app with the registrar
// and run it with the provided arguments. // and run it with the provided arguments.
@@ -75,10 +75,13 @@ 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. <?# Alert ?>
`MyTypeRegistrar` is a custom class that implements [ITypeRegistrar](xref:T:Spectre.Console.Cli.ITypeRegistrar) and must be provided by the user.
<?#/ Alert ?>
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 working [example of dependency injection](https://github.com/spectreconsole/examples/tree/main/examples/Cli/Injection) that uses `Microsoft.Extensions.DependencyInjection` as the container. Example implementations of `ITypeRegistrar` and `ITypeResolver` are provided, which you can copy and paste to your application for dependency injection.
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.
Unit testing your `ITypeRegistrar` and `ITypeResolver` implementations is done using the utility `TypeRegistrarBaseTests` included in `Spectre.Console.Testing`. Simply call `TypeRegistrarBaseTests.RunAllTests()` and expect no `TypeRegistrarBaseTests.TestFailedException` to be thrown.
## Interception ## Interception
Interceptors can be registered with the `TypeRegistrar` (or with a custom DI-Container). Alternatively, `CommandApp` also provides a `SetInterceptor` configuration. Interceptors can be registered with the `TypeRegistrar` (or with a custom DI-Container). Alternatively, `CommandApp` also provides a `SetInterceptor` configuration.
@@ -89,4 +92,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

@@ -1,8 +1,8 @@
Title: Composing Commands Title: Composing Commands
RedirectFrom: introduction RedirectFrom: introduction
Order: 8 Order: 8
Description: "The underlying philosophy behind *Spectre.Console.Cli* is to rely on the .NET type system to Description: The underlying philosophy behind *Spectre.Console.Cli* is
declare the commands, but tie everything together via composition." to rely on the .NET type system to declare the commands, but tie everything together via composition.
--- ---
The underlying philosophy behind `Spectre.Console.Cli` is to rely on the .NET type system to The underlying philosophy behind `Spectre.Console.Cli` is to rely on the .NET type system to

View File

@@ -1,8 +1,8 @@
Title: Introduction Title: Introduction
Order: 1 Order: 1
Description: "*Spectre.Console.Cli* is a modern library for parsing command line arguments. While it's extremely Description: "*Spectre.Console.Cli* is a modern library for parsing command line arguments. While it's extremely
opinionated in what it does, it tries to follow established industry conventions, and draws opinionated in what it does, it tries to follow established industry conventions, and draws
its inspiration from applications you use everyday." its inspiration from applications you use everyday."
--- ---
`Spectre.Console.Cli` is a modern library for parsing command line arguments. While it's extremely `Spectre.Console.Cli` is a modern library for parsing command line arguments. While it's extremely

22
docs/input/cli/opencli.md Normal file
View File

@@ -0,0 +1,22 @@
Title: OpenCLI Integration
Order: 15
Description: OpenCLI integration
Highlights:
- Generate OpenCLI descriptions
---
From version `0.52.0` and above, you will be able to generate [OpenCLI](https://opencli.org)
descriptions from your `Spectre.Console.Cli` applications.
Simply add the `--help-dump-opencli` option to your application, and an
OpenCLI description will be written to stdout.
```shell
$ ./myapp --help-dump-opencli
```
If you want to save it to disk, pipe it to a file.
```shell
$ ./myapp --help-dump-opencli > myapp.openapi.json
```

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

@@ -0,0 +1,199 @@
Title: Unit Testing
Order: 14
Description: Instructions for unit testing a Spectre.Console application.
Reference:
- T:Spectre.Console.Testing.CommandAppTester
- T:Spectre.Console.Testing.TestConsole
- T:Spectre.Console.Testing.TestConsoleInput
---
`Spectre.Console` has a separate project that contains test harnesses for unit testing your own console applications.
The fastest way of getting started is to install the `Spectre.Console.Testing` NuGet package.
```text
> dotnet add package Spectre.Console.Testing
```
`Spectre.Console.Testing` is also the namespace containing the test classes.
## Testing a CommandApp
The `CommandAppTester` is a test implementation of `CommandApp` that's configured in a similar manner but designed for unit testing.
The following example validates the exit code and terminal output of a `Spectre.Console` command:
```csharp
/// <summary>
/// A Spectre.Console Command
/// </summary>
public class HelloWorldCommand : Command
{
private readonly IAnsiConsole _console;
public HelloWorldCommand(IAnsiConsole console)
{
// nb. AnsiConsole should not be called directly by the command
// since this doesn't play well with testing. Instead,
// the command should inject a IAnsiConsole and use that.
_console = console;
}
public override int Execute(CommandContext context)
{
_console.WriteLine("Hello world.");
return 0;
}
}
[TestMethod]
public void Should_Output_Hello_World()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<HelloWorldCommand>();
// When
var result = app.Run();
// Then
Assert.AreEqual(result.ExitCode, 0);
Assert.AreEqual(result.Output, "Hello world.");
}
```
The following example demonstrates how to mock user inputs for an interactive command.
This test (InteractiveCommand_WithMockedUserInputs_ProducesExpectedOutput) simulates user interactions by pushing predefined inputs to the console, then verifies that the resulting output is as expected.
```csharp
public sealed class InteractiveCommandTests
{
private sealed class InteractiveCommand : Command
{
private readonly IAnsiConsole _console;
public InteractiveCommand(IAnsiConsole console)
{
_console = console;
}
public override int Execute(CommandContext context)
{
var fruits = _console.Prompt(
new MultiSelectionPrompt<string>()
.Title("What are your [green]favorite fruits[/]?")
.NotRequired() // Not required to have a favorite fruit
.PageSize(10)
.MoreChoicesText("[grey](Move up and down to reveal more fruits)[/]")
.InstructionsText(
"[grey](Press [blue]<space>[/] to toggle a fruit, " +
"[green]<enter>[/] to accept)[/]")
.AddChoices(new[] {
"Apple", "Apricot", "Avocado",
"Banana", "Blackcurrant", "Blueberry",
"Cherry", "Cloudberry", "Coconut",
}));
var fruit = _console.Prompt(
new SelectionPrompt<string>()
.Title("What's your [green]favorite fruit[/]?")
.PageSize(10)
.MoreChoicesText("[grey](Move up and down to reveal more fruits)[/]")
.AddChoices(new[] {
"Apple", "Apricot", "Avocado",
"Banana", "Blackcurrant", "Blueberry",
"Cherry", "Cloudberry", "Cocunut",
}));
var name = _console.Ask<string>("What's your name?");
_console.WriteLine($"[{string.Join(',', fruits)};{fruit};{name}]");
return 0;
}
}
[Fact]
public void InteractiveCommand_WithMockedUserInputs_ProducesExpectedOutput()
{
// Given
TestConsole console = new();
console.Interactive();
// Your mocked inputs must always end with "Enter" for each prompt!
// Multi selection prompt: Choose first option
console.Input.PushKey(ConsoleKey.Spacebar);
console.Input.PushKey(ConsoleKey.Enter);
// Selection prompt: Choose second option
console.Input.PushKey(ConsoleKey.DownArrow);
console.Input.PushKey(ConsoleKey.Enter);
// Ask text prompt: Enter name
console.Input.PushTextWithEnter("Spectre Console");
var app = new CommandAppTester(null, new CommandAppTesterSettings(), console);
app.SetDefaultCommand<InteractiveCommand>();
// When
var result = app.Run();
// Then
result.ExitCode.ShouldBe(0);
result.Output.EndsWith("[Apple;Apricot;Spectre Console]");
}
}
```
## Testing console behaviour
`TestConsole` and `TestConsoleInput` are testable implementations of `IAnsiConsole` and `IAnsiConsoleInput`, allowing you fine-grain control over testing console output and interactivity.
The following example renders some widgets before then validating the console output:
```csharp
[TestMethod]
public void Should_Render_Panel()
{
// Given
var console = new TestConsole();
// When
console.Write(new Panel(new Text("Hello World")));
// Then
Assert.AreEqual(console.Output, """"
┌─────────────┐
Hello World
└─────────────┘
"""");
}
```
While `Assert` is fine for validating simple output, more complex output may benefit from a tool like [Verify](https://github.com/VerifyTests/Verify).
The following example prompts the user for input before then validating the expected choice was made:
```csharp
[TestMethod]
public void Should_Select_Orange()
{
// Given
var console = new TestConsole();
console.Input.PushTextWithEnter("Orange");
// When
console.Prompt(
new TextPrompt<string>("Favorite fruit?")
.AddChoice("Banana")
.AddChoice("Orange"));
// Then
Assert.AreEqual(console.Output, "Favorite fruit? [Banana/Orange]: Orange\n");
}
```
`CommandAppTester` uses `TestConsole` internally, which in turn uses `TestConsoleInput`, offering a fully testable harness for `Spectre.Console` widgets, prompts and commands.

View File

@@ -6,7 +6,7 @@ Order: 0
Spectre.Console is a `.NET` library that makes it easier Spectre.Console is a `.NET` library that makes it easier
to create beautiful console applications. to create beautiful console applications.
## Spectre.Console.AnsiConsole Features ## Spectre.Console.AnsiConsole
* Easily output text with different colors and even styles such as bold, italic and blinking with a Rich inspired [markup language](markup). * Easily output text with different colors and even styles such as bold, italic and blinking with a Rich inspired [markup language](markup).
* Supports `3`/`4`/`8`/`24`-bit colors in the terminal with auto-detection of the current terminal's capabilities. * Supports `3`/`4`/`8`/`24`-bit colors in the terminal with auto-detection of the current terminal's capabilities.
@@ -14,16 +14,19 @@ to create beautiful console applications.
* Display progress for long running tasks with live displays of [progress](live/progress) and [status](live/status) controls. * Display progress for long running tasks with live displays of [progress](live/progress) and [status](live/status) controls.
* Prompt user input with strongly typed [text input](prompts/text) or via [single-item select](prompts/selection) and [multiple item select](prompts/multiselection) controls. * Prompt user input with strongly typed [text input](prompts/text) or via [single-item select](prompts/selection) and [multiple item select](prompts/multiselection) controls.
* Format .NET [exceptions](exceptions) with custom color coded themes and styles. * Format .NET [exceptions](exceptions) with custom color coded themes and styles.
* Written with unit testing in mind.
Spectre.Console.AnsiConsole has been heavily inspired Spectre.Console.AnsiConsole has been heavily inspired by the excellent [Rich](https://github.com/willmcgugan/rich) library for Python written by Will McGugan.
by the excellent [Rich](https://github.com/willmcgugan/rich) library
for Python written by Will McGugan.
## Spectre.Console.Cli ## Spectre.Console.Cli
* Create strongly typed settings and commands for parsing `args[]` to create complex command line applications like `git`, `gh`, or `dotnet` * Create strongly typed settings and commands for parsing `args[]` to create complex command line applications like `git`, `gh`, or `dotnet`
## Spectre.Console.Testing
* Spectre.Console has been developed with unit testing in mind. The Spectre.Console library itself is covered by an extensive test suite, project maintainers require test coverage for all new commits, and the same extension points and test harnesses used internally for testing are available to you.
* The [Unit Testing](cli/unit-testing) page provides instructions for testing a Spectre.Console application.
## Examples ## Examples
![Sample of Spectre.Console output](./assets/images/example.png) ![Sample of Spectre.Console output](./assets/images/example.png)
@@ -36,3 +39,4 @@ for Python written by Will McGugan.
Sorry, your browser doesn't support embedded videos. Sorry, your browser doesn't support embedded videos.
</video> </video>
The Spectre.Console [examples repository](https://github.com/spectreconsole/examples) contains many other examples.

73
docs/input/live/async.md Normal file
View File

@@ -0,0 +1,73 @@
Title: Async Extensions
Order: 11
Description: "Async Extensions provides extension methods for running tasks with an inline animations."
Highlights:
- Extension methods for running tasks with spinner animations
- Support for both void and generic Task types
- Customizable spinner styles and console output
Reference:
- T:Spectre.Console.Extensions.SpinnerExtensions
Xref: spinner-extensions
---
The Async Spinner Extension provides convenient extension methods for running tasks with an inline spinner animations in the console.
<?# AsciiCast cast="await-spinner" /?>
<?# Alert ?>
The spinner animation is not thread safe, and using it together with other interactive
components such as prompts, progress displays or other status displays is not supported.
<?#/ Alert ?>
## Usage
The extension methods allow you to easily add spinner animations to any Task execution:
```csharp
// Basic usage with void Task
await someTask.Spinner();
// With generic Task<T>
var result = await someTaskWithResult.Spinner(
Spinner.Known.Star,
new Style(foreground: Color.Green));
// With custom console
await someTask.Spinner(
Spinner.Known.Dots,
style: Style.Plain,
ansiConsole: customConsole);
```
## Features
The spinner extensions provide:
- Support for both void Tasks and Tasks with return values
- Customizable spinner animations using any Spectre.Console Spinner
- Optional styling for the spinner animation
- Ability to specify a custom IAnsiConsole instance
## Examples
Here's a more complete example showing different ways to use the spinner extensions:
```csharp
// Basic spinner with default settings
await Task.Delay(1000)
.Spinner(Spinner.Known.Dots);
// Customized spinner with style
var result = await CalculateSomething()
.Spinner(
Spinner.Known.Star,
new Style(foreground: Color.Green));
// Using with a custom console
await ProcessData()
.Spinner(
new Spinner(new[] { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" }, 80),
new Style(foreground: Color.Blue),
customConsole);
```

View File

@@ -9,6 +9,7 @@ Highlights:
Reference: Reference:
- T:Spectre.Console.Progress - T:Spectre.Console.Progress
- M:Spectre.Console.AnsiConsole.Progress - M:Spectre.Console.AnsiConsole.Progress
Xref: live-progress
--- ---
Spectre.Console can display information about long running tasks in the console. Spectre.Console can display information about long running tasks in the console.
@@ -85,6 +86,8 @@ AnsiConsole.Progress()
new PercentageColumn(), // Percentage new PercentageColumn(), // Percentage
new RemainingTimeColumn(), // Remaining time new RemainingTimeColumn(), // Remaining time
new SpinnerColumn(), // Spinner new SpinnerColumn(), // Spinner
new DownloadedColumn(), // Downloaded
new TransferSpeedColumn(), // Transfer speed
}) })
.Start(ctx => .Start(ctx =>
{ {

View File

@@ -8,6 +8,7 @@ Highlights:
Reference: Reference:
- T:Spectre.Console.Status - T:Spectre.Console.Status
- M:Spectre.Console.AnsiConsole.Status - M:Spectre.Console.AnsiConsole.Status
Xref: live-status
--- ---
Spectre.Console can display information about long running tasks in the console. Spectre.Console can display information about long running tasks in the console.

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 for the user's favorite color (optional)
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

@@ -17,7 +17,7 @@ and the ascii terminal player.
/* temp styling for alerts */ /* temp styling for alerts */
.alert-warning { .alert-warning {
@apply p-4 border border-yellow-300 bg-yellow-100 text-yellow-800 dark:border-orange-700/50 dark:bg-orange-800/50 dark:text-orange-300/90 rounded shadow-sm text-sm; @apply p-4 border border-yellow-300 bg-yellow-100 text-yellow-800 dark:border-red-700/50 dark:bg-red-800/50 dark:text-red-100/90 rounded shadow-sm text-sm;
} }
.alert-warning p { .alert-warning p {

View File

@@ -0,0 +1,66 @@
Title: Align
Description: "Use **Align** to render and position widgets in the console."
Highlights:
- Custom colors
- Labels
- Use your own data with a converter.
Reference: T:Spectre.Console.Align
---
Use `Align` to render and position widgets in the console.
<?# AsciiCast cast="align" /?>
## Usage
### Basic usage
```csharp
// Render an item and align it in the bottom-left corner of the console
AnsiConsole.Write(new Align(
new Text("Spectre!"),
HorizontalAlignment.Left,
VerticalAlignment.Bottom
));
```
### Align items from an IEnumerable
```csharp
// Create a list of items
var alignItems = new List<Text>(){
new Text("Spectre"),
new Text("Console"),
new Text("Is Awesome!")
};
// Render the items in the middle-right of the console
AnsiConsole.Write(new Align(
alignItems,
HorizontalAlignment.Right,
VerticalAlignment.Middle
));
```
### Dynamically align with different widgets
```csharp
// Create a table
var table = new Table()
.AddColumn("ID")
.AddColumn("Methods")
.AddColumn("Purpose")
.AddRow("1", "Center()", "Initializes a new instance that is center aligned")
.AddRow("2", "Measure()", "Measures the renderable object")
.AddRow("3", "Right()", "Initializes a new instance that is right aligned.");
// Create a panel
var panel = new Panel(table)
.Header("Other Align Methods")
.Border(BoxBorder.Double);
// Renders the panel in the top-center of the console
AnsiConsole.Write(new Align(panel, HorizontalAlignment.Center, VerticalAlignment.Top));
```

View File

@@ -137,4 +137,11 @@ table.Columns[0].NoWrap();
```csharp ```csharp
// Set the column width // Set the column width
table.Columns[0].Width(15); table.Columns[0].Width(15);
```
### Show row separators
```csharp
// Shows separator between each row
table.ShowRowSeparators();
``` ```

282
docs/package-lock.json generated
View File

@@ -123,12 +123,13 @@
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.17.0", "version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
"integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==", "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.14.0"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -315,12 +316,13 @@
} }
}, },
"node_modules/braces": { "node_modules/braces": {
"version": "3.0.2", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"fill-range": "^7.0.1" "fill-range": "^7.1.1"
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@@ -475,10 +477,11 @@
} }
}, },
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.3", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"path-key": "^3.1.0", "path-key": "^3.1.0",
"shebang-command": "^2.0.0", "shebang-command": "^2.0.0",
@@ -500,6 +503,13 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"dev": true,
"license": "MIT"
},
"node_modules/defined": { "node_modules/defined": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
@@ -587,10 +597,11 @@
} }
}, },
"node_modules/fill-range": { "node_modules/fill-range": {
"version": "7.0.1", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"to-regex-range": "^5.0.1" "to-regex-range": "^5.0.1"
}, },
@@ -737,6 +748,7 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=0.12.0" "node": ">=0.12.0"
} }
@@ -802,13 +814,14 @@
} }
}, },
"node_modules/micromatch": { "node_modules/micromatch": {
"version": "4.0.4", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"braces": "^3.0.1", "braces": "^3.0.3",
"picomatch": "^2.2.3" "picomatch": "^2.3.1"
}, },
"engines": { "engines": {
"node": ">=8.6" "node": ">=8.6"
@@ -824,16 +837,27 @@
} }
}, },
"node_modules/minimist": { "node_modules/minimist": {
"version": "1.2.5", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.2.0", "version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"dev": true, "dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"bin": { "bin": {
"nanoid": "bin/nanoid.cjs" "nanoid": "bin/nanoid.cjs"
}, },
@@ -931,10 +955,11 @@
} }
}, },
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.0.0", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true "dev": true,
"license": "ISC"
}, },
"node_modules/picomatch": { "node_modules/picomatch": {
"version": "2.3.1", "version": "2.3.1",
@@ -949,21 +974,32 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.6", "version": "8.5.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
"integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
"dev": true, "dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": { "dependencies": {
"nanoid": "^3.2.0", "nanoid": "^3.3.8",
"picocolors": "^1.0.0", "picocolors": "^1.1.1",
"source-map-js": "^1.0.2" "source-map-js": "^1.2.1"
}, },
"engines": { "engines": {
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
} }
}, },
"node_modules/postcss-js": { "node_modules/postcss-js": {
@@ -1093,10 +1129,11 @@
} }
}, },
"node_modules/regenerator-runtime": { "node_modules/regenerator-runtime": {
"version": "0.13.9", "version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/resolve": { "node_modules/resolve": {
"version": "1.22.0", "version": "1.22.0",
@@ -1157,6 +1194,29 @@
"queue-microtask": "^1.2.2" "queue-microtask": "^1.2.2"
} }
}, },
"node_modules/seroval": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/seroval/-/seroval-1.2.1.tgz",
"integrity": "sha512-yBxFFs3zmkvKNmR0pFSU//rIsYjuX418TnlDmc2weaq5XFDqDIV/NOMPBoLrbxjLH42p4UzRuXHryXh9dYcKcw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/seroval-plugins": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.2.1.tgz",
"integrity": "sha512-H5vs53+39+x4Udwp4J5rNZfgFuA+Lt+uU+09w1gYBVWomtAl98B+E9w7yC05Xc81/HgLvJdlyqJbU0fJCKCmdw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
},
"peerDependencies": {
"seroval": "^1.0"
}
},
"node_modules/shebang-command": { "node_modules/shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -1179,16 +1239,23 @@
} }
}, },
"node_modules/solid-js": { "node_modules/solid-js": {
"version": "1.3.5", "version": "1.9.5",
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.3.5.tgz", "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.5.tgz",
"integrity": "sha512-PUom2cCARfvvgxI7cwOhfXMrZZZxjp+vIrb5fzVNBFyICy8A30wTqExwfUv457eJYgKpii2D3qStW9ILtKnShw==", "integrity": "sha512-ogI3DaFcyn6UhYhrgcyRAMbu/buBJitYQASZz5WzfQVPP10RD2AbCoRZ517psnezrasyCbWzIxZ6kVqet768xw==",
"dev": true "dev": true,
"license": "MIT",
"dependencies": {
"csstype": "^3.1.0",
"seroval": "^1.1.0",
"seroval-plugins": "^1.1.0"
}
}, },
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.0.2", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true, "dev": true,
"license": "BSD-3-Clause",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -1274,6 +1341,7 @@
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"is-number": "^7.0.0" "is-number": "^7.0.0"
}, },
@@ -1407,12 +1475,12 @@
} }
}, },
"@babel/runtime": { "@babel/runtime": {
"version": "7.17.0", "version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
"integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==", "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
"dev": true, "dev": true,
"requires": { "requires": {
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.14.0"
} }
}, },
"@nodelib/fs.scandir": { "@nodelib/fs.scandir": {
@@ -1547,12 +1615,12 @@
"dev": true "dev": true
}, },
"braces": { "braces": {
"version": "3.0.2", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true, "dev": true,
"requires": { "requires": {
"fill-range": "^7.0.1" "fill-range": "^7.1.1"
} }
}, },
"browserslist": { "browserslist": {
@@ -1652,9 +1720,9 @@
} }
}, },
"cross-spawn": { "cross-spawn": {
"version": "7.0.3", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true, "dev": true,
"requires": { "requires": {
"path-key": "^3.1.0", "path-key": "^3.1.0",
@@ -1668,6 +1736,12 @@
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true "dev": true
}, },
"csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"dev": true
},
"defined": { "defined": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
@@ -1743,9 +1817,9 @@
} }
}, },
"fill-range": { "fill-range": {
"version": "7.0.1", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true, "dev": true,
"requires": { "requires": {
"to-regex-range": "^5.0.1" "to-regex-range": "^5.0.1"
@@ -1905,13 +1979,13 @@
"dev": true "dev": true
}, },
"micromatch": { "micromatch": {
"version": "4.0.4", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true, "dev": true,
"requires": { "requires": {
"braces": "^3.0.1", "braces": "^3.0.3",
"picomatch": "^2.2.3" "picomatch": "^2.3.1"
} }
}, },
"mini-svg-data-uri": { "mini-svg-data-uri": {
@@ -1921,15 +1995,15 @@
"dev": true "dev": true
}, },
"minimist": { "minimist": {
"version": "1.2.5", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true "dev": true
}, },
"nanoid": { "nanoid": {
"version": "3.2.0", "version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"dev": true "dev": true
}, },
"node-releases": { "node-releases": {
@@ -1998,9 +2072,9 @@
"dev": true "dev": true
}, },
"picocolors": { "picocolors": {
"version": "1.0.0", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true "dev": true
}, },
"picomatch": { "picomatch": {
@@ -2010,14 +2084,14 @@
"dev": true "dev": true
}, },
"postcss": { "postcss": {
"version": "8.4.6", "version": "8.5.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
"integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
"dev": true, "dev": true,
"requires": { "requires": {
"nanoid": "^3.2.0", "nanoid": "^3.3.8",
"picocolors": "^1.0.0", "picocolors": "^1.1.1",
"source-map-js": "^1.0.2" "source-map-js": "^1.2.1"
} }
}, },
"postcss-js": { "postcss-js": {
@@ -2086,9 +2160,9 @@
} }
}, },
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.13.9", "version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"dev": true "dev": true
}, },
"resolve": { "resolve": {
@@ -2123,6 +2197,19 @@
"queue-microtask": "^1.2.2" "queue-microtask": "^1.2.2"
} }
}, },
"seroval": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/seroval/-/seroval-1.2.1.tgz",
"integrity": "sha512-yBxFFs3zmkvKNmR0pFSU//rIsYjuX418TnlDmc2weaq5XFDqDIV/NOMPBoLrbxjLH42p4UzRuXHryXh9dYcKcw==",
"dev": true
},
"seroval-plugins": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.2.1.tgz",
"integrity": "sha512-H5vs53+39+x4Udwp4J5rNZfgFuA+Lt+uU+09w1gYBVWomtAl98B+E9w7yC05Xc81/HgLvJdlyqJbU0fJCKCmdw==",
"dev": true,
"requires": {}
},
"shebang-command": { "shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -2139,15 +2226,20 @@
"dev": true "dev": true
}, },
"solid-js": { "solid-js": {
"version": "1.3.5", "version": "1.9.5",
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.3.5.tgz", "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.5.tgz",
"integrity": "sha512-PUom2cCARfvvgxI7cwOhfXMrZZZxjp+vIrb5fzVNBFyICy8A30wTqExwfUv457eJYgKpii2D3qStW9ILtKnShw==", "integrity": "sha512-ogI3DaFcyn6UhYhrgcyRAMbu/buBJitYQASZz5WzfQVPP10RD2AbCoRZ517psnezrasyCbWzIxZ6kVqet768xw==",
"dev": true "dev": true,
"requires": {
"csstype": "^3.1.0",
"seroval": "^1.1.0",
"seroval-plugins": "^1.1.0"
}
}, },
"source-map-js": { "source-map-js": {
"version": "1.0.2", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true "dev": true
}, },
"supports-color": { "supports-color": {

View File

@@ -99,8 +99,7 @@ public class Api : Pipeline
new ConcatDocuments(nameof(Code)), new ConcatDocuments(nameof(Code)),
new CacheDocuments( new CacheDocuments(
new AnalyzeCSharp() new AnalyzeCSharp()
.WhereNamespaces(ns => ns.StartsWith("Spectre.Console") && !ns.Contains("Analyzer") && .WhereNamespaces(ns => ns.StartsWith("Spectre.Console") && !ns.Contains("Analyzer") && !ns.Contains("Examples"))
!ns.Contains("Testing") && !ns.Contains("Examples"))
.WherePublic(true) .WherePublic(true)
.WithCssClasses("code", "cs") .WithCssClasses("code", "cs")
.WithDestinationPrefix("api") .WithDestinationPrefix("api")

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 9.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

@@ -58,21 +58,31 @@ internal static class HighlightService
} }
var text = await syntaxReference.SyntaxTree.GetTextAsync(); var text = await syntaxReference.SyntaxTree.GetTextAsync();
// we need a workspace, but it seems it is only used to resolve a few services and nothing else so an empty one will suffice
return HighlightElement(_emptyWorkspace, model, text, textSpan, indent); // we need a document for the syntax highlighter, so create a temporary solution and project to hold it.
var workspace = new AdhocWorkspace();
var solution = workspace.CurrentSolution
.AddProject("TempProject", "TempProject", "C#")
.AddDocument("TempDocument", await syntaxReference.SyntaxTree.GetTextAsync());
var document = solution.Project.Documents.First();
var highlightElement = await HighlightElement(document, text, textSpan, indent);
return highlightElement;
} }
private static int GetIndent(SyntaxTriviaList leadingTrivia) private static int GetIndent(SyntaxTriviaList leadingTrivia)
{ {
var whitespace = leadingTrivia.FirstOrDefault(i => i.Kind() == SyntaxKind.WhitespaceTrivia); var whitespace = leadingTrivia.FirstOrDefault(i => i.IsKind(SyntaxKind.WhitespaceTrivia));
return whitespace == default ? 0 : whitespace.Span.Length; return whitespace == default ? 0 : whitespace.Span.Length;
} }
private static string HighlightElement(Workspace workspace, SemanticModel semanticModel, SourceText fullSourceText, private static async Task<string> HighlightElement(Document document,
SourceText fullSourceText,
TextSpan textSpan, int indent) TextSpan textSpan, int indent)
{ {
var classifiedSpans = Classifier.GetClassifiedSpans(semanticModel, textSpan, workspace); var classifiedSpans = await Classifier.GetClassifiedSpansAsync(document, textSpan);
return HighlightElement(classifiedSpans, fullSourceText, indent); return HighlightElement(classifiedSpans, fullSourceText, indent);
} }

View File

@@ -3,15 +3,15 @@
"isRoot": true, "isRoot": true,
"tools": { "tools": {
"cake.tool": { "cake.tool": {
"version": "4.0.0", "version": "5.1.0",
"commands": [ "commands": [
"dotnet-cake" "dotnet-cake"
] ]
}, },
"dotnet-example": { "verify.tool": {
"version": "3.1.0", "version": "0.6.0",
"commands": [ "commands": [
"dotnet-example" "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>

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