mirror of
https://github.com/spectreconsole/spectre.console.git
synced 2025-10-25 15:19:23 +00:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4d1796e40 | ||
|
|
2dd0eb9f74 | ||
|
|
fa85216554 | ||
|
|
d475e3b30a | ||
|
|
9637066927 | ||
|
|
0b4321115a | ||
|
|
5cd9ece31a | ||
|
|
b0341862cf | ||
|
|
2e7b3d520a | ||
|
|
646f51a628 | ||
|
|
a0bd481255 | ||
|
|
6d197c5140 | ||
|
|
108e56c229 | ||
|
|
66994cd904 | ||
|
|
f9bd936254 | ||
|
|
a068fc68c3 | ||
|
|
aa34c145b9 | ||
|
|
98cf63f485 | ||
|
|
c3286a4842 | ||
|
|
e5bf2bd498 | ||
|
|
5267ebda49 | ||
|
|
f19202b427 | ||
|
|
8e4f33bba4 | ||
|
|
e596e6eb4f | ||
|
|
a80120babc | ||
|
|
214d510d6d | ||
|
|
0986a5f744 | ||
|
|
b72a695c35 | ||
|
|
6a7733cabf | ||
|
|
36e2034a1c |
6
.github/workflows/ci.yaml
vendored
6
.github/workflows/ci.yaml
vendored
@@ -2,9 +2,7 @@ name: Continuous Integration
|
||||
on: pull_request
|
||||
|
||||
env:
|
||||
# Set the DOTNET_SKIP_FIRST_TIME_EXPERIENCE environment variable to stop wasting time caching packages
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
|
||||
# Disable sending usage data to Microsoft
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
||||
|
||||
jobs:
|
||||
@@ -28,10 +26,6 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 'Get Git tags'
|
||||
run: git fetch --tags
|
||||
shell: bash
|
||||
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
|
||||
10
.github/workflows/publish.yaml
vendored
10
.github/workflows/publish.yaml
vendored
@@ -8,9 +8,7 @@ on:
|
||||
- main
|
||||
|
||||
env:
|
||||
# Set the DOTNET_SKIP_FIRST_TIME_EXPERIENCE environment variable to stop wasting time caching packages
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
|
||||
# Disable sending usage data to Microsoft
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
||||
|
||||
jobs:
|
||||
@@ -39,10 +37,6 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 'Get Git tags'
|
||||
run: git fetch --tags
|
||||
shell: bash
|
||||
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
@@ -69,10 +63,6 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 'Get Git tags'
|
||||
run: git fetch --tags
|
||||
shell: bash
|
||||
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
|
||||
299
README.md
299
README.md
@@ -1,9 +1,21 @@
|
||||
# `Spectre.Console`
|
||||
|
||||
_[](https://www.nuget.org/packages/spectre.console)_
|
||||
|
||||
A .NET Standard 2.0 library that makes it easier to create beautiful console applications.
|
||||
It is heavily inspired by the excellent [Rich library](https://github.com/willmcgugan/rich)
|
||||
for Python.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Features](#features)
|
||||
2. [Example](#example)
|
||||
3. [Usage](#usage)
|
||||
3.1. [Using the static API](#using-the-static-api)
|
||||
3.2. [Creating a console](#creating-a-console)
|
||||
4. [Available styles](#available-styles)
|
||||
5. [Predefined colors](#predefined-colors)
|
||||
|
||||
## Features
|
||||
|
||||
* Written with unit testing in mind.
|
||||
@@ -38,12 +50,11 @@ like you usually do with the `System.Console` API, but prettier.
|
||||
|
||||
```csharp
|
||||
AnsiConsole.Foreground = Color.CornflowerBlue;
|
||||
AnsiConsole.Style = Styles.Underline | Styles.Bold;
|
||||
AnsiConsole.Decoration = Decoration.Underline | Decoration.Bold;
|
||||
AnsiConsole.WriteLine("Hello World!");
|
||||
|
||||
AnsiConsole.Reset();
|
||||
AnsiConsole.WriteLine("Good bye!");
|
||||
AnsiConsole.WriteLine();
|
||||
AnsiConsole.MarkupLine("[bold yellow on red]{0}[/] [underline]world[/]!", "Goodbye");
|
||||
```
|
||||
|
||||
If you want to get a reference to the default `IAnsiConsole`,
|
||||
@@ -53,7 +64,10 @@ you can access it via `AnsiConsole.Console`.
|
||||
|
||||
Sometimes it's useful to explicitly create a console with specific
|
||||
capabilities, such as during unit testing when you want control
|
||||
over the environment your code runs in.
|
||||
over the environment your code runs in.
|
||||
|
||||
It's recommended to not use `AnsiConsole` in code that run as
|
||||
part of a unit test.
|
||||
|
||||
```csharp
|
||||
IAnsiConsole console = AnsiConsole.Create(
|
||||
@@ -69,3 +83,280 @@ _NOTE: Even if you can specify a specific color system to use
|
||||
when manually creating a console, remember that the user's terminal
|
||||
might not be able to use it, so unless you're creating an IAnsiConsole
|
||||
for testing, always use `ColorSystemSupport.Detect` and `AnsiSupport.Detect`._
|
||||
|
||||
## Available styles
|
||||
|
||||
_NOTE: Not all styles are supported in every terminal._
|
||||
|
||||
Name | Description
|
||||
--- | ---
|
||||
`bold` | Bold text
|
||||
`dim` | Dim or faint text
|
||||
`italic` | Italic text
|
||||
`underline` | Underlined text
|
||||
`invert` | Swaps the foreground and background colors
|
||||
`conceal` | Hides the text
|
||||
`slowblink` | Makes text blink slowly
|
||||
`rapidblink` | Makes text blink
|
||||
`strikethrough` | Shows text with a horizontal line through the center
|
||||
|
||||
## Predefined colors
|
||||
|
||||
Number | Name | RGB | Hex | System.ConsoleColor
|
||||
--- | --- | --- | --- | ---
|
||||
`0` | `black` | `0,0,0` | `#000000` | `Black`
|
||||
`1` | `maroon` | `128,0,0` | `#800000` | `DarkRed`
|
||||
`2` | `green` | `0,128,0` | `#008000` | `DarkGreen`
|
||||
`3` | `olive` | `128,128,0` | `#808000` | `DarkYellow`
|
||||
`4` | `navy` | `0,0,128` | `#000080` | `DarkBlue`
|
||||
`5` | `purple` | `128,0,128` | `#800080` | `DarkMagenta`
|
||||
`6` | `teal` | `0,128,128` | `#008080` | `DarkCyan`
|
||||
`7` | `silver` | `192,192,192` | `#c0c0c0` | `Gray`
|
||||
`8` | `grey` | `128,128,128` | `#808080` | `DarkGray`
|
||||
`9` | `red` | `255,0,0` | `#ff0000` | `Red`
|
||||
`10` | `lime` | `0,255,0` | `#00ff00` | `Green`
|
||||
`11` | `yellow` | `255,255,0` | `#ffff00` | `Yellow`
|
||||
`12` | `blue` | `0,0,255` | `#0000ff` | `Blue`
|
||||
`13` | `fuchsia` | `255,0,255` | `#ff00ff` | `Magenta`
|
||||
`14` | `aqua` | `0,255,255` | `#00ffff` | `Cyan`
|
||||
`15` | `white` | `255,255,255` | `#ffffff` | `White`
|
||||
`16` | `grey0` | `0,0,0` | `#000000`
|
||||
`17` | `navyblue` | `0,0,95` | `#00005f`
|
||||
`18` | `darkblue` | `0,0,135` | `#000087`
|
||||
`19` | `blue3` | `0,0,175` | `#0000af`
|
||||
`20` | `blue3_1` | `0,0,215` | `#0000d7`
|
||||
`21` | `blue1` | `0,0,255` | `#0000ff`
|
||||
`22` | `darkgreen` | `0,95,0` | `#005f00`
|
||||
`23` | `deepskyblue4` | `0,95,95` | `#005f5f`
|
||||
`24` | `deepskyblue4_1` | `0,95,135` | `#005f87`
|
||||
`25` | `deepskyblue4_2` | `0,95,175` | `#005faf`
|
||||
`26` | `dodgerblue3` | `0,95,215` | `#005fd7`
|
||||
`27` | `dodgerblue2` | `0,95,255` | `#005fff`
|
||||
`28` | `green4` | `0,135,0` | `#008700`
|
||||
`29` | `springgreen4` | `0,135,95` | `#00875f`
|
||||
`30` | `turquoise4` | `0,135,135` | `#008787`
|
||||
`31` | `deepskyblue3` | `0,135,175` | `#0087af`
|
||||
`32` | `deepskyblue3_1` | `0,135,215` | `#0087d7`
|
||||
`33` | `dodgerblue1` | `0,135,255` | `#0087ff`
|
||||
`34` | `green3` | `0,175,0` | `#00af00`
|
||||
`35` | `springgreen3` | `0,175,95` | `#00af5f`
|
||||
`36` | `darkcyan` | `0,175,135` | `#00af87`
|
||||
`37` | `lightseagreen` | `0,175,175` | `#00afaf`
|
||||
`38` | `deepskyblue2` | `0,175,215` | `#00afd7`
|
||||
`39` | `deepskyblue1` | `0,175,255` | `#00afff`
|
||||
`40` | `green3_1` | `0,215,0` | `#00d700`
|
||||
`41` | `springgreen3_1` | `0,215,95` | `#00d75f`
|
||||
`42` | `springgreen2` | `0,215,135` | `#00d787`
|
||||
`43` | `cyan3` | `0,215,175` | `#00d7af`
|
||||
`44` | `darkturquoise` | `0,215,215` | `#00d7d7`
|
||||
`45` | `turquoise2` | `0,215,255` | `#00d7ff`
|
||||
`46` | `green1` | `0,255,0` | `#00ff00`
|
||||
`47` | `springgreen2_1` | `0,255,95` | `#00ff5f`
|
||||
`48` | `springgreen1` | `0,255,135` | `#00ff87`
|
||||
`49` | `mediumspringgreen` | `0,255,175` | `#00ffaf`
|
||||
`50` | `cyan2` | `0,255,215` | `#00ffd7`
|
||||
`51` | `cyan1` | `0,255,255` | `#00ffff`
|
||||
`52` | `darkred` | `95,0,0` | `#5f0000`
|
||||
`53` | `deeppink4` | `95,0,95` | `#5f005f`
|
||||
`54` | `purple4` | `95,0,135` | `#5f0087`
|
||||
`55` | `purple4_1` | `95,0,175` | `#5f00af`
|
||||
`56` | `purple3` | `95,0,215` | `#5f00d7`
|
||||
`57` | `blueviolet` | `95,0,255` | `#5f00ff`
|
||||
`58` | `orange4` | `95,95,0` | `#5f5f00`
|
||||
`59` | `grey37` | `95,95,95` | `#5f5f5f`
|
||||
`60` | `mediumpurple4` | `95,95,135` | `#5f5f87`
|
||||
`61` | `slateblue3` | `95,95,175` | `#5f5faf`
|
||||
`62` | `slateblue3_1` | `95,95,215` | `#5f5fd7`
|
||||
`63` | `royalblue1` | `95,95,255` | `#5f5fff`
|
||||
`64` | `chartreuse4` | `95,135,0` | `#5f8700`
|
||||
`65` | `darkseagreen4` | `95,135,95` | `#5f875f`
|
||||
`66` | `paleturquoise4` | `95,135,135` | `#5f8787`
|
||||
`67` | `steelblue` | `95,135,175` | `#5f87af`
|
||||
`68` | `steelblue3` | `95,135,215` | `#5f87d7`
|
||||
`69` | `cornflowerblue` | `95,135,255` | `#5f87ff`
|
||||
`70` | `chartreuse3` | `95,175,0` | `#5faf00`
|
||||
`71` | `darkseagreen4_1` | `95,175,95` | `#5faf5f`
|
||||
`72` | `cadetblue` | `95,175,135` | `#5faf87`
|
||||
`73` | `cadetblue_1` | `95,175,175` | `#5fafaf`
|
||||
`74` | `skyblue3` | `95,175,215` | `#5fafd7`
|
||||
`75` | `steelblue1` | `95,175,255` | `#5fafff`
|
||||
`76` | `chartreuse3_1` | `95,215,0` | `#5fd700`
|
||||
`77` | `palegreen3` | `95,215,95` | `#5fd75f`
|
||||
`78` | `seagreen3` | `95,215,135` | `#5fd787`
|
||||
`79` | `aquamarine3` | `95,215,175` | `#5fd7af`
|
||||
`80` | `mediumturquoise` | `95,215,215` | `#5fd7d7`
|
||||
`81` | `steelblue1_1` | `95,215,255` | `#5fd7ff`
|
||||
`82` | `chartreuse2` | `95,255,0` | `#5fff00`
|
||||
`83` | `seagreen2` | `95,255,95` | `#5fff5f`
|
||||
`84` | `seagreen1` | `95,255,135` | `#5fff87`
|
||||
`85` | `seagreen1_1` | `95,255,175` | `#5fffaf`
|
||||
`86` | `aquamarine1` | `95,255,215` | `#5fffd7`
|
||||
`87` | `darkslategray2` | `95,255,255` | `#5fffff`
|
||||
`88` | `darkred_1` | `135,0,0` | `#870000`
|
||||
`89` | `deeppink4_1` | `135,0,95` | `#87005f`
|
||||
`90` | `darkmagenta` | `135,0,135` | `#870087`
|
||||
`91` | `darkmagenta_1` | `135,0,175` | `#8700af`
|
||||
`92` | `darkviolet` | `135,0,215` | `#8700d7`
|
||||
`93` | `purple_1` | `135,0,255` | `#8700ff`
|
||||
`94` | `orange4_1` | `135,95,0` | `#875f00`
|
||||
`95` | `lightpink4` | `135,95,95` | `#875f5f`
|
||||
`96` | `plum4` | `135,95,135` | `#875f87`
|
||||
`97` | `mediumpurple3` | `135,95,175` | `#875faf`
|
||||
`98` | `mediumpurple3_1` | `135,95,215` | `#875fd7`
|
||||
`99` | `slateblue1` | `135,95,255` | `#875fff`
|
||||
`100` | `yellow4` | `135,135,0` | `#878700`
|
||||
`101` | `wheat4` | `135,135,95` | `#87875f`
|
||||
`102` | `grey53` | `135,135,135` | `#878787`
|
||||
`103` | `lightslategrey` | `135,135,175` | `#8787af`
|
||||
`104` | `mediumpurple` | `135,135,215` | `#8787d7`
|
||||
`105` | `lightslateblue` | `135,135,255` | `#8787ff`
|
||||
`106` | `yellow4_1` | `135,175,0` | `#87af00`
|
||||
`107` | `darkolivegreen3` | `135,175,95` | `#87af5f`
|
||||
`108` | `darkseagreen` | `135,175,135` | `#87af87`
|
||||
`109` | `lightskyblue3` | `135,175,175` | `#87afaf`
|
||||
`110` | `lightskyblue3_1` | `135,175,215` | `#87afd7`
|
||||
`111` | `skyblue2` | `135,175,255` | `#87afff`
|
||||
`112` | `chartreuse2_1` | `135,215,0` | `#87d700`
|
||||
`113` | `darkolivegreen3_1` | `135,215,95` | `#87d75f`
|
||||
`114` | `palegreen3_1` | `135,215,135` | `#87d787`
|
||||
`115` | `darkseagreen3` | `135,215,175` | `#87d7af`
|
||||
`116` | `darkslategray3` | `135,215,215` | `#87d7d7`
|
||||
`117` | `skyblue1` | `135,215,255` | `#87d7ff`
|
||||
`118` | `chartreuse1` | `135,255,0` | `#87ff00`
|
||||
`119` | `lightgreen` | `135,255,95` | `#87ff5f`
|
||||
`120` | `lightgreen_1` | `135,255,135` | `#87ff87`
|
||||
`121` | `palegreen1` | `135,255,175` | `#87ffaf`
|
||||
`122` | `aquamarine1_1` | `135,255,215` | `#87ffd7`
|
||||
`123` | `darkslategray1` | `135,255,255` | `#87ffff`
|
||||
`124` | `red3` | `175,0,0` | `#af0000`
|
||||
`125` | `deeppink4_2` | `175,0,95` | `#af005f`
|
||||
`126` | `mediumvioletred` | `175,0,135` | `#af0087`
|
||||
`127` | `magenta3` | `175,0,175` | `#af00af`
|
||||
`128` | `darkviolet_1` | `175,0,215` | `#af00d7`
|
||||
`129` | `purple_2` | `175,0,255` | `#af00ff`
|
||||
`130` | `darkorange3` | `175,95,0` | `#af5f00`
|
||||
`131` | `indianred` | `175,95,95` | `#af5f5f`
|
||||
`132` | `hotpink3` | `175,95,135` | `#af5f87`
|
||||
`133` | `mediumorchid3` | `175,95,175` | `#af5faf`
|
||||
`134` | `mediumorchid` | `175,95,215` | `#af5fd7`
|
||||
`135` | `mediumpurple2` | `175,95,255` | `#af5fff`
|
||||
`136` | `darkgoldenrod` | `175,135,0` | `#af8700`
|
||||
`137` | `lightsalmon3` | `175,135,95` | `#af875f`
|
||||
`138` | `rosybrown` | `175,135,135` | `#af8787`
|
||||
`139` | `grey63` | `175,135,175` | `#af87af`
|
||||
`140` | `mediumpurple2_1` | `175,135,215` | `#af87d7`
|
||||
`141` | `mediumpurple1` | `175,135,255` | `#af87ff`
|
||||
`142` | `gold3` | `175,175,0` | `#afaf00`
|
||||
`143` | `darkkhaki` | `175,175,95` | `#afaf5f`
|
||||
`144` | `navajowhite3` | `175,175,135` | `#afaf87`
|
||||
`145` | `grey69` | `175,175,175` | `#afafaf`
|
||||
`146` | `lightsteelblue3` | `175,175,215` | `#afafd7`
|
||||
`147` | `lightsteelblue` | `175,175,255` | `#afafff`
|
||||
`148` | `yellow3` | `175,215,0` | `#afd700`
|
||||
`149` | `darkolivegreen3_2` | `175,215,95` | `#afd75f`
|
||||
`150` | `darkseagreen3_1` | `175,215,135` | `#afd787`
|
||||
`151` | `darkseagreen2` | `175,215,175` | `#afd7af`
|
||||
`152` | `lightcyan3` | `175,215,215` | `#afd7d7`
|
||||
`153` | `lightskyblue1` | `175,215,255` | `#afd7ff`
|
||||
`154` | `greenyellow` | `175,255,0` | `#afff00`
|
||||
`155` | `darkolivegreen2` | `175,255,95` | `#afff5f`
|
||||
`156` | `palegreen1_1` | `175,255,135` | `#afff87`
|
||||
`157` | `darkseagreen2_1` | `175,255,175` | `#afffaf`
|
||||
`158` | `darkseagreen1` | `175,255,215` | `#afffd7`
|
||||
`159` | `paleturquoise1` | `175,255,255` | `#afffff`
|
||||
`160` | `red3_1` | `215,0,0` | `#d70000`
|
||||
`161` | `deeppink3` | `215,0,95` | `#d7005f`
|
||||
`162` | `deeppink3_1` | `215,0,135` | `#d70087`
|
||||
`163` | `magenta3_1` | `215,0,175` | `#d700af`
|
||||
`164` | `magenta3_2` | `215,0,215` | `#d700d7`
|
||||
`165` | `magenta2` | `215,0,255` | `#d700ff`
|
||||
`166` | `darkorange3_1` | `215,95,0` | `#d75f00`
|
||||
`167` | `indianred_1` | `215,95,95` | `#d75f5f`
|
||||
`168` | `hotpink3_1` | `215,95,135` | `#d75f87`
|
||||
`169` | `hotpink2` | `215,95,175` | `#d75faf`
|
||||
`170` | `orchid` | `215,95,215` | `#d75fd7`
|
||||
`171` | `mediumorchid1` | `215,95,255` | `#d75fff`
|
||||
`172` | `orange3` | `215,135,0` | `#d78700`
|
||||
`173` | `lightsalmon3_1` | `215,135,95` | `#d7875f`
|
||||
`174` | `lightpink3` | `215,135,135` | `#d78787`
|
||||
`175` | `pink3` | `215,135,175` | `#d787af`
|
||||
`176` | `plum3` | `215,135,215` | `#d787d7`
|
||||
`177` | `violet` | `215,135,255` | `#d787ff`
|
||||
`178` | `gold3_1` | `215,175,0` | `#d7af00`
|
||||
`179` | `lightgoldenrod3` | `215,175,95` | `#d7af5f`
|
||||
`180` | `tan` | `215,175,135` | `#d7af87`
|
||||
`181` | `mistyrose3` | `215,175,175` | `#d7afaf`
|
||||
`182` | `thistle3` | `215,175,215` | `#d7afd7`
|
||||
`183` | `plum2` | `215,175,255` | `#d7afff`
|
||||
`184` | `yellow3_1` | `215,215,0` | `#d7d700`
|
||||
`185` | `khaki3` | `215,215,95` | `#d7d75f`
|
||||
`186` | `lightgoldenrod2` | `215,215,135` | `#d7d787`
|
||||
`187` | `lightyellow3` | `215,215,175` | `#d7d7af`
|
||||
`188` | `grey84` | `215,215,215` | `#d7d7d7`
|
||||
`189` | `lightsteelblue1` | `215,215,255` | `#d7d7ff`
|
||||
`190` | `yellow2` | `215,255,0` | `#d7ff00`
|
||||
`191` | `darkolivegreen1` | `215,255,95` | `#d7ff5f`
|
||||
`192` | `darkolivegreen1_1` | `215,255,135` | `#d7ff87`
|
||||
`193` | `darkseagreen1_1` | `215,255,175` | `#d7ffaf`
|
||||
`194` | `honeydew2` | `215,255,215` | `#d7ffd7`
|
||||
`195` | `lightcyan1` | `215,255,255` | `#d7ffff`
|
||||
`196` | `red1` | `255,0,0` | `#ff0000`
|
||||
`197` | `deeppink2` | `255,0,95` | `#ff005f`
|
||||
`198` | `deeppink1` | `255,0,135` | `#ff0087`
|
||||
`199` | `deeppink1_1` | `255,0,175` | `#ff00af`
|
||||
`200` | `magenta2_1` | `255,0,215` | `#ff00d7`
|
||||
`201` | `magenta1` | `255,0,255` | `#ff00ff`
|
||||
`202` | `orangered1` | `255,95,0` | `#ff5f00`
|
||||
`203` | `indianred1` | `255,95,95` | `#ff5f5f`
|
||||
`204` | `indianred1_1` | `255,95,135` | `#ff5f87`
|
||||
`205` | `hotpink` | `255,95,175` | `#ff5faf`
|
||||
`206` | `hotpink_1` | `255,95,215` | `#ff5fd7`
|
||||
`207` | `mediumorchid1_1` | `255,95,255` | `#ff5fff`
|
||||
`208` | `darkorange` | `255,135,0` | `#ff8700`
|
||||
`209` | `salmon1` | `255,135,95` | `#ff875f`
|
||||
`210` | `lightcoral` | `255,135,135` | `#ff8787`
|
||||
`211` | `palevioletred1` | `255,135,175` | `#ff87af`
|
||||
`212` | `orchid2` | `255,135,215` | `#ff87d7`
|
||||
`213` | `orchid1` | `255,135,255` | `#ff87ff`
|
||||
`214` | `orange1` | `255,175,0` | `#ffaf00`
|
||||
`215` | `sandybrown` | `255,175,95` | `#ffaf5f`
|
||||
`216` | `lightsalmon1` | `255,175,135` | `#ffaf87`
|
||||
`217` | `lightpink1` | `255,175,175` | `#ffafaf`
|
||||
`218` | `pink1` | `255,175,215` | `#ffafd7`
|
||||
`219` | `plum1` | `255,175,255` | `#ffafff`
|
||||
`220` | `gold1` | `255,215,0` | `#ffd700`
|
||||
`221` | `lightgoldenrod2_1` | `255,215,95` | `#ffd75f`
|
||||
`222` | `lightgoldenrod2_2` | `255,215,135` | `#ffd787`
|
||||
`223` | `navajowhite1` | `255,215,175` | `#ffd7af`
|
||||
`224` | `mistyrose1` | `255,215,215` | `#ffd7d7`
|
||||
`225` | `thistle1` | `255,215,255` | `#ffd7ff`
|
||||
`226` | `yellow1` | `255,255,0` | `#ffff00`
|
||||
`227` | `lightgoldenrod1` | `255,255,95` | `#ffff5f`
|
||||
`228` | `khaki1` | `255,255,135` | `#ffff87`
|
||||
`229` | `wheat1` | `255,255,175` | `#ffffaf`
|
||||
`230` | `cornsilk1` | `255,255,215` | `#ffffd7`
|
||||
`231` | `grey100` | `255,255,255` | `#ffffff`
|
||||
`232` | `grey3` | `8,8,8` | `#080808`
|
||||
`233` | `grey7` | `18,18,18` | `#121212`
|
||||
`234` | `grey11` | `28,28,28` | `#1c1c1c`
|
||||
`235` | `grey15` | `38,38,38` | `#262626`
|
||||
`236` | `grey19` | `48,48,48` | `#303030`
|
||||
`237` | `grey23` | `58,58,58` | `#3a3a3a`
|
||||
`238` | `grey27` | `68,68,68` | `#444444`
|
||||
`239` | `grey30` | `78,78,78` | `#4e4e4e`
|
||||
`240` | `grey35` | `88,88,88` | `#585858`
|
||||
`241` | `grey39` | `98,98,98` | `#626262`
|
||||
`242` | `grey42` | `108,108,108` | `#6c6c6c`
|
||||
`243` | `grey46` | `118,118,118` | `#767676`
|
||||
`244` | `grey50` | `128,128,128` | `#808080`
|
||||
`245` | `grey54` | `138,138,138` | `#8a8a8a`
|
||||
`246` | `grey58` | `148,148,148` | `#949494`
|
||||
`247` | `grey62` | `158,158,158` | `#9e9e9e`
|
||||
`248` | `grey66` | `168,168,168` | `#a8a8a8`
|
||||
`249` | `grey70` | `178,178,178` | `#b2b2b2`
|
||||
`250` | `grey74` | `188,188,188` | `#bcbcbc`
|
||||
`251` | `grey78` | `198,198,198` | `#c6c6c6`
|
||||
`252` | `grey82` | `208,208,208` | `#d0d0d0`
|
||||
`253` | `grey85` | `218,218,218` | `#dadada`
|
||||
`254` | `grey89` | `228,228,228` | `#e4e4e4`
|
||||
`255` | `grey93` | `238,238,238` | `#eeeeee`
|
||||
|
||||
BIN
gfx/large-logo.png
Normal file
BIN
gfx/large-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 600 KiB |
BIN
gfx/medium-logo.png
Normal file
BIN
gfx/medium-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
BIN
gfx/small-logo.png
Normal file
BIN
gfx/small-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
2
scripts/.gitignore
vendored
Normal file
2
scripts/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Generated
|
||||
Temp
|
||||
24
scripts/Generate-Colors.ps1
Normal file
24
scripts/Generate-Colors.ps1
Normal file
@@ -0,0 +1,24 @@
|
||||
##########################################################
|
||||
# Script that generates known colors and lookup tables.
|
||||
##########################################################
|
||||
|
||||
$Output = Join-Path $PSScriptRoot "Temp"
|
||||
$Source = Join-Path $PSScriptRoot "/../src/Spectre.Console"
|
||||
|
||||
if(!(Test-Path $Output -PathType Container)) {
|
||||
New-Item -ItemType Directory -Path $Output | Out-Null
|
||||
}
|
||||
|
||||
# Generate the files
|
||||
Push-Location Generator
|
||||
&dotnet run -- colors "$Output"
|
||||
if(!$?) {
|
||||
Pop-Location
|
||||
Throw "An error occured when generating code."
|
||||
}
|
||||
Pop-Location
|
||||
|
||||
# Copy the files to the correct location
|
||||
Copy-Item (Join-Path "$Output" "Color.Generated.cs") -Destination "$Source/Color.Generated.cs"
|
||||
Copy-Item (Join-Path "$Output" "ColorPalette.Generated.cs") -Destination "$Source/Internal/Colors/ColorPalette.Generated.cs"
|
||||
Copy-Item (Join-Path "$Output" "ColorTable.Generated.cs") -Destination "$Source/Internal/Colors/ColorTable.Generated.cs"
|
||||
59
scripts/Generator/Commands/ColorGeneratorCommand.cs
Normal file
59
scripts/Generator/Commands/ColorGeneratorCommand.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Generator.Models;
|
||||
using Scriban;
|
||||
using Spectre.Cli;
|
||||
using Spectre.IO;
|
||||
|
||||
namespace Generator.Commands
|
||||
{
|
||||
public sealed class ColorGeneratorCommand : Command<GeneratorCommandSettings>
|
||||
{
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
public ColorGeneratorCommand()
|
||||
{
|
||||
_fileSystem = new FileSystem();
|
||||
}
|
||||
|
||||
public override int Execute(CommandContext context, GeneratorCommandSettings settings)
|
||||
{
|
||||
var templates = new FilePath[]
|
||||
{
|
||||
"Templates/ColorPalette.Generated.template",
|
||||
"Templates/Color.Generated.template",
|
||||
"Templates/ColorTable.Generated.template"
|
||||
};
|
||||
|
||||
// Read the color model.
|
||||
var model = Color.Parse(File.ReadAllText("Data/colors.json"));
|
||||
|
||||
var output = new DirectoryPath(settings.Output);
|
||||
if (!_fileSystem.Directory.Exists(settings.Output))
|
||||
{
|
||||
_fileSystem.Directory.Create(settings.Output);
|
||||
}
|
||||
|
||||
foreach (var templatePath in templates)
|
||||
{
|
||||
// Parse the Scriban template.
|
||||
var template = Template.Parse(File.ReadAllText(templatePath.FullPath));
|
||||
|
||||
// Render the template with the model.
|
||||
var result = template.Render(new { Colors = model });
|
||||
|
||||
// Write output to file
|
||||
var file = output.CombineWithFilePath(templatePath.GetFilename().ChangeExtension(".cs"));
|
||||
File.WriteAllText(file.FullPath, result);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class GeneratorCommandSettings : CommandSettings
|
||||
{
|
||||
[CommandArgument(0, "<OUTPUT>")]
|
||||
public string Output { get; set; }
|
||||
}
|
||||
}
|
||||
3842
scripts/Generator/Data/colors.json
Normal file
3842
scripts/Generator/Data/colors.json
Normal file
File diff suppressed because it is too large
Load Diff
36
scripts/Generator/Generator.csproj
Normal file
36
scripts/Generator/Generator.csproj
Normal file
@@ -0,0 +1,36 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="out\**" />
|
||||
<EmbeddedResource Remove="out\**" />
|
||||
<None Remove="out\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Data\colors.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Templates\ColorTable.Generated.template">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Templates\Color.Generated.template">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Templates\ColorPalette.Generated.template">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Scriban" Version="2.1.3" />
|
||||
<PackageReference Include="Spectre.Cli" Version="0.36.1-preview.0.6" />
|
||||
<PackageReference Include="Spectre.IO" Version="0.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
37
scripts/Generator/Generator.sln
Normal file
37
scripts/Generator/Generator.sln
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30320.27
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Generator", "Generator.csproj", "{5668D267-53E3-4B99-97AE-59AA597D22ED}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{5668D267-53E3-4B99-97AE-59AA597D22ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5668D267-53E3-4B99-97AE-59AA597D22ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5668D267-53E3-4B99-97AE-59AA597D22ED}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5668D267-53E3-4B99-97AE-59AA597D22ED}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5668D267-53E3-4B99-97AE-59AA597D22ED}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5668D267-53E3-4B99-97AE-59AA597D22ED}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5668D267-53E3-4B99-97AE-59AA597D22ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5668D267-53E3-4B99-97AE-59AA597D22ED}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5668D267-53E3-4B99-97AE-59AA597D22ED}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5668D267-53E3-4B99-97AE-59AA597D22ED}.Release|x64.Build.0 = Release|Any CPU
|
||||
{5668D267-53E3-4B99-97AE-59AA597D22ED}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5668D267-53E3-4B99-97AE-59AA597D22ED}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5F37FDE3-D591-4D43-8DDE-2ED6BAB0A7B4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
62
scripts/Generator/Models/Color.cs
Normal file
62
scripts/Generator/Models/Color.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Generator.Models
|
||||
{
|
||||
public sealed class Color
|
||||
{
|
||||
public int Number { get; set; }
|
||||
public string Hex { get; set; }
|
||||
public string Name { get; set; }
|
||||
public Rgb Rgb { get; set; }
|
||||
|
||||
public int R => Rgb.R;
|
||||
public int G => Rgb.G;
|
||||
public int B => Rgb.B;
|
||||
|
||||
public static IEnumerable<Color> Parse(string json)
|
||||
{
|
||||
var source = JsonConvert.DeserializeObject<List<Color>>(json);
|
||||
|
||||
var check = new Dictionary<string, Color>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var color in source.OrderBy(c => c.Number))
|
||||
{
|
||||
if (!check.ContainsKey(color.Name))
|
||||
{
|
||||
check.Add(color.Name, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newName = (string)null;
|
||||
for (int i = 1; i < 100; i++)
|
||||
{
|
||||
if (!check.ContainsKey($"{color.Name}_{i}"))
|
||||
{
|
||||
newName = $"{color.Name}_{i}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newName == null)
|
||||
{
|
||||
throw new InvalidOperationException("Impossible!");
|
||||
}
|
||||
|
||||
check.Add(newName, color);
|
||||
color.Name = newName;
|
||||
}
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Rgb
|
||||
{
|
||||
public int R { get; set; }
|
||||
public int G { get; set; }
|
||||
public int B { get; set; }
|
||||
}
|
||||
}
|
||||
14
scripts/Generator/Models/ColorModel.cs
Normal file
14
scripts/Generator/Models/ColorModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Generator.Models
|
||||
{
|
||||
public sealed class ColorModel
|
||||
{
|
||||
public List<Color> Colors { get; set; }
|
||||
|
||||
public ColorModel(IEnumerable<Color> colors)
|
||||
{
|
||||
Colors = new List<Color>(colors);
|
||||
}
|
||||
}
|
||||
}
|
||||
6
scripts/Generator/Models/Palette.cs
Normal file
6
scripts/Generator/Models/Palette.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Generator.Models
|
||||
{
|
||||
public sealed class Palette
|
||||
{
|
||||
}
|
||||
}
|
||||
19
scripts/Generator/Program.cs
Normal file
19
scripts/Generator/Program.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Generator.Commands;
|
||||
using Spectre.Cli;
|
||||
|
||||
namespace Generator
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
var app = new CommandApp();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.AddCommand<ColorGeneratorCommand>("colors");
|
||||
});
|
||||
|
||||
return app.Run(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
36
scripts/Generator/Templates/Color.Generated.template
Normal file
36
scripts/Generator/Templates/Color.Generated.template
Normal file
@@ -0,0 +1,36 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Generated {{ date.now | date.to_string `%Y-%m-%d %k:%M` }}
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a color.
|
||||
/// </summary>
|
||||
public partial struct Color
|
||||
{
|
||||
internal Color(byte number, byte red, byte green, byte blue, bool isDefault = false)
|
||||
: this(red, green, blue)
|
||||
{
|
||||
Number = number;
|
||||
IsDefault = isDefault;
|
||||
}
|
||||
{{~ for color in colors }}
|
||||
/// <summary>
|
||||
/// Gets the color "{{ color.name }}" (RGB {{ color.r }},{{ color.g }},{{ color.b }}).
|
||||
/// </summary>
|
||||
{{- if string.contains color.name "_" }}
|
||||
[SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores")]
|
||||
{{- end}}
|
||||
public static Color {{ color.name }} { get; } = new Color({{ color.number }}, {{ color.r }}, {{ color.g }}, {{ color.b }});
|
||||
{{~ end ~}}
|
||||
}
|
||||
}
|
||||
47
scripts/Generator/Templates/ColorPalette.Generated.template
Normal file
47
scripts/Generator/Templates/ColorPalette.Generated.template
Normal file
@@ -0,0 +1,47 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Generated {{ date.now | date.to_string `%Y-%m-%d %k:%M` }}
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static partial class ColorPalette
|
||||
{
|
||||
private static List<Color> GenerateLegacyPalette()
|
||||
{
|
||||
return new List<Color>
|
||||
{
|
||||
{{~ for number in 0..7 ~}}
|
||||
Color.{{ colors[number].name }},
|
||||
{{~ end ~}}
|
||||
};
|
||||
}
|
||||
|
||||
private static List<Color> GenerateStandardPalette(IReadOnlyList<Color> legacy)
|
||||
{
|
||||
return new List<Color>(legacy)
|
||||
{
|
||||
{{~ for number in 8..15 ~}}
|
||||
Color.{{ colors[number].name }},
|
||||
{{~ end ~}}
|
||||
};
|
||||
}
|
||||
|
||||
private static List<Color> GenerateEightBitPalette(IReadOnlyList<Color> standard)
|
||||
{
|
||||
return new List<Color>(standard)
|
||||
{
|
||||
{{~ for number in 16..255 ~}}
|
||||
Color.{{ colors[number].name }},
|
||||
{{~ end ~}}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
28
scripts/Generator/Templates/ColorTable.Generated.template
Normal file
28
scripts/Generator/Templates/ColorTable.Generated.template
Normal file
@@ -0,0 +1,28 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Generated {{ date.now | date.to_string `%Y-%m-%d %k:%M` }}
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static partial class ColorTable
|
||||
{
|
||||
private static Dictionary<string, int> GenerateTable()
|
||||
{
|
||||
return new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{{~ for color in colors ~}}
|
||||
{ "{{ string.downcase color.name }}", {{ color.number }} },
|
||||
{{~ end ~}}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,3 +75,6 @@ dotnet_diagnostic.CA1032.severity = none
|
||||
|
||||
# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly
|
||||
dotnet_diagnostic.CA1826.severity = none
|
||||
|
||||
# RCS1079: Throwing of new NotImplementedException.
|
||||
dotnet_diagnostic.RCS1079.severity = warning
|
||||
@@ -18,6 +18,7 @@
|
||||
<Authors>Patrik Svensson</Authors>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<RepositoryUrl>https://github.com/spectresystems/spectre.console</RepositoryUrl>
|
||||
<PackageIcon>small-logo.png</PackageIcon>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
<PackageProjectUrl>https://github.com/spectresystems/spectre.console</PackageProjectUrl>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace Sample
|
||||
@@ -14,14 +9,28 @@ namespace Sample
|
||||
{
|
||||
// Use the static API to write some things to the console.
|
||||
AnsiConsole.Foreground = Color.Chartreuse2;
|
||||
AnsiConsole.Style = Styles.Underline | Styles.Bold;
|
||||
AnsiConsole.Decoration = Decoration.Underline | Decoration.Bold;
|
||||
AnsiConsole.WriteLine("Hello World!");
|
||||
AnsiConsole.Reset();
|
||||
AnsiConsole.WriteLine($"Capabilities: {AnsiConsole.Capabilities}");
|
||||
AnsiConsole.WriteLine($"Width={AnsiConsole.Width}, Height={AnsiConsole.Height}");
|
||||
AnsiConsole.WriteLine("Good bye!");
|
||||
AnsiConsole.MarkupLine("Capabilities: [yellow underline]{0}[/]", AnsiConsole.Capabilities);
|
||||
AnsiConsole.MarkupLine("Encoding: [yellow underline]{0}[/]", AnsiConsole.Console.Encoding.EncodingName);
|
||||
AnsiConsole.MarkupLine("Width=[yellow]{0}[/], Height=[yellow]{1}[/]", AnsiConsole.Width, AnsiConsole.Height);
|
||||
AnsiConsole.MarkupLine("[white on red]Good[/] [red]bye[/]!");
|
||||
AnsiConsole.WriteLine();
|
||||
|
||||
// We can also use System.ConsoleColor with AnsiConsole
|
||||
// to set the foreground and background color.
|
||||
foreach (ConsoleColor value in Enum.GetValues(typeof(ConsoleColor)))
|
||||
{
|
||||
var foreground = value;
|
||||
var background = (ConsoleColor)(15 - (int)value);
|
||||
|
||||
AnsiConsole.Foreground = foreground;
|
||||
AnsiConsole.Background = background;
|
||||
AnsiConsole.WriteLine("{0} on {1}", foreground, background);
|
||||
AnsiConsole.ResetColors();
|
||||
}
|
||||
|
||||
// We can get the default console via the static API.
|
||||
var console = AnsiConsole.Console;
|
||||
|
||||
@@ -36,18 +45,125 @@ namespace Sample
|
||||
|
||||
// In this case, we will find the closest colors
|
||||
// and downgrade them to the specified color system.
|
||||
console.WriteLine();
|
||||
console.Foreground = Color.Chartreuse2;
|
||||
console.Style = Styles.Underline | Styles.Bold;
|
||||
console.Decoration = Decoration.Underline | Decoration.Bold;
|
||||
console.WriteLine("Hello World!");
|
||||
console.ResetColors();
|
||||
console.ResetStyle();
|
||||
console.WriteLine($"Capabilities: {console.Capabilities}");
|
||||
console.WriteLine($"Width={AnsiConsole.Width}, Height={AnsiConsole.Height}");
|
||||
console.WriteLine("Good bye!");
|
||||
console.ResetDecoration();
|
||||
console.MarkupLine("Capabilities: [yellow underline]{0}[/]", console.Capabilities);
|
||||
console.MarkupLine("Encoding: [yellow underline]{0}[/]", AnsiConsole.Console.Encoding.EncodingName);
|
||||
console.MarkupLine("Width=[yellow]{0}[/], Height=[yellow]{1}[/]", console.Width, console.Height);
|
||||
console.MarkupLine("[white on red]Good[/] [red]bye[/]!");
|
||||
console.WriteLine();
|
||||
|
||||
// Nest some panels and text
|
||||
AnsiConsole.Foreground = Color.Maroon;
|
||||
AnsiConsole.Render(
|
||||
new Panel(
|
||||
new Panel(
|
||||
new Panel(
|
||||
new Panel(
|
||||
Text.New(
|
||||
"[underline]I[/] heard [underline on blue]you[/] like 📦\n\n\n\n" +
|
||||
"So I put a 📦 in a 📦\nin a 📦 in a 📦\n\n" +
|
||||
"😅", foreground: Color.White))
|
||||
{ Alignment = Justify.Center, Border = BorderKind.Rounded })))
|
||||
{
|
||||
Border = BorderKind.Ascii
|
||||
});
|
||||
|
||||
// Reset colors
|
||||
AnsiConsole.ResetColors();
|
||||
|
||||
// Left adjusted panel with text
|
||||
AnsiConsole.Render(new Panel(
|
||||
Text.New("Left adjusted\nLeft"))
|
||||
{
|
||||
Expand = true,
|
||||
Alignment = Justify.Left,
|
||||
});
|
||||
|
||||
// Centered panel with text
|
||||
AnsiConsole.Render(new Panel(
|
||||
Text.New("Centered\nCenter"))
|
||||
{
|
||||
Expand = true,
|
||||
Alignment = Justify.Center,
|
||||
});
|
||||
|
||||
// Right adjusted panel with text
|
||||
AnsiConsole.Render(new Panel(
|
||||
Text.New("Right adjusted\nRight"))
|
||||
{
|
||||
Expand = true,
|
||||
Alignment = Justify.Right,
|
||||
});
|
||||
|
||||
// A normal, square table
|
||||
var table = new Table();
|
||||
table.AddColumns("[red underline]Foo[/]", "Bar");
|
||||
table.AddRow("[blue][underline]Hell[/]o[/]", "World 🌍");
|
||||
table.AddRow("[yellow]Patrik [green]\"Lol[/]\" Svensson[/]", "Was [underline]here[/]!");
|
||||
table.AddRow("Lorem ipsum dolor sit amet, consectetur adipiscing elit,sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum", "◀ Strange language");
|
||||
table.AddRow("Hej 👋", "[green]Världen[/]");
|
||||
AnsiConsole.Render(table);
|
||||
|
||||
// A rounded table
|
||||
table = new Table { Border = BorderKind.Rounded };
|
||||
table.AddColumns("[red underline]Foo[/]", "Bar");
|
||||
table.AddRow("[blue][underline]Hell[/]o[/]", "World 🌍");
|
||||
table.AddRow("[yellow]Patrik [green]\"Lol[/]\" Svensson[/]", "Was [underline]here[/]!");
|
||||
table.AddRow("Lorem ipsum dolor sit amet, consectetur [blue]adipiscing[/] elit,sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum", "◀ Strange language");
|
||||
table.AddRow("Hej 👋", "[green]Världen[/]");
|
||||
AnsiConsole.Render(table);
|
||||
|
||||
// A rounded table without headers
|
||||
table = new Table { Border = BorderKind.Rounded, ShowHeaders = false };
|
||||
table.AddColumns("[red underline]Foo[/]", "Bar");
|
||||
table.AddRow("[blue][underline]Hell[/]o[/]", "World 🌍");
|
||||
table.AddRow("[yellow]Patrik [green]\"Lol[/]\" Svensson[/]", "Was [underline]here[/]!");
|
||||
table.AddRow("Lorem ipsum dolor sit amet, consectetur [blue]adipiscing[/] elit,sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum", "◀ Strange language");
|
||||
table.AddRow("Hej 👋", "[green]Världen[/]");
|
||||
AnsiConsole.Render(table);
|
||||
|
||||
// Emulate the usage information for "dotnet run"
|
||||
AnsiConsole.WriteLine();
|
||||
AnsiConsole.MarkupLine("Usage: [grey]dotnet [blue]run[/] [[options] [[[[--] <additional arguments>...]][/]");
|
||||
AnsiConsole.WriteLine();
|
||||
var grid = new Grid();
|
||||
grid.AddColumn(new GridColumn { NoWrap = true });
|
||||
grid.AddColumn(new GridColumn { NoWrap = true, Width = 2 });
|
||||
grid.AddColumn();
|
||||
grid.AddRow("Options:", "", "");
|
||||
grid.AddRow(" [blue]-h[/], [blue]--help[/]", "", "Show command line help.");
|
||||
grid.AddRow(" [blue]-c[/], [blue]--configuration[/] <CONFIGURATION>", "", "The configuration to run for.\nThe default for most projects is [green]Debug[/].");
|
||||
grid.AddRow(" [blue]-v[/], [blue]--verbosity[/] <LEVEL>", "", "Set the MSBuild verbosity level. Allowed values are \nq[grey][[uiet][/], m[grey][[inimal][/], n[grey][[ormal][/], d[grey][[etailed][/], and diag[grey][[nostic][/].");
|
||||
AnsiConsole.Render(grid);
|
||||
|
||||
// A simple table
|
||||
AnsiConsole.WriteLine();
|
||||
table = new Table { Border = BorderKind.Rounded };
|
||||
table.AddColumn("Foo");
|
||||
table.AddColumn("Bar");
|
||||
table.AddColumn("Baz");
|
||||
table.AddRow("Qux\nQuuuuuux", "[blue]Corgi[/]", "Waldo");
|
||||
table.AddRow("Grault", "Garply", "Fred");
|
||||
AnsiConsole.Render(table);
|
||||
|
||||
// Render a table in some panels.
|
||||
AnsiConsole.Render(new Panel(new Panel(table) { Border = BorderKind.Ascii }) { Padding = new Padding(0, 0) });
|
||||
|
||||
// Draw another table
|
||||
table = new Table { Expand = false };
|
||||
table.AddColumn(new TableColumn("Date"));
|
||||
table.AddColumn(new TableColumn("Title"));
|
||||
table.AddColumn(new TableColumn("Production\nBudget"));
|
||||
table.AddColumn(new TableColumn("Box Office"));
|
||||
table.AddRow("Dec 20, 2019", "Star Wars: The Rise of Skywalker", "$275,000,000", "[red]$375,126,118[/]");
|
||||
table.AddRow("May 25, 2018", "[yellow]Solo[/]: A Star Wars Story", "$275,000,000", "$393,151,347");
|
||||
table.AddRow("Dec 15, 2017", "Star Wars Ep. VIII: The Last Jedi", "$262,000,000", "[bold green]$1,332,539,889[/]");
|
||||
AnsiConsole.Render(table);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -21,3 +21,6 @@ dotnet_diagnostic.CA1034.severity = none
|
||||
|
||||
# CA2000: Dispose objects before losing scope
|
||||
dotnet_diagnostic.CA2000.severity = none
|
||||
|
||||
# SA1118: Parameter should not span multiple lines
|
||||
dotnet_diagnostic.SA1118.severity = none
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests
|
||||
{
|
||||
public partial class AnsiConsoleTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(Styles.Bold, "\u001b[1mHello World[0m")]
|
||||
[InlineData(Styles.Dim, "\u001b[2mHello World[0m")]
|
||||
[InlineData(Styles.Italic, "\u001b[3mHello World[0m")]
|
||||
[InlineData(Styles.Underline, "\u001b[4mHello World[0m")]
|
||||
[InlineData(Styles.Invert, "\u001b[7mHello World[0m")]
|
||||
[InlineData(Styles.Conceal, "\u001b[8mHello World[0m")]
|
||||
[InlineData(Styles.SlowBlink, "\u001b[5mHello World[0m")]
|
||||
[InlineData(Styles.RapidBlink, "\u001b[6mHello World[0m")]
|
||||
[InlineData(Styles.Strikethrough, "\u001b[9mHello World[0m")]
|
||||
public void Should_Write_Style_Correctly(Styles style, string expected)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
|
||||
fixture.Console.Style = style;
|
||||
|
||||
// When
|
||||
fixture.Console.Write("Hello World");
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(Styles.Bold | Styles.Underline, "\u001b[1;4mHello World[0m")]
|
||||
[InlineData(Styles.Bold | Styles.Underline | Styles.Conceal, "\u001b[1;4;8mHello World[0m")]
|
||||
public void Should_Write_Combined_Styles_Correctly(Styles style, string expected)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
|
||||
fixture.Console.Style = style;
|
||||
|
||||
// When
|
||||
fixture.Console.Write("Hello World");
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe(expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests
|
||||
{
|
||||
public partial class AnsiConsoleTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Combine_Style_And_Colors()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
|
||||
fixture.Console.Foreground = Color.RoyalBlue1;
|
||||
fixture.Console.Background = Color.NavajoWhite1;
|
||||
fixture.Console.Style = Styles.Italic;
|
||||
|
||||
// When
|
||||
fixture.Console.Write("Hello");
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("\u001b[3;90;47mHello\u001b[0m");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Not_Include_Foreground_If_Set_To_Default_Color()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
|
||||
fixture.Console.Foreground = Color.Default;
|
||||
fixture.Console.Background = Color.NavajoWhite1;
|
||||
fixture.Console.Style = Styles.Italic;
|
||||
|
||||
// When
|
||||
fixture.Console.Write("Hello");
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("\u001b[3;47mHello\u001b[0m");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Not_Include_Background_If_Set_To_Default_Color()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
|
||||
fixture.Console.Foreground = Color.RoyalBlue1;
|
||||
fixture.Console.Background = Color.Default;
|
||||
fixture.Console.Style = Styles.Italic;
|
||||
|
||||
// When
|
||||
fixture.Console.Write("Hello");
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("\u001b[3;90mHello\u001b[0m");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Not_Include_Style_If_Set_To_None()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
|
||||
fixture.Console.Foreground = Color.RoyalBlue1;
|
||||
fixture.Console.Background = Color.NavajoWhite1;
|
||||
fixture.Console.Style = Styles.None;
|
||||
|
||||
// When
|
||||
fixture.Console.Write("Hello");
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("\u001b[90;47mHello\u001b[0m");
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/Spectre.Console.Tests/Extensions/StringExtensions.cs
Normal file
13
src/Spectre.Console.Tests/Extensions/StringExtensions.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Tests
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string NormalizeLineEndings(this string text)
|
||||
{
|
||||
return text?.Replace("\r\n", "\n", StringComparison.OrdinalIgnoreCase)
|
||||
?.Replace("\r", string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,16 +11,17 @@ namespace Spectre.Console.Tests
|
||||
|
||||
public string Output => _writer.ToString();
|
||||
|
||||
public AnsiConsoleFixture(ColorSystem system)
|
||||
public AnsiConsoleFixture(ColorSystem system, AnsiSupport ansi = AnsiSupport.Yes, int width = 80)
|
||||
{
|
||||
_writer = new StringWriter();
|
||||
|
||||
Console = AnsiConsole.Create(new AnsiConsoleSettings
|
||||
{
|
||||
Ansi = AnsiSupport.Yes,
|
||||
ColorSystem = (ColorSystemSupport)system,
|
||||
Out = _writer,
|
||||
});
|
||||
Console = new ConsoleWithWidth(
|
||||
AnsiConsole.Create(new AnsiConsoleSettings
|
||||
{
|
||||
Ansi = ansi,
|
||||
ColorSystem = (ColorSystemSupport)system,
|
||||
Out = _writer,
|
||||
}), width);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
31
src/Spectre.Console.Tests/Fixtures/ConsoleWithWidth.cs
Normal file
31
src/Spectre.Console.Tests/Fixtures/ConsoleWithWidth.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Spectre.Console.Tests
|
||||
{
|
||||
public sealed class ConsoleWithWidth : IAnsiConsole
|
||||
{
|
||||
private readonly IAnsiConsole _console;
|
||||
|
||||
public Capabilities Capabilities => _console.Capabilities;
|
||||
|
||||
public int Width { get; }
|
||||
public int Height => _console.Height;
|
||||
|
||||
public Encoding Encoding => _console.Encoding;
|
||||
|
||||
public Decoration Decoration { get => _console.Decoration; set => _console.Decoration = value; }
|
||||
public Color Foreground { get => _console.Foreground; set => _console.Foreground = value; }
|
||||
public Color Background { get => _console.Background; set => _console.Background = value; }
|
||||
|
||||
public ConsoleWithWidth(IAnsiConsole console, int width)
|
||||
{
|
||||
_console = console;
|
||||
Width = width;
|
||||
}
|
||||
|
||||
public void Write(string text)
|
||||
{
|
||||
_console.Write(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
46
src/Spectre.Console.Tests/Fixtures/PlainConsole.cs
Normal file
46
src/Spectre.Console.Tests/Fixtures/PlainConsole.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Spectre.Console.Tests
|
||||
{
|
||||
public sealed class PlainConsole : IAnsiConsole, IDisposable
|
||||
{
|
||||
public Capabilities Capabilities { get; }
|
||||
public Encoding Encoding { get; }
|
||||
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
|
||||
public Decoration Decoration { get; set; }
|
||||
public Color Foreground { get; set; }
|
||||
public Color Background { get; set; }
|
||||
|
||||
public StringWriter Writer { get; }
|
||||
public string Output => Writer.ToString().TrimEnd('\n');
|
||||
public IReadOnlyList<string> Lines => Output.Split(new char[] { '\n' });
|
||||
|
||||
public PlainConsole(
|
||||
int width = 80, int height = 9000, Encoding encoding = null,
|
||||
bool supportsAnsi = true, ColorSystem colorSystem = ColorSystem.Standard,
|
||||
bool legacyConsole = false)
|
||||
{
|
||||
Capabilities = new Capabilities(supportsAnsi, colorSystem, legacyConsole);
|
||||
Encoding = encoding ?? Encoding.UTF8;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Writer = new StringWriter();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Writer.Dispose();
|
||||
}
|
||||
|
||||
public void Write(string text)
|
||||
{
|
||||
Writer.Write(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
public partial class AnsiConsoleTests
|
||||
{
|
||||
89
src/Spectre.Console.Tests/Unit/AnsiConsoleTests.Markup.cs
Normal file
89
src/Spectre.Console.Tests/Unit/AnsiConsoleTests.Markup.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
public partial class AnsiConsoleTests
|
||||
{
|
||||
[SuppressMessage("Naming", "CA1724:Type names should not match namespaces")]
|
||||
public sealed class Markup
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("[yellow]Hello[/]", "[93mHello[0m")]
|
||||
[InlineData("[yellow]Hello [italic]World[/]![/]", "[93mHello [0m[3;93mWorld[0m[93m![0m")]
|
||||
public void Should_Output_Expected_Ansi_For_Markup(string markup, string expected)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
|
||||
|
||||
// When
|
||||
fixture.Console.Markup(markup);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("[yellow]Hello [[ World[/]", "[93mHello [0m[93m[[0m[93m World[0m")]
|
||||
public void Should_Be_Able_To_Escape_Tags(string markup, string expected)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
|
||||
|
||||
// When
|
||||
fixture.Console.Markup(markup);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("[yellow]Hello[", "Encountered malformed markup tag at position 14.")]
|
||||
[InlineData("[yellow]Hello[/", "Encountered malformed markup tag at position 15.")]
|
||||
[InlineData("[yellow]Hello[/foo", "Encountered malformed markup tag at position 15.")]
|
||||
[InlineData("[yellow Hello", "Encountered malformed markup tag at position 13.")]
|
||||
public void Should_Throw_If_Encounters_Malformed_Tag(string markup, string expected)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => fixture.Console.Markup(markup));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>()
|
||||
.Message.ShouldBe(expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Tags_Are_Unbalanced()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => fixture.Console.Markup("[yellow][blue]Hello[/]"));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>()
|
||||
.Message.ShouldBe("Unbalanced markup stack. Did you forget to close a tag?");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Encounters_Closing_Tag()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => fixture.Console.Markup("Hello[/]World"));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>()
|
||||
.Message.ShouldBe("Encountered closing tag when none was expected near position 5.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/Spectre.Console.Tests/Unit/AnsiConsoleTests.Style.cs
Normal file
47
src/Spectre.Console.Tests/Unit/AnsiConsoleTests.Style.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
public partial class AnsiConsoleTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(Decoration.Bold, "\u001b[1mHello World[0m")]
|
||||
[InlineData(Decoration.Dim, "\u001b[2mHello World[0m")]
|
||||
[InlineData(Decoration.Italic, "\u001b[3mHello World[0m")]
|
||||
[InlineData(Decoration.Underline, "\u001b[4mHello World[0m")]
|
||||
[InlineData(Decoration.Invert, "\u001b[7mHello World[0m")]
|
||||
[InlineData(Decoration.Conceal, "\u001b[8mHello World[0m")]
|
||||
[InlineData(Decoration.SlowBlink, "\u001b[5mHello World[0m")]
|
||||
[InlineData(Decoration.RapidBlink, "\u001b[6mHello World[0m")]
|
||||
[InlineData(Decoration.Strikethrough, "\u001b[9mHello World[0m")]
|
||||
public void Should_Write_Decorated_Text_Correctly(Decoration decoration, string expected)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
|
||||
fixture.Console.Decoration = decoration;
|
||||
|
||||
// When
|
||||
fixture.Console.Write("Hello World");
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(Decoration.Bold | Decoration.Underline, "\u001b[1;4mHello World[0m")]
|
||||
[InlineData(Decoration.Bold | Decoration.Underline | Decoration.Conceal, "\u001b[1;4;8mHello World[0m")]
|
||||
public void Should_Write_Text_With_Multiple_Decorations_Correctly(Decoration decoration, string expected)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
|
||||
fixture.Console.Decoration = decoration;
|
||||
|
||||
// When
|
||||
fixture.Console.Write("Hello World");
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe(expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
452
src/Spectre.Console.Tests/Unit/AnsiConsoleTests.cs
Normal file
452
src/Spectre.Console.Tests/Unit/AnsiConsoleTests.cs
Normal file
@@ -0,0 +1,452 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
public partial class AnsiConsoleTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Combine_Decoration_And_Colors()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
|
||||
fixture.Console.Foreground = Color.RoyalBlue1;
|
||||
fixture.Console.Background = Color.NavajoWhite1;
|
||||
fixture.Console.Decoration = Decoration.Italic;
|
||||
|
||||
// When
|
||||
fixture.Console.Write("Hello");
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("\u001b[3;90;47mHello\u001b[0m");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Not_Include_Foreground_If_Set_To_Default_Color()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
|
||||
fixture.Console.Foreground = Color.Default;
|
||||
fixture.Console.Background = Color.NavajoWhite1;
|
||||
fixture.Console.Decoration = Decoration.Italic;
|
||||
|
||||
// When
|
||||
fixture.Console.Write("Hello");
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("\u001b[3;47mHello\u001b[0m");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Not_Include_Background_If_Set_To_Default_Color()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
|
||||
fixture.Console.Foreground = Color.RoyalBlue1;
|
||||
fixture.Console.Background = Color.Default;
|
||||
fixture.Console.Decoration = Decoration.Italic;
|
||||
|
||||
// When
|
||||
fixture.Console.Write("Hello");
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("\u001b[3;90mHello\u001b[0m");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Not_Include_Decoration_If_Set_To_None()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
|
||||
fixture.Console.Foreground = Color.RoyalBlue1;
|
||||
fixture.Console.Background = Color.NavajoWhite1;
|
||||
fixture.Console.Decoration = Decoration.None;
|
||||
|
||||
// When
|
||||
fixture.Console.Write("Hello");
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("\u001b[90;47mHello\u001b[0m");
|
||||
}
|
||||
|
||||
public sealed class Write
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Int32_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.Write(CultureInfo.InvariantCulture, 32);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_UInt32_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.Write(CultureInfo.InvariantCulture, 32U);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Int64_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.Write(CultureInfo.InvariantCulture, 32L);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_UInt64_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.Write(CultureInfo.InvariantCulture, 32UL);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Single_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.Write(CultureInfo.InvariantCulture, 32.432F);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32.432");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Double_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.Write(CultureInfo.InvariantCulture, (double)32.432);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32.432");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Decimal_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.Write(CultureInfo.InvariantCulture, 32.432M);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32.432");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Boolean_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.Write(CultureInfo.InvariantCulture, true);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("True");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Char_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.Write(CultureInfo.InvariantCulture, 'P');
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("P");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Char_Array_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.Write(
|
||||
CultureInfo.InvariantCulture,
|
||||
new[] { 'P', 'a', 't', 'r', 'i', 'k' });
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("Patrik");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Formatted_String_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.Write(
|
||||
CultureInfo.InvariantCulture,
|
||||
"Hello {0}! {1}",
|
||||
"World", 32);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("Hello World! 32");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WriteLine
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Reset_Colors_Correctly_After_Line_Break()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
|
||||
|
||||
// When
|
||||
fixture.Console.Background = ConsoleColor.Red;
|
||||
fixture.Console.WriteLine("Hello");
|
||||
fixture.Console.Background = ConsoleColor.Green;
|
||||
fixture.Console.WriteLine("World");
|
||||
|
||||
// Then
|
||||
fixture.Output.NormalizeLineEndings()
|
||||
.ShouldBe("[101mHello[0m\n[102mWorld[0m\n");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Reset_Colors_Correctly_After_Line_Break_In_Text()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
|
||||
|
||||
// When
|
||||
fixture.Console.Background = ConsoleColor.Red;
|
||||
fixture.Console.WriteLine("Hello\nWorld");
|
||||
|
||||
// Then
|
||||
fixture.Output.NormalizeLineEndings()
|
||||
.ShouldBe("[101mHello[0m\n[101mWorld[0m\n");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Int32_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 32);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32" + Environment.NewLine);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_UInt32_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 32U);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32" + Environment.NewLine);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Int64_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 32L);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32" + Environment.NewLine);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_UInt64_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 32UL);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32" + Environment.NewLine);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Single_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 32.432F);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32.432" + Environment.NewLine);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Double_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.WriteLine(CultureInfo.InvariantCulture, (double)32.432);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32.432" + Environment.NewLine);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Decimal_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 32.432M);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("32.432" + Environment.NewLine);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Boolean_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.WriteLine(CultureInfo.InvariantCulture, true);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("True" + Environment.NewLine);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Char_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 'P');
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("P" + Environment.NewLine);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Char_Array_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.WriteLine(
|
||||
CultureInfo.InvariantCulture,
|
||||
new[] { 'P', 'a', 't', 'r', 'i', 'k' });
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("Patrik" + Environment.NewLine);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AnsiSupport.Yes)]
|
||||
[InlineData(AnsiSupport.No)]
|
||||
public void Should_Write_Formatted_String_With_Format_Provider(AnsiSupport ansi)
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
|
||||
|
||||
// When
|
||||
fixture.Console.WriteLine(
|
||||
CultureInfo.InvariantCulture,
|
||||
"Hello {0}! {1}",
|
||||
"World", 32);
|
||||
|
||||
// Then
|
||||
fixture.Output.ShouldBe("Hello World! 32" + Environment.NewLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
254
src/Spectre.Console.Tests/Unit/ColorTests.cs
Normal file
254
src/Spectre.Console.Tests/Unit/ColorTests.cs
Normal file
@@ -0,0 +1,254 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
public sealed class ColorTests
|
||||
{
|
||||
public sealed class TheEqualsMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Consider_Color_And_Non_Color_Equal()
|
||||
{
|
||||
// Given
|
||||
var color1 = new Color(128, 0, 128);
|
||||
|
||||
// When
|
||||
var result = color1.Equals("Foo");
|
||||
|
||||
// Then
|
||||
result.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Consider_Same_Colors_Equal_By_Component()
|
||||
{
|
||||
// Given
|
||||
var color1 = new Color(128, 0, 128);
|
||||
var color2 = new Color(128, 0, 128);
|
||||
|
||||
// When
|
||||
var result = color1.Equals(color2);
|
||||
|
||||
// Then
|
||||
result.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Consider_Same_Known_Colors_Equal()
|
||||
{
|
||||
// Given
|
||||
var color1 = Color.Cyan1;
|
||||
var color2 = Color.Cyan1;
|
||||
|
||||
// When
|
||||
var result = color1.Equals(color2);
|
||||
|
||||
// Then
|
||||
result.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Consider_Known_Color_And_Color_With_Same_Components_Equal()
|
||||
{
|
||||
// Given
|
||||
var color1 = Color.Cyan1;
|
||||
var color2 = new Color(0, 255, 255);
|
||||
|
||||
// When
|
||||
var result = color1.Equals(color2);
|
||||
|
||||
// Then
|
||||
result.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Not_Consider_Different_Colors_Equal()
|
||||
{
|
||||
// Given
|
||||
var color1 = new Color(128, 0, 128);
|
||||
var color2 = new Color(128, 128, 128);
|
||||
|
||||
// When
|
||||
var result = color1.Equals(color2);
|
||||
|
||||
// Then
|
||||
result.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Shourd_Not_Consider_Black_And_Default_Colors_Equal()
|
||||
{
|
||||
// Given
|
||||
var color1 = Color.Default;
|
||||
var color2 = Color.Black;
|
||||
|
||||
// When
|
||||
var result = color1.Equals(color2);
|
||||
|
||||
// Then
|
||||
result.ShouldBeFalse();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TheGetHashCodeMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Return_Same_HashCode_For_Same_Colors()
|
||||
{
|
||||
// Given
|
||||
var color1 = new Color(128, 0, 128);
|
||||
var color2 = new Color(128, 0, 128);
|
||||
|
||||
// When
|
||||
var hash1 = color1.GetHashCode();
|
||||
var hash2 = color2.GetHashCode();
|
||||
|
||||
// Then
|
||||
hash1.ShouldBe(hash2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Return_Different_HashCode_For_Different_Colors()
|
||||
{
|
||||
// Given
|
||||
var color1 = new Color(128, 0, 128);
|
||||
var color2 = new Color(128, 128, 128);
|
||||
|
||||
// When
|
||||
var hash1 = color1.GetHashCode();
|
||||
var hash2 = color2.GetHashCode();
|
||||
|
||||
// Then
|
||||
hash1.ShouldNotBe(hash2);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ImplicitConversions
|
||||
{
|
||||
public sealed class Int32ToColor
|
||||
{
|
||||
public static IEnumerable<object[]> Data =>
|
||||
Enumerable.Range(0, 255)
|
||||
.Select(number => new object[] { number });
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(Data))]
|
||||
public void Should_Return_Expected_Color(int number)
|
||||
{
|
||||
// Given, When
|
||||
var result = (Color)number;
|
||||
|
||||
// Then
|
||||
result.ShouldBe(Color.FromInt32(number));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Integer_Is_Lower_Than_Zero()
|
||||
{
|
||||
// Given, When
|
||||
var result = Record.Exception(() => (Color)(-1));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>();
|
||||
result.Message.ShouldBe("Color number must be between 0 and 255");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Integer_Is_Higher_Than_255()
|
||||
{
|
||||
// Given, When
|
||||
var result = Record.Exception(() => (Color)256);
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>();
|
||||
result.Message.ShouldBe("Color number must be between 0 and 255");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ConsoleColorToColor
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(ConsoleColor.Black, 0)]
|
||||
[InlineData(ConsoleColor.DarkRed, 1)]
|
||||
[InlineData(ConsoleColor.DarkGreen, 2)]
|
||||
[InlineData(ConsoleColor.DarkYellow, 3)]
|
||||
[InlineData(ConsoleColor.DarkBlue, 4)]
|
||||
[InlineData(ConsoleColor.DarkMagenta, 5)]
|
||||
[InlineData(ConsoleColor.DarkCyan, 6)]
|
||||
[InlineData(ConsoleColor.Gray, 7)]
|
||||
[InlineData(ConsoleColor.DarkGray, 8)]
|
||||
[InlineData(ConsoleColor.Red, 9)]
|
||||
[InlineData(ConsoleColor.Green, 10)]
|
||||
[InlineData(ConsoleColor.Yellow, 11)]
|
||||
[InlineData(ConsoleColor.Blue, 12)]
|
||||
[InlineData(ConsoleColor.Magenta, 13)]
|
||||
[InlineData(ConsoleColor.Cyan, 14)]
|
||||
[InlineData(ConsoleColor.White, 15)]
|
||||
public void Should_Return_Expected_Color(ConsoleColor color, int expected)
|
||||
{
|
||||
// Given, When
|
||||
var result = (Color)color;
|
||||
|
||||
// Then
|
||||
result.ShouldBe(Color.FromInt32(expected));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ColorToConsoleColor
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0, ConsoleColor.Black)]
|
||||
[InlineData(1, ConsoleColor.DarkRed)]
|
||||
[InlineData(2, ConsoleColor.DarkGreen)]
|
||||
[InlineData(3, ConsoleColor.DarkYellow)]
|
||||
[InlineData(4, ConsoleColor.DarkBlue)]
|
||||
[InlineData(5, ConsoleColor.DarkMagenta)]
|
||||
[InlineData(6, ConsoleColor.DarkCyan)]
|
||||
[InlineData(7, ConsoleColor.Gray)]
|
||||
[InlineData(8, ConsoleColor.DarkGray)]
|
||||
[InlineData(9, ConsoleColor.Red)]
|
||||
[InlineData(10, ConsoleColor.Green)]
|
||||
[InlineData(11, ConsoleColor.Yellow)]
|
||||
[InlineData(12, ConsoleColor.Blue)]
|
||||
[InlineData(13, ConsoleColor.Magenta)]
|
||||
[InlineData(14, ConsoleColor.Cyan)]
|
||||
[InlineData(15, ConsoleColor.White)]
|
||||
public void Should_Return_Expected_ConsoleColor_For_Known_Color(int color, ConsoleColor expected)
|
||||
{
|
||||
// Given, When
|
||||
var result = (ConsoleColor)Color.FromInt32(color);
|
||||
|
||||
// Then
|
||||
result.ShouldBe(expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TheToStringMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Return_Color_Name_For_Known_Colors()
|
||||
{
|
||||
// Given, When
|
||||
var name = Color.Fuchsia.ToString();
|
||||
|
||||
// Then
|
||||
name.ShouldBe("fuchsia");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Return_Hex_String_For_Unknown_Colors()
|
||||
{
|
||||
// Given, When
|
||||
var name = new Color(128, 0, 128).ToString();
|
||||
|
||||
// Then
|
||||
name.ShouldBe("#800080 (RGB=128,0,128)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
src/Spectre.Console.Tests/Unit/Composition/BorderTests.cs
Normal file
42
src/Spectre.Console.Tests/Unit/Composition/BorderTests.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using Shouldly;
|
||||
using Spectre.Console.Composition;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Composition
|
||||
{
|
||||
public sealed class BorderTests
|
||||
{
|
||||
public sealed class TheGetBorderMethod
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(BorderKind.None, false, typeof(NoBorder))]
|
||||
[InlineData(BorderKind.Ascii, false, typeof(AsciiBorder))]
|
||||
[InlineData(BorderKind.Square, false, typeof(SquareBorder))]
|
||||
[InlineData(BorderKind.Rounded, false, typeof(RoundedBorder))]
|
||||
[InlineData(BorderKind.None, true, typeof(NoBorder))]
|
||||
[InlineData(BorderKind.Ascii, true, typeof(AsciiBorder))]
|
||||
[InlineData(BorderKind.Square, true, typeof(SquareBorder))]
|
||||
[InlineData(BorderKind.Rounded, true, typeof(SquareBorder))]
|
||||
public void Should_Return_Correct_Border_For_Specified_Kind(BorderKind kind, bool safe, Type expected)
|
||||
{
|
||||
// Given, When
|
||||
var result = Border.GetBorder(kind, safe);
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType(expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Unknown_Border_Kind_Is_Specified()
|
||||
{
|
||||
// Given, When
|
||||
var result = Record.Exception(() => Border.GetBorder((BorderKind)int.MaxValue, false));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>();
|
||||
result.Message.ShouldBe("Unknown border kind");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
145
src/Spectre.Console.Tests/Unit/Composition/GridTests.cs
Normal file
145
src/Spectre.Console.Tests/Unit/Composition/GridTests.cs
Normal file
@@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Composition
|
||||
{
|
||||
public sealed class GridTests
|
||||
{
|
||||
public sealed class TheAddRowMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Throw_If_Rows_Are_Null()
|
||||
{
|
||||
// Given
|
||||
var grid = new Grid();
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => grid.AddRow(null));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<ArgumentNullException>()
|
||||
.ParamName.ShouldBe("columns");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Row_Columns_Is_Less_Than_Number_Of_Columns()
|
||||
{
|
||||
// Given
|
||||
var grid = new Grid();
|
||||
grid.AddColumn();
|
||||
grid.AddColumn();
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => grid.AddRow("Foo"));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>();
|
||||
result.Message.ShouldBe("The number of row columns are less than the number of grid columns.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Row_Columns_Are_Greater_Than_Number_Of_Columns()
|
||||
{
|
||||
// Given
|
||||
var grid = new Grid();
|
||||
grid.AddColumn();
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => grid.AddRow("Foo", "Bar"));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>();
|
||||
result.Message.ShouldBe("The number of row columns are greater than the number of grid columns.");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Grid_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var grid = new Grid();
|
||||
grid.AddColumn();
|
||||
grid.AddColumn();
|
||||
grid.AddColumn();
|
||||
grid.AddRow("Qux", "Corgi", "Waldo");
|
||||
grid.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
// When
|
||||
console.Render(grid);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(2);
|
||||
console.Lines[0].ShouldBe("Qux Corgi Waldo");
|
||||
console.Lines[1].ShouldBe("Grault Garply Fred ");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Grid_Column_Alignment_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var grid = new Grid();
|
||||
grid.AddColumn(new GridColumn { Alignment = Justify.Right });
|
||||
grid.AddColumn(new GridColumn { Alignment = Justify.Center });
|
||||
grid.AddColumn(new GridColumn { Alignment = Justify.Left });
|
||||
grid.AddRow("Foo", "Bar", "Baz");
|
||||
grid.AddRow("Qux", "Corgi", "Waldo");
|
||||
grid.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
// When
|
||||
console.Render(grid);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(3);
|
||||
console.Lines[0].ShouldBe(" Foo Bar Baz ");
|
||||
console.Lines[1].ShouldBe(" Qux Corgi Waldo");
|
||||
console.Lines[2].ShouldBe("Grault Garply Fred ");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Grid_Column_Padding_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var grid = new Grid();
|
||||
grid.AddColumn(new GridColumn { Padding = new Padding(3, 0) });
|
||||
grid.AddColumns(2);
|
||||
grid.AddRow("Foo", "Bar", "Baz");
|
||||
grid.AddRow("Qux", "Corgi", "Waldo");
|
||||
grid.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
// When
|
||||
console.Render(grid);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(3);
|
||||
console.Lines[0].ShouldBe(" Foo Bar Baz ");
|
||||
console.Lines[1].ShouldBe(" Qux Corgi Waldo");
|
||||
console.Lines[2].ShouldBe(" Grault Garply Fred ");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Grid()
|
||||
{
|
||||
var console = new PlainConsole(width: 80);
|
||||
var grid = new Grid();
|
||||
grid.AddColumn(new GridColumn { NoWrap = true });
|
||||
grid.AddColumn(new GridColumn { Padding = new Padding(2, 0) });
|
||||
grid.AddRow("[bold]Options[/]", string.Empty);
|
||||
grid.AddRow(" [blue]-h[/], [blue]--help[/]", "Show command line help.");
|
||||
grid.AddRow(" [blue]-c[/], [blue]--configuration[/]", "The configuration to run for.\nThe default for most projects is [green]Debug[/].");
|
||||
|
||||
// When
|
||||
console.Render(grid);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(4);
|
||||
console.Lines[0].ShouldBe("Options ");
|
||||
console.Lines[1].ShouldBe(" -h, --help Show command line help. ");
|
||||
console.Lines[2].ShouldBe(" -c, --configuration The configuration to run for. ");
|
||||
console.Lines[3].ShouldBe(" The default for most projects is Debug.");
|
||||
}
|
||||
}
|
||||
}
|
||||
180
src/Spectre.Console.Tests/Unit/Composition/PanelTests.cs
Normal file
180
src/Spectre.Console.Tests/Unit/Composition/PanelTests.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
public sealed class PanelTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Render_Panel()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
|
||||
// When
|
||||
console.Render(new Panel(Text.New("Hello World")));
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(3);
|
||||
console.Lines[0].ShouldBe("┌─────────────┐");
|
||||
console.Lines[1].ShouldBe("│ Hello World │");
|
||||
console.Lines[2].ShouldBe("└─────────────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Panel_With_Padding()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
|
||||
// When
|
||||
console.Render(new Panel(Text.New("Hello World"))
|
||||
{
|
||||
Padding = new Padding(3, 5),
|
||||
});
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(3);
|
||||
console.Lines[0].ShouldBe("┌───────────────────┐");
|
||||
console.Lines[1].ShouldBe("│ Hello World │");
|
||||
console.Lines[2].ShouldBe("└───────────────────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Panel_With_Unicode_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
|
||||
// When
|
||||
console.Render(new Panel(Text.New(" \n💩\n ")));
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(5);
|
||||
console.Lines[0].ShouldBe("┌────┐");
|
||||
console.Lines[1].ShouldBe("│ │");
|
||||
console.Lines[2].ShouldBe("│ 💩 │");
|
||||
console.Lines[3].ShouldBe("│ │");
|
||||
console.Lines[4].ShouldBe("└────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Panel_With_Multiple_Lines()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
|
||||
// When
|
||||
console.Render(new Panel(Text.New("Hello World\nFoo Bar")));
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(4);
|
||||
console.Lines[0].ShouldBe("┌─────────────┐");
|
||||
console.Lines[1].ShouldBe("│ Hello World │");
|
||||
console.Lines[2].ShouldBe("│ Foo Bar │");
|
||||
console.Lines[3].ShouldBe("└─────────────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Preserve_Explicit_Line_Ending()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var text = new Panel(
|
||||
Text.New("I heard [underline on blue]you[/] like 📦\n\n\n\nSo I put a 📦 in a 📦"));
|
||||
|
||||
// When
|
||||
console.Render(text);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(7);
|
||||
console.Lines[0].ShouldBe("┌───────────────────────┐");
|
||||
console.Lines[1].ShouldBe("│ I heard you like 📦 │");
|
||||
console.Lines[2].ShouldBe("│ │");
|
||||
console.Lines[3].ShouldBe("│ │");
|
||||
console.Lines[4].ShouldBe("│ │");
|
||||
console.Lines[5].ShouldBe("│ So I put a 📦 in a 📦 │");
|
||||
console.Lines[6].ShouldBe("└───────────────────────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Expand_Panel_If_Enabled()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
|
||||
// When
|
||||
console.Render(new Panel(Text.New("Hello World"))
|
||||
{
|
||||
Expand = true,
|
||||
});
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(3);
|
||||
console.Lines[0].Length.ShouldBe(80);
|
||||
console.Lines[0].ShouldBe("┌──────────────────────────────────────────────────────────────────────────────┐");
|
||||
console.Lines[1].ShouldBe("│ Hello World │");
|
||||
console.Lines[2].ShouldBe("└──────────────────────────────────────────────────────────────────────────────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Justify_Child_To_Right()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 25);
|
||||
|
||||
// When
|
||||
console.Render(
|
||||
new Panel(
|
||||
Text.New("Hello World").WithAlignment(Justify.Right))
|
||||
{
|
||||
Expand = true,
|
||||
});
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(3);
|
||||
console.Lines[0].ShouldBe("┌───────────────────────┐");
|
||||
console.Lines[1].ShouldBe("│ Hello World │");
|
||||
console.Lines[2].ShouldBe("└───────────────────────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Justify_Child_To_Center()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 25);
|
||||
|
||||
// When
|
||||
console.Render(
|
||||
new Panel(
|
||||
Text.New("Hello World").WithAlignment(Justify.Center))
|
||||
{
|
||||
Expand = true,
|
||||
});
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(3);
|
||||
console.Lines[0].ShouldBe("┌───────────────────────┐");
|
||||
console.Lines[1].ShouldBe("│ Hello World │");
|
||||
console.Lines[2].ShouldBe("└───────────────────────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Panel_Inside_Panel_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
|
||||
// When
|
||||
console.Render(new Panel(new Panel(Text.New("Hello World"))));
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(5);
|
||||
console.Lines[0].ShouldBe("┌─────────────────┐");
|
||||
console.Lines[1].ShouldBe("│ ┌─────────────┐ │");
|
||||
console.Lines[2].ShouldBe("│ │ Hello World │ │");
|
||||
console.Lines[3].ShouldBe("│ └─────────────┘ │");
|
||||
console.Lines[4].ShouldBe("└─────────────────┘");
|
||||
}
|
||||
}
|
||||
}
|
||||
92
src/Spectre.Console.Tests/Unit/Composition/SegmentTests.cs
Normal file
92
src/Spectre.Console.Tests/Unit/Composition/SegmentTests.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Composition;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
public sealed class SegmentTests
|
||||
{
|
||||
public sealed class TheSplitMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Split_Segment_Correctly()
|
||||
{
|
||||
// Given
|
||||
var style = new Style(Color.Red, Color.Green, Decoration.Bold);
|
||||
var segment = new Segment("Foo Bar", style);
|
||||
|
||||
// When
|
||||
var (first, second) = segment.Split(3);
|
||||
|
||||
// Then
|
||||
first.Text.ShouldBe("Foo");
|
||||
first.Style.ShouldBe(style);
|
||||
second.Text.ShouldBe(" Bar");
|
||||
second.Style.ShouldBe(style);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TheSplitLinesMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Split_Segment()
|
||||
{
|
||||
var lines = Segment.SplitLines(
|
||||
new[]
|
||||
{
|
||||
new Segment("Foo"),
|
||||
new Segment("Bar"),
|
||||
new Segment("\n"),
|
||||
new Segment("Baz"),
|
||||
new Segment("Qux"),
|
||||
new Segment("\n"),
|
||||
new Segment("Corgi"),
|
||||
});
|
||||
|
||||
// Then
|
||||
lines.Count.ShouldBe(3);
|
||||
|
||||
lines[0].Count.ShouldBe(2);
|
||||
lines[0][0].Text.ShouldBe("Foo");
|
||||
lines[0][1].Text.ShouldBe("Bar");
|
||||
|
||||
lines[1].Count.ShouldBe(2);
|
||||
lines[1][0].Text.ShouldBe("Baz");
|
||||
lines[1][1].Text.ShouldBe("Qux");
|
||||
|
||||
lines[2].Count.ShouldBe(1);
|
||||
lines[2][0].Text.ShouldBe("Corgi");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Split_Segments_With_Linebreak_In_Text()
|
||||
{
|
||||
var lines = Segment.SplitLines(
|
||||
new[]
|
||||
{
|
||||
new Segment("Foo\n"),
|
||||
new Segment("Bar\n"),
|
||||
new Segment("Baz"),
|
||||
new Segment("Qux\n"),
|
||||
new Segment("Corgi"),
|
||||
});
|
||||
|
||||
// Then
|
||||
lines.Count.ShouldBe(4);
|
||||
|
||||
lines[0].Count.ShouldBe(1);
|
||||
lines[0][0].Text.ShouldBe("Foo");
|
||||
|
||||
lines[1].Count.ShouldBe(1);
|
||||
lines[1][0].Text.ShouldBe("Bar");
|
||||
|
||||
lines[2].Count.ShouldBe(2);
|
||||
lines[2][0].Text.ShouldBe("Baz");
|
||||
lines[2][1].Text.ShouldBe("Qux");
|
||||
|
||||
lines[3].Count.ShouldBe(1);
|
||||
lines[3][0].Text.ShouldBe("Corgi");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
330
src/Spectre.Console.Tests/Unit/Composition/TableTests.cs
Normal file
330
src/Spectre.Console.Tests/Unit/Composition/TableTests.cs
Normal file
@@ -0,0 +1,330 @@
|
||||
using System;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Composition
|
||||
{
|
||||
public sealed class TableTests
|
||||
{
|
||||
public sealed class TheAddColumnMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Throw_If_Column_Is_Null()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => table.AddColumn((string)null));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<ArgumentNullException>()
|
||||
.ParamName.ShouldBe("column");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TheAddColumnsMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Throw_If_Columns_Are_Null()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => table.AddColumns((string[])null));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<ArgumentNullException>()
|
||||
.ParamName.ShouldBe("columns");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TheAddRowMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Throw_If_Rows_Are_Null()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => table.AddRow(null));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<ArgumentNullException>()
|
||||
.ParamName.ShouldBe("columns");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Row_Columns_Is_Less_Than_Number_Of_Columns()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
table.AddColumn("Hello");
|
||||
table.AddColumn("World");
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => table.AddRow("Foo"));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>();
|
||||
result.Message.ShouldBe("The number of row columns are less than the number of table columns.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Row_Columns_Are_Greater_Than_Number_Of_Columns()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
table.AddColumn("Hello");
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => table.AddRow("Foo", "Bar"));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>();
|
||||
result.Message.ShouldBe("The number of row columns are greater than the number of table columns.");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Table_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var table = new Table();
|
||||
table.AddColumns("Foo", "Bar", "Baz");
|
||||
table.AddRow("Qux", "Corgi", "Waldo");
|
||||
table.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
// When
|
||||
console.Render(table);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(6);
|
||||
console.Lines[0].ShouldBe("┌────────┬────────┬───────┐");
|
||||
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
|
||||
console.Lines[2].ShouldBe("├────────┼────────┼───────┤");
|
||||
console.Lines[3].ShouldBe("│ Qux │ Corgi │ Waldo │");
|
||||
console.Lines[4].ShouldBe("│ Grault │ Garply │ Fred │");
|
||||
console.Lines[5].ShouldBe("└────────┴────────┴───────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Table_Nested_In_Panels_Correctly()
|
||||
{
|
||||
// A simple table
|
||||
var console = new PlainConsole(width: 80);
|
||||
var table = new Table() { Border = BorderKind.Rounded };
|
||||
table.AddColumn("Foo");
|
||||
table.AddColumn("Bar");
|
||||
table.AddColumn(new TableColumn("Baz") { Alignment = Justify.Right });
|
||||
table.AddRow("Qux\nQuuuuuux", "[blue]Corgi[/]", "Waldo");
|
||||
table.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
// Render a table in some panels.
|
||||
console.Render(new Panel(new Panel(table)
|
||||
{
|
||||
Border = BorderKind.Ascii,
|
||||
}));
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(11);
|
||||
console.Lines[00].ShouldBe("┌───────────────────────────────────┐");
|
||||
console.Lines[01].ShouldBe("│ +-------------------------------+ │");
|
||||
console.Lines[02].ShouldBe("│ | ╭──────────┬────────┬───────╮ | │");
|
||||
console.Lines[03].ShouldBe("│ | │ Foo │ Bar │ Baz │ | │");
|
||||
console.Lines[04].ShouldBe("│ | ├──────────┼────────┼───────┤ | │");
|
||||
console.Lines[05].ShouldBe("│ | │ Qux │ Corgi │ Waldo │ | │");
|
||||
console.Lines[06].ShouldBe("│ | │ Quuuuuux │ │ │ | │");
|
||||
console.Lines[07].ShouldBe("│ | │ Grault │ Garply │ Fred │ | │");
|
||||
console.Lines[08].ShouldBe("│ | ╰──────────┴────────┴───────╯ | │");
|
||||
console.Lines[09].ShouldBe("│ +-------------------------------+ │");
|
||||
console.Lines[10].ShouldBe("└───────────────────────────────────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Table_With_Column_Justification_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var table = new Table();
|
||||
table.AddColumn(new TableColumn("Foo") { Alignment = Justify.Left });
|
||||
table.AddColumn(new TableColumn("Bar") { Alignment = Justify.Right });
|
||||
table.AddColumn(new TableColumn("Baz") { Alignment = Justify.Center });
|
||||
table.AddRow("Qux", "Corgi", "Waldo");
|
||||
table.AddRow("Grault", "Garply", "Lorem ipsum dolor sit amet");
|
||||
|
||||
// When
|
||||
console.Render(table);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(6);
|
||||
console.Lines[0].ShouldBe("┌────────┬────────┬────────────────────────────┐");
|
||||
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
|
||||
console.Lines[2].ShouldBe("├────────┼────────┼────────────────────────────┤");
|
||||
console.Lines[3].ShouldBe("│ Qux │ Corgi │ Waldo │");
|
||||
console.Lines[4].ShouldBe("│ Grault │ Garply │ Lorem ipsum dolor sit amet │");
|
||||
console.Lines[5].ShouldBe("└────────┴────────┴────────────────────────────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Expand_Table_To_Available_Space_If_Specified()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var table = new Table() { Expand = true };
|
||||
table.AddColumns("Foo", "Bar", "Baz");
|
||||
table.AddRow("Qux", "Corgi", "Waldo");
|
||||
table.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
// When
|
||||
console.Render(table);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(6);
|
||||
console.Lines[0].Length.ShouldBe(80);
|
||||
console.Lines[0].ShouldBe("┌───────────────────────────┬───────────────────────────┬──────────────────────┐");
|
||||
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
|
||||
console.Lines[2].ShouldBe("├───────────────────────────┼───────────────────────────┼──────────────────────┤");
|
||||
console.Lines[3].ShouldBe("│ Qux │ Corgi │ Waldo │");
|
||||
console.Lines[4].ShouldBe("│ Grault │ Garply │ Fred │");
|
||||
console.Lines[5].ShouldBe("└───────────────────────────┴───────────────────────────┴──────────────────────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Table_With_Ascii_Border_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var table = new Table { Border = BorderKind.Ascii };
|
||||
table.AddColumns("Foo", "Bar", "Baz");
|
||||
table.AddRow("Qux", "Corgi", "Waldo");
|
||||
table.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
// When
|
||||
console.Render(table);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(6);
|
||||
console.Lines[0].ShouldBe("+-------------------------+");
|
||||
console.Lines[1].ShouldBe("| Foo | Bar | Baz |");
|
||||
console.Lines[2].ShouldBe("|--------+--------+-------|");
|
||||
console.Lines[3].ShouldBe("| Qux | Corgi | Waldo |");
|
||||
console.Lines[4].ShouldBe("| Grault | Garply | Fred |");
|
||||
console.Lines[5].ShouldBe("+-------------------------+");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Table_With_Rounded_Border_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var table = new Table { Border = BorderKind.Rounded };
|
||||
table.AddColumns("Foo", "Bar", "Baz");
|
||||
table.AddRow("Qux", "Corgi", "Waldo");
|
||||
table.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
// When
|
||||
console.Render(table);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(6);
|
||||
console.Lines[0].ShouldBe("╭────────┬────────┬───────╮");
|
||||
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
|
||||
console.Lines[2].ShouldBe("├────────┼────────┼───────┤");
|
||||
console.Lines[3].ShouldBe("│ Qux │ Corgi │ Waldo │");
|
||||
console.Lines[4].ShouldBe("│ Grault │ Garply │ Fred │");
|
||||
console.Lines[5].ShouldBe("╰────────┴────────┴───────╯");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Table_With_No_Border_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var table = new Table { Border = BorderKind.None };
|
||||
table.AddColumns("Foo", "Bar", "Baz");
|
||||
table.AddRow("Qux", "Corgi", "Waldo");
|
||||
table.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
// When
|
||||
console.Render(table);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(3);
|
||||
console.Lines[0].ShouldBe("Foo Bar Baz ");
|
||||
console.Lines[1].ShouldBe("Qux Corgi Waldo");
|
||||
console.Lines[2].ShouldBe("Grault Garply Fred ");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Table_With_Multiple_Rows_In_Cell_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var table = new Table();
|
||||
table.AddColumns("Foo", "Bar", "Baz");
|
||||
table.AddRow("Qux\nQuuux", "Corgi", "Waldo");
|
||||
table.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
// When
|
||||
console.Render(table);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(7);
|
||||
console.Lines[0].ShouldBe("┌────────┬────────┬───────┐");
|
||||
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
|
||||
console.Lines[2].ShouldBe("├────────┼────────┼───────┤");
|
||||
console.Lines[3].ShouldBe("│ Qux │ Corgi │ Waldo │");
|
||||
console.Lines[4].ShouldBe("│ Quuux │ │ │");
|
||||
console.Lines[5].ShouldBe("│ Grault │ Garply │ Fred │");
|
||||
console.Lines[6].ShouldBe("└────────┴────────┴───────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Table_With_Cell_Padding_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var table = new Table();
|
||||
table.AddColumns("Foo", "Bar");
|
||||
table.AddColumn(new TableColumn("Baz") { Padding = new Padding(3, 2) });
|
||||
table.AddRow("Qux\nQuuux", "Corgi", "Waldo");
|
||||
table.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
// When
|
||||
console.Render(table);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(7);
|
||||
console.Lines[0].ShouldBe("┌────────┬────────┬──────────┐");
|
||||
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
|
||||
console.Lines[2].ShouldBe("├────────┼────────┼──────────┤");
|
||||
console.Lines[3].ShouldBe("│ Qux │ Corgi │ Waldo │");
|
||||
console.Lines[4].ShouldBe("│ Quuux │ │ │");
|
||||
console.Lines[5].ShouldBe("│ Grault │ Garply │ Fred │");
|
||||
console.Lines[6].ShouldBe("└────────┴────────┴──────────┘");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Table_Without_Footer_If_No_Rows_Are_Added()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var table = new Table();
|
||||
table.AddColumns("Foo", "Bar");
|
||||
table.AddColumn(new TableColumn("Baz") { Padding = new Padding(3, 2) });
|
||||
|
||||
// When
|
||||
console.Render(table);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(3);
|
||||
console.Lines[0].ShouldBe("┌─────┬─────┬────────┐");
|
||||
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
|
||||
console.Lines[2].ShouldBe("└─────┴─────┴────────┘");
|
||||
}
|
||||
}
|
||||
}
|
||||
77
src/Spectre.Console.Tests/Unit/Composition/TextTests.cs
Normal file
77
src/Spectre.Console.Tests/Unit/Composition/TextTests.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
public sealed class TextTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Render_Unstyled_Text_As_Expected()
|
||||
{
|
||||
// Given
|
||||
var fixture = new PlainConsole(width: 80);
|
||||
var text = Text.New("Hello World");
|
||||
|
||||
// When
|
||||
fixture.Render(text);
|
||||
|
||||
// Then
|
||||
fixture.Output
|
||||
.NormalizeLineEndings()
|
||||
.ShouldBe("Hello World");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Split_Unstyled_Text_To_New_Lines_If_Width_Exceeds_Console_Width()
|
||||
{
|
||||
// Given
|
||||
var fixture = new PlainConsole(width: 5);
|
||||
var text = Text.New("Hello World");
|
||||
|
||||
// When
|
||||
fixture.Render(text);
|
||||
|
||||
// Then
|
||||
fixture.Output
|
||||
.NormalizeLineEndings()
|
||||
.ShouldBe("Hello\n Worl\nd");
|
||||
}
|
||||
|
||||
public sealed class TheStylizeMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Apply_Style_To_Text()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
|
||||
var text = Text.New("Hello World");
|
||||
text.Stylize(start: 3, end: 8, new Style(decoration: Decoration.Underline));
|
||||
|
||||
// When
|
||||
fixture.Console.Render(text);
|
||||
|
||||
// Then
|
||||
fixture.Output
|
||||
.NormalizeLineEndings()
|
||||
.ShouldBe("Hel[4mlo Wo[0mrld");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Apply_Style_To_Text_Which_Spans_Over_Multiple_Lines()
|
||||
{
|
||||
// Given
|
||||
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, width: 5);
|
||||
var text = Text.New("Hello World");
|
||||
text.Stylize(start: 3, end: 8, new Style(decoration: Decoration.Underline));
|
||||
|
||||
// When
|
||||
fixture.Console.Render(text);
|
||||
|
||||
// Then
|
||||
fixture.Output
|
||||
.NormalizeLineEndings()
|
||||
.ShouldBe("Hel[4mlo[0m\n[4m Wo[0mrl\nd");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
237
src/Spectre.Console.Tests/Unit/StyleTests.cs
Normal file
237
src/Spectre.Console.Tests/Unit/StyleTests.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
public sealed class StyleTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Combine_Two_Styles_As_Expected()
|
||||
{
|
||||
// Given
|
||||
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic);
|
||||
var other = new Style(Color.Green, Color.Silver, Decoration.Underline);
|
||||
|
||||
// When
|
||||
var result = first.Combine(other);
|
||||
|
||||
// Then
|
||||
result.Foreground.ShouldBe(Color.Green);
|
||||
result.Background.ShouldBe(Color.Silver);
|
||||
result.Decoration.ShouldBe(Decoration.Bold | Decoration.Italic | Decoration.Underline);
|
||||
}
|
||||
|
||||
public sealed class TheParseMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Default_Keyword_Should_Return_Default_Style()
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.Parse("default");
|
||||
|
||||
// Then
|
||||
result.ShouldNotBeNull();
|
||||
result.Foreground.ShouldBe(Color.Default);
|
||||
result.Background.ShouldBe(Color.Default);
|
||||
result.Decoration.ShouldBe(Decoration.None);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("bold", Decoration.Bold)]
|
||||
[InlineData("dim", Decoration.Dim)]
|
||||
[InlineData("italic", Decoration.Italic)]
|
||||
[InlineData("underline", Decoration.Underline)]
|
||||
[InlineData("invert", Decoration.Invert)]
|
||||
[InlineData("conceal", Decoration.Conceal)]
|
||||
[InlineData("slowblink", Decoration.SlowBlink)]
|
||||
[InlineData("rapidblink", Decoration.RapidBlink)]
|
||||
[InlineData("strikethrough", Decoration.Strikethrough)]
|
||||
public void Should_Parse_Decoration(string text, Decoration decoration)
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.Parse(text);
|
||||
|
||||
// Then
|
||||
result.ShouldNotBeNull();
|
||||
result.Decoration.ShouldBe(decoration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Parse_Text_And_Decoration()
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.Parse("bold underline blue on green");
|
||||
|
||||
// Then
|
||||
result.ShouldNotBeNull();
|
||||
result.Decoration.ShouldBe(Decoration.Bold | Decoration.Underline);
|
||||
result.Foreground.ShouldBe(Color.Blue);
|
||||
result.Background.ShouldBe(Color.Green);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Parse_Background_If_Foreground_Is_Set_To_Default()
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.Parse("default on green");
|
||||
|
||||
// Then
|
||||
result.ShouldNotBeNull();
|
||||
result.Decoration.ShouldBe(Decoration.None);
|
||||
result.Foreground.ShouldBe(Color.Default);
|
||||
result.Background.ShouldBe(Color.Green);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Foreground_Is_Set_Twice()
|
||||
{
|
||||
// Given, When
|
||||
var result = Record.Exception(() => Style.Parse("green yellow"));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>();
|
||||
result.Message.ShouldBe("A foreground color has already been set.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Background_Is_Set_Twice()
|
||||
{
|
||||
// Given, When
|
||||
var result = Record.Exception(() => Style.Parse("green on blue yellow"));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>();
|
||||
result.Message.ShouldBe("A background color has already been set.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Color_Name_Could_Not_Be_Found()
|
||||
{
|
||||
// Given, When
|
||||
var result = Record.Exception(() => Style.Parse("bold lol"));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>();
|
||||
result.Message.ShouldBe("Could not find color or style 'lol'.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Background_Color_Name_Could_Not_Be_Found()
|
||||
{
|
||||
// Given, When
|
||||
var result = Record.Exception(() => Style.Parse("blue on lol"));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<InvalidOperationException>();
|
||||
result.Message.ShouldBe("Could not find color 'lol'.");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TheTryParseMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Default_Keyword_Should_Return_Default_Style()
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.TryParse("default", out var style);
|
||||
|
||||
// Then
|
||||
result.ShouldBeTrue();
|
||||
style.ShouldNotBeNull();
|
||||
style.Foreground.ShouldBe(Color.Default);
|
||||
style.Background.ShouldBe(Color.Default);
|
||||
style.Decoration.ShouldBe(Decoration.None);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("bold", Decoration.Bold)]
|
||||
[InlineData("dim", Decoration.Dim)]
|
||||
[InlineData("italic", Decoration.Italic)]
|
||||
[InlineData("underline", Decoration.Underline)]
|
||||
[InlineData("invert", Decoration.Invert)]
|
||||
[InlineData("conceal", Decoration.Conceal)]
|
||||
[InlineData("slowblink", Decoration.SlowBlink)]
|
||||
[InlineData("rapidblink", Decoration.RapidBlink)]
|
||||
[InlineData("strikethrough", Decoration.Strikethrough)]
|
||||
public void Should_Parse_Decoration(string text, Decoration decoration)
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.TryParse(text, out var style);
|
||||
|
||||
// Then
|
||||
result.ShouldBeTrue();
|
||||
style.ShouldNotBeNull();
|
||||
style.Decoration.ShouldBe(decoration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Parse_Text_And_Decoration()
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.TryParse("bold underline blue on green", out var style);
|
||||
|
||||
// Then
|
||||
result.ShouldBeTrue();
|
||||
style.ShouldNotBeNull();
|
||||
style.Decoration.ShouldBe(Decoration.Bold | Decoration.Underline);
|
||||
style.Foreground.ShouldBe(Color.Blue);
|
||||
style.Background.ShouldBe(Color.Green);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Parse_Background_If_Foreground_Is_Set_To_Default()
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.TryParse("default on green", out var style);
|
||||
|
||||
// Then
|
||||
result.ShouldBeTrue();
|
||||
style.ShouldNotBeNull();
|
||||
style.Decoration.ShouldBe(Decoration.None);
|
||||
style.Foreground.ShouldBe(Color.Default);
|
||||
style.Background.ShouldBe(Color.Green);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Foreground_Is_Set_Twice()
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.TryParse("green yellow", out _);
|
||||
|
||||
// Then
|
||||
result.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Background_Is_Set_Twice()
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.TryParse("green on blue yellow", out _);
|
||||
|
||||
// Then
|
||||
result.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Color_Name_Could_Not_Be_Found()
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.TryParse("bold lol", out _);
|
||||
|
||||
// Then
|
||||
result.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Background_Color_Name_Could_Not_Be_Found()
|
||||
{
|
||||
// Given, When
|
||||
var result = Style.TryParse("blue on lol", out _);
|
||||
|
||||
// Then
|
||||
result.ShouldBeFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/Spectre.Console/AnsiConsole.Markup.cs
Normal file
52
src/Spectre.Console/AnsiConsole.Markup.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the specified markup to the console.
|
||||
/// </summary>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Markup(string format, params object[] args)
|
||||
{
|
||||
Console.Markup(format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Markup(IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Console.Markup(provider, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void MarkupLine(string format, params object[] args)
|
||||
{
|
||||
Console.MarkupLine(format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void MarkupLine(IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Console.MarkupLine(provider, format, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/Spectre.Console/AnsiConsole.Rendering.cs
Normal file
19
src/Spectre.Console/AnsiConsole.Rendering.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Spectre.Console.Composition;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders the specified object to the console.
|
||||
/// </summary>
|
||||
/// <param name="renderable">The object to render.</param>
|
||||
public static void Render(IRenderable renderable)
|
||||
{
|
||||
Console.Render(renderable);
|
||||
}
|
||||
}
|
||||
}
|
||||
245
src/Spectre.Console/AnsiConsole.Write.cs
Normal file
245
src/Spectre.Console/AnsiConsole.Write.cs
Normal file
@@ -0,0 +1,245 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the specified string value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(string value)
|
||||
{
|
||||
Console.Write(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(int value)
|
||||
{
|
||||
Console.Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, int value)
|
||||
{
|
||||
Console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(uint value)
|
||||
{
|
||||
Console.Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, uint value)
|
||||
{
|
||||
Console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(long value)
|
||||
{
|
||||
Console.Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, long value)
|
||||
{
|
||||
Console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(ulong value)
|
||||
{
|
||||
Console.Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, ulong value)
|
||||
{
|
||||
Console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(float value)
|
||||
{
|
||||
Console.Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, float value)
|
||||
{
|
||||
Console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(double value)
|
||||
{
|
||||
Console.Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, double value)
|
||||
{
|
||||
Console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(decimal value)
|
||||
{
|
||||
Console.Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, decimal value)
|
||||
{
|
||||
Console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(bool value)
|
||||
{
|
||||
Console.Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, bool value)
|
||||
{
|
||||
Console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(char value)
|
||||
{
|
||||
Console.Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, char value)
|
||||
{
|
||||
Console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(char[] value)
|
||||
{
|
||||
Console.Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, char[] value)
|
||||
{
|
||||
Console.Write(provider, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// to the console using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Write(string format, params object[] args)
|
||||
{
|
||||
Console.Write(CultureInfo.CurrentCulture, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// to the console using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Write(IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Console.Write(string.Format(provider, format, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
263
src/Spectre.Console/AnsiConsole.WriteLine.cs
Normal file
263
src/Spectre.Console/AnsiConsole.WriteLine.cs
Normal file
@@ -0,0 +1,263 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes an empty line to the console.
|
||||
/// </summary>
|
||||
public static void WriteLine()
|
||||
{
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified string value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(string value)
|
||||
{
|
||||
Console.WriteLine(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(int value)
|
||||
{
|
||||
Console.WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, int value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(uint value)
|
||||
{
|
||||
Console.WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, uint value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(long value)
|
||||
{
|
||||
Console.WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, long value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(ulong value)
|
||||
{
|
||||
Console.WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, ulong value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(float value)
|
||||
{
|
||||
Console.WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, float value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(double value)
|
||||
{
|
||||
Console.WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, double value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(decimal value)
|
||||
{
|
||||
Console.WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, decimal value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(bool value)
|
||||
{
|
||||
Console.WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, bool value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(char value)
|
||||
{
|
||||
Console.WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, char value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(char[] value)
|
||||
{
|
||||
Console.WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, char[] value)
|
||||
{
|
||||
Console.WriteLine(provider, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// followed by the current line terminator, to the console
|
||||
/// using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void WriteLine(string format, params object[] args)
|
||||
{
|
||||
Console.WriteLine(CultureInfo.CurrentCulture, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// followed by the current line terminator, to the console
|
||||
/// using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Console.WriteLine(string.Format(provider, format, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,16 +6,18 @@ namespace Spectre.Console
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static class AnsiConsole
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
private static readonly Lazy<IAnsiConsole> _console = new Lazy<IAnsiConsole>(() =>
|
||||
{
|
||||
return Create(new AnsiConsoleSettings
|
||||
var console = Create(new AnsiConsoleSettings
|
||||
{
|
||||
Ansi = AnsiSupport.Detect,
|
||||
ColorSystem = ColorSystemSupport.Detect,
|
||||
Out = System.Console.Out,
|
||||
});
|
||||
Created = true;
|
||||
return console;
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
@@ -26,7 +28,9 @@ namespace Spectre.Console
|
||||
/// <summary>
|
||||
/// Gets the console's capabilities.
|
||||
/// </summary>
|
||||
public static AnsiConsoleCapabilities Capabilities => Console.Capabilities;
|
||||
public static Capabilities Capabilities => Console.Capabilities;
|
||||
|
||||
internal static bool Created { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffer width of the console.
|
||||
@@ -63,12 +67,12 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the style.
|
||||
/// Gets or sets the text decoration.
|
||||
/// </summary>
|
||||
public static Styles Style
|
||||
public static Decoration Decoration
|
||||
{
|
||||
get => Console.Style;
|
||||
set => Console.Style = value;
|
||||
get => Console.Decoration;
|
||||
set => Console.Decoration = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -83,7 +87,7 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets colors and styles to the default ones.
|
||||
/// Resets colors and text decorations.
|
||||
/// </summary>
|
||||
public static void Reset()
|
||||
{
|
||||
@@ -91,45 +95,19 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the current style back to the default one.
|
||||
/// Resets the current applied text decorations.
|
||||
/// </summary>
|
||||
public static void ResetStyle()
|
||||
public static void ResetDecoration()
|
||||
{
|
||||
Console.ResetStyle();
|
||||
Console.ResetDecoration();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the foreground and background colors to the default ones.
|
||||
/// Resets the current applied foreground and background colors.
|
||||
/// </summary>
|
||||
public static void ResetColors()
|
||||
{
|
||||
Console.ResetColors();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the content to the console.
|
||||
/// </summary>
|
||||
/// <param name="content">The content to write.</param>
|
||||
public static void Write(string content)
|
||||
{
|
||||
Console.Write(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an empty line to the console.
|
||||
/// </summary>
|
||||
public static void WriteLine()
|
||||
{
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a line to the console.
|
||||
/// </summary>
|
||||
/// <param name="content">The content to write.</param>
|
||||
public static void WriteLine(string content)
|
||||
{
|
||||
Console.WriteLine(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents console capabilities.
|
||||
/// </summary>
|
||||
public sealed class AnsiConsoleCapabilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not
|
||||
/// the console supports Ansi.
|
||||
/// </summary>
|
||||
public bool SupportsAnsi { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the color system.
|
||||
/// </summary>
|
||||
public ColorSystem ColorSystem { get; }
|
||||
|
||||
internal AnsiConsoleCapabilities(bool supportsAnsi, ColorSystem colorSystem)
|
||||
{
|
||||
SupportsAnsi = supportsAnsi;
|
||||
ColorSystem = colorSystem;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
var supportsAnsi = SupportsAnsi ? "Yes" : "No";
|
||||
var bits = ColorSystem switch
|
||||
{
|
||||
ColorSystem.NoColors => "1 bit",
|
||||
ColorSystem.Legacy => "3 bits",
|
||||
ColorSystem.Standard => "4 bits",
|
||||
ColorSystem.EightBit => "8 bits",
|
||||
ColorSystem.TrueColor => "24 bits",
|
||||
_ => "?"
|
||||
};
|
||||
|
||||
return $"ANSI={supportsAnsi}, Colors={ColorSystem} ({bits})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,7 @@ using System.IO;
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Settings used by <see cref="ConsoleBuilder"/>
|
||||
/// when building a <see cref="IAnsiConsole"/>.
|
||||
/// Settings used when building a <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
public sealed class AnsiConsoleSettings
|
||||
{
|
||||
|
||||
59
src/Spectre.Console/Capabilities.cs
Normal file
59
src/Spectre.Console/Capabilities.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents console capabilities.
|
||||
/// </summary>
|
||||
public sealed class Capabilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not
|
||||
/// the console supports Ansi.
|
||||
/// </summary>
|
||||
public bool SupportsAnsi { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the color system.
|
||||
/// </summary>
|
||||
public ColorSystem ColorSystem { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not
|
||||
/// this is a legacy console (cmd.exe).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only relevant when running on Microsoft Windows.
|
||||
/// </remarks>
|
||||
public bool LegacyConsole { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Capabilities"/> class.
|
||||
/// </summary>
|
||||
/// <param name="supportsAnsi">Whether or not ANSI escape sequences are supported.</param>
|
||||
/// <param name="colorSystem">The color system that is supported.</param>
|
||||
/// <param name="legacyConsole">Whether or not this is a legacy console.</param>
|
||||
public Capabilities(bool supportsAnsi, ColorSystem colorSystem, bool legacyConsole)
|
||||
{
|
||||
SupportsAnsi = supportsAnsi;
|
||||
ColorSystem = colorSystem;
|
||||
LegacyConsole = legacyConsole;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
var supportsAnsi = SupportsAnsi ? "Yes" : "No";
|
||||
var legacyConsole = LegacyConsole ? "Legacy" : "Modern";
|
||||
var bits = ColorSystem switch
|
||||
{
|
||||
ColorSystem.NoColors => "1 bit",
|
||||
ColorSystem.Legacy => "3 bits",
|
||||
ColorSystem.Standard => "4 bits",
|
||||
ColorSystem.EightBit => "8 bits",
|
||||
ColorSystem.TrueColor => "24 bits",
|
||||
_ => "?"
|
||||
};
|
||||
|
||||
return $"ANSI={supportsAnsi}, Colors={ColorSystem}, Kind={legacyConsole} ({bits})";
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Globalization;
|
||||
using Spectre.Console.Internal;
|
||||
|
||||
namespace Spectre.Console
|
||||
@@ -17,7 +17,7 @@ namespace Spectre.Console
|
||||
|
||||
static Color()
|
||||
{
|
||||
Default = new Color(0, "default", 0, 0, 0, true);
|
||||
Default = new Color(0, 0, 0, 0, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -35,11 +35,6 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
public byte B { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the color, if any.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of the color, if any.
|
||||
/// </summary>
|
||||
@@ -62,7 +57,6 @@ namespace Spectre.Console
|
||||
G = green;
|
||||
B = blue;
|
||||
IsDefault = false;
|
||||
Name = null;
|
||||
Number = null;
|
||||
}
|
||||
|
||||
@@ -88,7 +82,8 @@ namespace Spectre.Console
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(Color other)
|
||||
{
|
||||
return Number == other.Number || (R == other.R && G == other.G && B == other.B);
|
||||
return (IsDefault && other.IsDefault) ||
|
||||
(IsDefault == other.IsDefault && R == other.R && G == other.G && B == other.B);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -113,6 +108,15 @@ namespace Spectre.Console
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convers a <see cref="int"/> to a <see cref="Color"/>.
|
||||
/// </summary>
|
||||
/// <param name="number">The color number to convert.</param>
|
||||
public static implicit operator Color(int number)
|
||||
{
|
||||
return FromInt32(number);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convers a <see cref="ConsoleColor"/> to a <see cref="Color"/>.
|
||||
/// </summary>
|
||||
@@ -123,18 +127,12 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convers a color number into a <see cref="Color"/>.
|
||||
/// Convers a <see cref="Color"/> to a <see cref="ConsoleColor"/>.
|
||||
/// </summary>
|
||||
/// <param name="number">The color number.</param>
|
||||
/// <returns>The color representing the specified color number.</returns>
|
||||
public static Color FromColorNumber(int number)
|
||||
/// <param name="color">The console color to convert.</param>
|
||||
public static implicit operator ConsoleColor(Color color)
|
||||
{
|
||||
if (number < 0 || number > 255)
|
||||
{
|
||||
throw new InvalidOperationException("Color number must be between 0 and 255");
|
||||
}
|
||||
|
||||
return ColorPalette.EightBit.First(x => x.Number == number);
|
||||
return ToConsoleColor(color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -179,6 +177,16 @@ namespace Spectre.Console
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convers a color number into a <see cref="Color"/>.
|
||||
/// </summary>
|
||||
/// <param name="number">The color number.</param>
|
||||
/// <returns>The color representing the specified color number.</returns>
|
||||
public static Color FromInt32(int number)
|
||||
{
|
||||
return ColorTable.GetColor(number);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convers a <see cref="ConsoleColor"/> to a <see cref="Color"/>.
|
||||
/// </summary>
|
||||
@@ -207,5 +215,20 @@ namespace Spectre.Console
|
||||
_ => Default,
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
if (Number != null)
|
||||
{
|
||||
var name = ColorTable.GetName(Number.Value);
|
||||
if (!string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Format(CultureInfo.InvariantCulture, "#{0:X2}{1:X2}{2:X2} (RGB={0},{1},{2})", R, G, B);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
103
src/Spectre.Console/Composition/Border.cs
Normal file
103
src/Spectre.Console/Composition/Border.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a border used by tables.
|
||||
/// </summary>
|
||||
public abstract class Border
|
||||
{
|
||||
private readonly Dictionary<BorderPart, string> _lookup;
|
||||
|
||||
private static readonly Dictionary<BorderKind, Border> _borders = new Dictionary<BorderKind, Border>
|
||||
{
|
||||
{ BorderKind.None, new NoBorder() },
|
||||
{ BorderKind.Ascii, new AsciiBorder() },
|
||||
{ BorderKind.Square, new SquareBorder() },
|
||||
{ BorderKind.Rounded, new RoundedBorder() },
|
||||
};
|
||||
|
||||
private static readonly Dictionary<BorderKind, BorderKind> _safeLookup = new Dictionary<BorderKind, BorderKind>
|
||||
{
|
||||
{ BorderKind.Rounded, BorderKind.Square },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Border"/> class.
|
||||
/// </summary>
|
||||
protected Border()
|
||||
{
|
||||
_lookup = Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="Border"/> represented by the specified <see cref="BorderKind"/>.
|
||||
/// </summary>
|
||||
/// <param name="kind">The kind of border to get.</param>
|
||||
/// <param name="safe">Whether or not to get a "safe" border that can be rendered in a legacy console.</param>
|
||||
/// <returns>A <see cref="Border"/> instance representing the specified <see cref="BorderKind"/>.</returns>
|
||||
public static Border GetBorder(BorderKind kind, bool safe)
|
||||
{
|
||||
if (safe && _safeLookup.TryGetValue(kind, out var safeKind))
|
||||
{
|
||||
kind = safeKind;
|
||||
}
|
||||
|
||||
if (!_borders.TryGetValue(kind, out var border))
|
||||
{
|
||||
throw new InvalidOperationException("Unknown border kind");
|
||||
}
|
||||
|
||||
return border;
|
||||
}
|
||||
|
||||
private Dictionary<BorderPart, string> Initialize()
|
||||
{
|
||||
var lookup = new Dictionary<BorderPart, string>();
|
||||
foreach (BorderPart part in Enum.GetValues(typeof(BorderPart)))
|
||||
{
|
||||
var text = GetBoxPart(part);
|
||||
if (text.Length > 1)
|
||||
{
|
||||
throw new InvalidOperationException("A box part cannot contain more than one character.");
|
||||
}
|
||||
|
||||
lookup.Add(part, GetBoxPart(part));
|
||||
}
|
||||
|
||||
return lookup;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string representation of a specific border part.
|
||||
/// </summary>
|
||||
/// <param name="part">The part to get a string representation for.</param>
|
||||
/// <param name="count">The number of repetitions.</param>
|
||||
/// <returns>A string representation of the specified border part.</returns>
|
||||
public string GetPart(BorderPart part, int count)
|
||||
{
|
||||
// TODO: This need some optimization...
|
||||
return string.Join(string.Empty, Enumerable.Repeat(GetBoxPart(part)[0], count));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string representation of a specific border part.
|
||||
/// </summary>
|
||||
/// <param name="part">The part to get a string representation for.</param>
|
||||
/// <returns>A string representation of the specified border part.</returns>
|
||||
public string GetPart(BorderPart part)
|
||||
{
|
||||
return _lookup[part].ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the character representing the specified border part.
|
||||
/// </summary>
|
||||
/// <param name="part">The part to get the character representation for.</param>
|
||||
/// <returns>A character representation of the specified border part.</returns>
|
||||
protected abstract string GetBoxPart(BorderPart part);
|
||||
}
|
||||
}
|
||||
28
src/Spectre.Console/Composition/BorderKind.cs
Normal file
28
src/Spectre.Console/Composition/BorderKind.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents different kinds of borders.
|
||||
/// </summary>
|
||||
public enum BorderKind
|
||||
{
|
||||
/// <summary>
|
||||
/// No border.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// A square border.
|
||||
/// </summary>
|
||||
Square = 1,
|
||||
|
||||
/// <summary>
|
||||
/// An old school ASCII border.
|
||||
/// </summary>
|
||||
Ascii = 2,
|
||||
|
||||
/// <summary>
|
||||
/// A rounded border.
|
||||
/// </summary>
|
||||
Rounded = 3,
|
||||
}
|
||||
}
|
||||
98
src/Spectre.Console/Composition/BorderPart.cs
Normal file
98
src/Spectre.Console/Composition/BorderPart.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the different border parts.
|
||||
/// </summary>
|
||||
public enum BorderPart
|
||||
{
|
||||
/// <summary>
|
||||
/// The top left part of a header.
|
||||
/// </summary>
|
||||
HeaderTopLeft,
|
||||
|
||||
/// <summary>
|
||||
/// The top part of a header.
|
||||
/// </summary>
|
||||
HeaderTop,
|
||||
|
||||
/// <summary>
|
||||
/// The top separator part of a header.
|
||||
/// </summary>
|
||||
HeaderTopSeparator,
|
||||
|
||||
/// <summary>
|
||||
/// The top right part of a header.
|
||||
/// </summary>
|
||||
HeaderTopRight,
|
||||
|
||||
/// <summary>
|
||||
/// The left part of a header.
|
||||
/// </summary>
|
||||
HeaderLeft,
|
||||
|
||||
/// <summary>
|
||||
/// A header separator.
|
||||
/// </summary>
|
||||
HeaderSeparator,
|
||||
|
||||
/// <summary>
|
||||
/// The right part of a header.
|
||||
/// </summary>
|
||||
HeaderRight,
|
||||
|
||||
/// <summary>
|
||||
/// The bottom left part of a header.
|
||||
/// </summary>
|
||||
HeaderBottomLeft,
|
||||
|
||||
/// <summary>
|
||||
/// The bottom part of a header.
|
||||
/// </summary>
|
||||
HeaderBottom,
|
||||
|
||||
/// <summary>
|
||||
/// The bottom separator part of a header.
|
||||
/// </summary>
|
||||
HeaderBottomSeparator,
|
||||
|
||||
/// <summary>
|
||||
/// The bottom right part of a header.
|
||||
/// </summary>
|
||||
HeaderBottomRight,
|
||||
|
||||
/// <summary>
|
||||
/// The left part of a cell.
|
||||
/// </summary>
|
||||
CellLeft,
|
||||
|
||||
/// <summary>
|
||||
/// A cell separator.
|
||||
/// </summary>
|
||||
CellSeparator,
|
||||
|
||||
/// <summary>
|
||||
/// The right part of a cell.
|
||||
/// </summary>
|
||||
CellRight,
|
||||
|
||||
/// <summary>
|
||||
/// The bottom left part of a footer.
|
||||
/// </summary>
|
||||
FooterBottomLeft,
|
||||
|
||||
/// <summary>
|
||||
/// The bottom part of a footer.
|
||||
/// </summary>
|
||||
FooterBottom,
|
||||
|
||||
/// <summary>
|
||||
/// The bottom separator part of a footer.
|
||||
/// </summary>
|
||||
FooterBottomSeparator,
|
||||
|
||||
/// <summary>
|
||||
/// The bottom right part of a footer.
|
||||
/// </summary>
|
||||
FooterBottomRight,
|
||||
}
|
||||
}
|
||||
37
src/Spectre.Console/Composition/Borders/AsciiBorder.cs
Normal file
37
src/Spectre.Console/Composition/Borders/AsciiBorder.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an old school ASCII border.
|
||||
/// </summary>
|
||||
public sealed class AsciiBorder : Border
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override string GetBoxPart(BorderPart part)
|
||||
{
|
||||
return part switch
|
||||
{
|
||||
BorderPart.HeaderTopLeft => "+",
|
||||
BorderPart.HeaderTop => "-",
|
||||
BorderPart.HeaderTopSeparator => "-",
|
||||
BorderPart.HeaderTopRight => "+",
|
||||
BorderPart.HeaderLeft => "|",
|
||||
BorderPart.HeaderSeparator => "|",
|
||||
BorderPart.HeaderRight => "|",
|
||||
BorderPart.HeaderBottomLeft => "|",
|
||||
BorderPart.HeaderBottom => "-",
|
||||
BorderPart.HeaderBottomSeparator => "+",
|
||||
BorderPart.HeaderBottomRight => "|",
|
||||
BorderPart.CellLeft => "|",
|
||||
BorderPart.CellSeparator => "|",
|
||||
BorderPart.CellRight => "|",
|
||||
BorderPart.FooterBottomLeft => "+",
|
||||
BorderPart.FooterBottom => "-",
|
||||
BorderPart.FooterBottomSeparator => "-",
|
||||
BorderPart.FooterBottomRight => "+",
|
||||
_ => throw new InvalidOperationException("Unknown box part."),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/Spectre.Console/Composition/Borders/NoBorder.cs
Normal file
14
src/Spectre.Console/Composition/Borders/NoBorder.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an invisible border.
|
||||
/// </summary>
|
||||
public sealed class NoBorder : Border
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override string GetBoxPart(BorderPart part)
|
||||
{
|
||||
return " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/Spectre.Console/Composition/Borders/RoundedBorder.cs
Normal file
37
src/Spectre.Console/Composition/Borders/RoundedBorder.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a rounded border.
|
||||
/// </summary>
|
||||
public sealed class RoundedBorder : Border
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override string GetBoxPart(BorderPart part)
|
||||
{
|
||||
return part switch
|
||||
{
|
||||
BorderPart.HeaderTopLeft => "╭",
|
||||
BorderPart.HeaderTop => "─",
|
||||
BorderPart.HeaderTopSeparator => "┬",
|
||||
BorderPart.HeaderTopRight => "╮",
|
||||
BorderPart.HeaderLeft => "│",
|
||||
BorderPart.HeaderSeparator => "│",
|
||||
BorderPart.HeaderRight => "│",
|
||||
BorderPart.HeaderBottomLeft => "├",
|
||||
BorderPart.HeaderBottom => "─",
|
||||
BorderPart.HeaderBottomSeparator => "┼",
|
||||
BorderPart.HeaderBottomRight => "┤",
|
||||
BorderPart.CellLeft => "│",
|
||||
BorderPart.CellSeparator => "│",
|
||||
BorderPart.CellRight => "│",
|
||||
BorderPart.FooterBottomLeft => "╰",
|
||||
BorderPart.FooterBottom => "─",
|
||||
BorderPart.FooterBottomSeparator => "┴",
|
||||
BorderPart.FooterBottomRight => "╯",
|
||||
_ => throw new InvalidOperationException("Unknown box part."),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/Spectre.Console/Composition/Borders/SquareBorder.cs
Normal file
37
src/Spectre.Console/Composition/Borders/SquareBorder.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a square border.
|
||||
/// </summary>
|
||||
public sealed class SquareBorder : Border
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override string GetBoxPart(BorderPart part)
|
||||
{
|
||||
return part switch
|
||||
{
|
||||
BorderPart.HeaderTopLeft => "┌",
|
||||
BorderPart.HeaderTop => "─",
|
||||
BorderPart.HeaderTopSeparator => "┬",
|
||||
BorderPart.HeaderTopRight => "┐",
|
||||
BorderPart.HeaderLeft => "│",
|
||||
BorderPart.HeaderSeparator => "│",
|
||||
BorderPart.HeaderRight => "│",
|
||||
BorderPart.HeaderBottomLeft => "├",
|
||||
BorderPart.HeaderBottom => "─",
|
||||
BorderPart.HeaderBottomSeparator => "┼",
|
||||
BorderPart.HeaderBottomRight => "┤",
|
||||
BorderPart.CellLeft => "│",
|
||||
BorderPart.CellSeparator => "│",
|
||||
BorderPart.CellRight => "│",
|
||||
BorderPart.FooterBottomLeft => "└",
|
||||
BorderPart.FooterBottom => "─",
|
||||
BorderPart.FooterBottomSeparator => "┴",
|
||||
BorderPart.FooterBottomRight => "┘",
|
||||
_ => throw new InvalidOperationException("Unknown box part."),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
120
src/Spectre.Console/Composition/Grid.cs
Normal file
120
src/Spectre.Console/Composition/Grid.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Spectre.Console.Composition;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a grid.
|
||||
/// </summary>
|
||||
public sealed class Grid : IRenderable
|
||||
{
|
||||
private readonly Table _table;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Grid"/> class.
|
||||
/// </summary>
|
||||
public Grid()
|
||||
{
|
||||
_table = new Table
|
||||
{
|
||||
Border = BorderKind.None,
|
||||
ShowHeaders = false,
|
||||
IsGrid = true,
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
return ((IRenderable)_table).Measure(context, maxWidth);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<Segment> Render(RenderContext context, int width)
|
||||
{
|
||||
return ((IRenderable)_table).Render(context, width);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a column to the grid.
|
||||
/// </summary>
|
||||
public void AddColumn()
|
||||
{
|
||||
AddColumn(new GridColumn());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a column to the grid.
|
||||
/// </summary>
|
||||
/// <param name="column">The column to add.</param>
|
||||
public void AddColumn(GridColumn column)
|
||||
{
|
||||
if (column is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(column));
|
||||
}
|
||||
|
||||
_table.AddColumn(new TableColumn(string.Empty)
|
||||
{
|
||||
Width = column.Width,
|
||||
NoWrap = column.NoWrap,
|
||||
Padding = column.Padding,
|
||||
Alignment = column.Alignment,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a column to the grid.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of columns to add.</param>
|
||||
public void AddColumns(int count)
|
||||
{
|
||||
for (var index = 0; index < count; index++)
|
||||
{
|
||||
AddColumn(new GridColumn());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a column to the grid.
|
||||
/// </summary>
|
||||
/// <param name="columns">The columns to add.</param>
|
||||
public void AddColumns(params GridColumn[] columns)
|
||||
{
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
foreach (var column in columns)
|
||||
{
|
||||
AddColumn(column);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new row to the grid.
|
||||
/// </summary>
|
||||
/// <param name="columns">The columns to add.</param>
|
||||
public void AddRow(params string[] columns)
|
||||
{
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
if (columns.Length < _table.ColumnCount)
|
||||
{
|
||||
throw new InvalidOperationException("The number of row columns are less than the number of grid columns.");
|
||||
}
|
||||
|
||||
if (columns.Length > _table.ColumnCount)
|
||||
{
|
||||
throw new InvalidOperationException("The number of row columns are greater than the number of grid columns.");
|
||||
}
|
||||
|
||||
_table.AddRow(columns);
|
||||
}
|
||||
}
|
||||
}
|
||||
30
src/Spectre.Console/Composition/GridColumn.cs
Normal file
30
src/Spectre.Console/Composition/GridColumn.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a grid column.
|
||||
/// </summary>
|
||||
public sealed class GridColumn
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the width of the column.
|
||||
/// If <c>null</c>, the column will adapt to it's contents.
|
||||
/// </summary>
|
||||
public int? Width { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether wrapping of
|
||||
/// text within the column should be prevented.
|
||||
/// </summary>
|
||||
public bool NoWrap { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the padding of the column.
|
||||
/// </summary>
|
||||
public Padding Padding { get; set; } = new Padding(0, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the alignment of the column.
|
||||
/// </summary>
|
||||
public Justify? Alignment { get; set; } = null;
|
||||
}
|
||||
}
|
||||
26
src/Spectre.Console/Composition/IRenderable.cs
Normal file
26
src/Spectre.Console/Composition/IRenderable.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents something that can be rendered to the console.
|
||||
/// </summary>
|
||||
public interface IRenderable
|
||||
{
|
||||
/// <summary>
|
||||
/// Measures the renderable object.
|
||||
/// </summary>
|
||||
/// <param name="context">The render context.</param>
|
||||
/// <param name="maxWidth">The maximum allowed width.</param>
|
||||
/// <returns>The minimum and maximum width of the object.</returns>
|
||||
Measurement Measure(RenderContext context, int maxWidth);
|
||||
|
||||
/// <summary>
|
||||
/// Renders the object.
|
||||
/// </summary>
|
||||
/// <param name="context">The render context.</param>
|
||||
/// <param name="maxWidth">The maximum allowed width.</param>
|
||||
/// <returns>A collection of segments.</returns>
|
||||
IEnumerable<Segment> Render(RenderContext context, int maxWidth);
|
||||
}
|
||||
}
|
||||
23
src/Spectre.Console/Composition/Justify.cs
Normal file
23
src/Spectre.Console/Composition/Justify.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents text justification.
|
||||
/// </summary>
|
||||
public enum Justify
|
||||
{
|
||||
/// <summary>
|
||||
/// Left aligned.
|
||||
/// </summary>
|
||||
Left = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Right aligned.
|
||||
/// </summary>
|
||||
Right = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Centered
|
||||
/// </summary>
|
||||
Center = 2,
|
||||
}
|
||||
}
|
||||
77
src/Spectre.Console/Composition/Measurement.cs
Normal file
77
src/Spectre.Console/Composition/Measurement.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a measurement.
|
||||
/// </summary>
|
||||
public struct Measurement : IEquatable<Measurement>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the minimum width.
|
||||
/// </summary>
|
||||
public int Min { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum width.
|
||||
/// </summary>
|
||||
public int Max { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Measurement"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="min">The minimum width.</param>
|
||||
/// <param name="max">The maximum width.</param>
|
||||
public Measurement(int min, int max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Measurement measurement && Equals(measurement);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = (int)2166136261;
|
||||
hash = (hash * 16777619) ^ Min.GetHashCode();
|
||||
hash = (hash * 16777619) ^ Max.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(Measurement other)
|
||||
{
|
||||
return Min == other.Min && Max == other.Max;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Measurement"/> instances are equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first measurement instance to compare.</param>
|
||||
/// <param name="right">The second measurement instance to compare.</param>
|
||||
/// <returns><c>true</c> if the two measurements are equal, otherwise <c>false</c>.</returns>
|
||||
public static bool operator ==(Measurement left, Measurement right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Measurement"/> instances are not equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first measurement instance to compare.</param>
|
||||
/// <param name="right">The second measurement instance to compare.</param>
|
||||
/// <returns><c>true</c> if the two measurements are not equal, otherwise <c>false</c>.</returns>
|
||||
public static bool operator !=(Measurement left, Measurement right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
||||
}
|
||||
86
src/Spectre.Console/Composition/Padding.cs
Normal file
86
src/Spectre.Console/Composition/Padding.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a measurement.
|
||||
/// </summary>
|
||||
public struct Padding : IEquatable<Padding>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the left padding.
|
||||
/// </summary>
|
||||
public int Left { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the right padding.
|
||||
/// </summary>
|
||||
public int Right { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Padding"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="left">The left padding.</param>
|
||||
/// <param name="right">The right padding.</param>
|
||||
public Padding(int left, int right)
|
||||
{
|
||||
Left = left;
|
||||
Right = right;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Padding padding && Equals(padding);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = (int)2166136261;
|
||||
hash = (hash * 16777619) ^ Left.GetHashCode();
|
||||
hash = (hash * 16777619) ^ Right.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(Padding other)
|
||||
{
|
||||
return Left == other.Left && Right == other.Right;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Padding"/> instances are equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="Padding"/> instance to compare.</param>
|
||||
/// <param name="right">The second <see cref="Padding"/> instance to compare.</param>
|
||||
/// <returns><c>true</c> if the two instances are equal, otherwise <c>false</c>.</returns>
|
||||
public static bool operator ==(Padding left, Padding right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Padding"/> instances are not equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="Padding"/> instance to compare.</param>
|
||||
/// <param name="right">The second <see cref="Padding"/> instance to compare.</param>
|
||||
/// <returns><c>true</c> if the two instances are not equal, otherwise <c>false</c>.</returns>
|
||||
public static bool operator !=(Padding left, Padding right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the horizontal padding.
|
||||
/// </summary>
|
||||
/// <returns>The horizontal padding.</returns>
|
||||
public int GetHorizontalPadding()
|
||||
{
|
||||
return Left + Right;
|
||||
}
|
||||
}
|
||||
}
|
||||
132
src/Spectre.Console/Composition/Panel.cs
Normal file
132
src/Spectre.Console/Composition/Panel.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Composition;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a panel which contains another renderable item.
|
||||
/// </summary>
|
||||
public sealed class Panel : IRenderable
|
||||
{
|
||||
private readonly IRenderable _child;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not to use
|
||||
/// a "safe" border on legacy consoles that might not be able
|
||||
/// to render non-ASCII characters. Defaults to <c>true</c>.
|
||||
/// </summary>
|
||||
public bool SafeBorder { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the kind of border to use.
|
||||
/// </summary>
|
||||
public BorderKind Border { get; set; } = BorderKind.Square;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the alignment of the panel contents.
|
||||
/// </summary>
|
||||
public Justify? Alignment { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not the panel should
|
||||
/// fit the available space. If <c>false</c>, the panel width will be
|
||||
/// auto calculated. Defaults to <c>false</c>.
|
||||
/// </summary>
|
||||
public bool Expand { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the padding.
|
||||
/// </summary>
|
||||
public Padding Padding { get; set; } = new Padding(1, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Panel"/> class.
|
||||
/// </summary>
|
||||
/// <param name="content">The panel content.</param>
|
||||
public Panel(IRenderable content)
|
||||
{
|
||||
_child = content ?? throw new System.ArgumentNullException(nameof(content));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Measurement IRenderable.Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
var childWidth = _child.Measure(context, maxWidth);
|
||||
return new Measurement(childWidth.Min + 2 + Padding.GetHorizontalPadding(), childWidth.Max + 2 + Padding.GetHorizontalPadding());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerable<Segment> IRenderable.Render(RenderContext context, int width)
|
||||
{
|
||||
var border = Composition.Border.GetBorder(Border, (context.LegacyConsole || !context.Unicode) && SafeBorder);
|
||||
|
||||
var edgeWidth = 2;
|
||||
var paddingWidth = Padding.GetHorizontalPadding();
|
||||
var childWidth = width - edgeWidth - paddingWidth;
|
||||
|
||||
if (!Expand)
|
||||
{
|
||||
var measurement = _child.Measure(context, width - edgeWidth - paddingWidth);
|
||||
childWidth = measurement.Max;
|
||||
}
|
||||
|
||||
var panelWidth = childWidth + paddingWidth;
|
||||
|
||||
// Panel top
|
||||
var result = new List<Segment>
|
||||
{
|
||||
new Segment(border.GetPart(BorderPart.HeaderTopLeft)),
|
||||
new Segment(border.GetPart(BorderPart.HeaderTop, panelWidth)),
|
||||
new Segment(border.GetPart(BorderPart.HeaderTopRight)),
|
||||
new Segment("\n"),
|
||||
};
|
||||
|
||||
// Render the child.
|
||||
var childContext = context.WithJustification(Alignment);
|
||||
var childSegments = _child.Render(childContext, childWidth);
|
||||
|
||||
// Split the child segments into lines.
|
||||
foreach (var line in Segment.SplitLines(childSegments, panelWidth))
|
||||
{
|
||||
result.Add(new Segment(border.GetPart(BorderPart.CellLeft)));
|
||||
|
||||
// Left padding
|
||||
if (Padding.Left > 0)
|
||||
{
|
||||
result.Add(new Segment(new string(' ', Padding.Left)));
|
||||
}
|
||||
|
||||
var content = new List<Segment>();
|
||||
content.AddRange(line);
|
||||
|
||||
// Do we need to pad the panel?
|
||||
var length = line.Sum(segment => segment.CellLength(context.Encoding));
|
||||
if (length < childWidth)
|
||||
{
|
||||
var diff = childWidth - length;
|
||||
content.Add(new Segment(new string(' ', diff)));
|
||||
}
|
||||
|
||||
result.AddRange(content);
|
||||
|
||||
// Right padding
|
||||
if (Padding.Right > 0)
|
||||
{
|
||||
result.Add(new Segment(new string(' ', Padding.Right)));
|
||||
}
|
||||
|
||||
result.Add(new Segment(border.GetPart(BorderPart.CellRight)));
|
||||
result.Add(new Segment("\n"));
|
||||
}
|
||||
|
||||
// Panel bottom
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottomLeft)));
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottom, panelWidth)));
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottomRight)));
|
||||
result.Add(new Segment("\n"));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/Spectre.Console/Composition/RenderContext.cs
Normal file
54
src/Spectre.Console/Composition/RenderContext.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a render context.
|
||||
/// </summary>
|
||||
public sealed class RenderContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the console's output encoding.
|
||||
/// </summary>
|
||||
public Encoding Encoding { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not this a legacy console (i.e. cmd.exe).
|
||||
/// </summary>
|
||||
public bool LegacyConsole { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not unicode is supported.
|
||||
/// </summary>
|
||||
public bool Unicode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current justification.
|
||||
/// </summary>
|
||||
public Justify? Justification { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RenderContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="encoding">The console's output encoding.</param>
|
||||
/// <param name="legacyConsole">A value indicating whether or not this a legacy console (i.e. cmd.exe).</param>
|
||||
/// <param name="justification">The justification to use when rendering.</param>
|
||||
public RenderContext(Encoding encoding, bool legacyConsole, Justify? justification = null)
|
||||
{
|
||||
Encoding = encoding ?? throw new System.ArgumentNullException(nameof(encoding));
|
||||
LegacyConsole = legacyConsole;
|
||||
Justification = justification;
|
||||
Unicode = Encoding == Encoding.UTF8 || Encoding == Encoding.Unicode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new context with the specified justification.
|
||||
/// </summary>
|
||||
/// <param name="justification">The justification.</param>
|
||||
/// <returns>A new <see cref="RenderContext"/> instance with the specified justification.</returns>
|
||||
public RenderContext WithJustification(Justify? justification)
|
||||
{
|
||||
return new RenderContext(Encoding, LegacyConsole, justification);
|
||||
}
|
||||
}
|
||||
}
|
||||
231
src/Spectre.Console/Composition/Segment.cs
Normal file
231
src/Spectre.Console/Composition/Segment.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Spectre.Console.Internal;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a renderable segment.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{Text,nq}")]
|
||||
public class Segment
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the segment text.
|
||||
/// </summary>
|
||||
public string Text { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not this is an expicit line break
|
||||
/// that should be preserved.
|
||||
/// </summary>
|
||||
public bool IsLineBreak { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the segment style.
|
||||
/// </summary>
|
||||
public Style Style { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Segment"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The segment text.</param>
|
||||
public Segment(string text)
|
||||
: this(text, Style.Plain)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Segment"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The segment text.</param>
|
||||
/// <param name="style">The segment style.</param>
|
||||
public Segment(string text, Style style)
|
||||
: this(text, style, false)
|
||||
{
|
||||
}
|
||||
|
||||
private Segment(string text, Style style, bool lineBreak)
|
||||
{
|
||||
Text = text?.NormalizeLineEndings() ?? throw new ArgumentNullException(nameof(text));
|
||||
Style = style;
|
||||
IsLineBreak = lineBreak;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a segment that represents an implicit line break.
|
||||
/// </summary>
|
||||
/// <returns>A segment that represents an implicit line break.</returns>
|
||||
public static Segment LineBreak()
|
||||
{
|
||||
return new Segment("\n", Style.Plain, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of cells that this segment
|
||||
/// occupies in the console.
|
||||
/// </summary>
|
||||
/// <param name="encoding">The encoding to use.</param>
|
||||
/// <returns>The number of cells that this segment occupies in the console.</returns>
|
||||
public int CellLength(Encoding encoding)
|
||||
{
|
||||
return Text.CellLength(encoding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new segment without any trailing line endings.
|
||||
/// </summary>
|
||||
/// <returns>A new segment without any trailing line endings.</returns>
|
||||
public Segment StripLineEndings()
|
||||
{
|
||||
return new Segment(Text.TrimEnd('\n'), Style);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the segment at the offset.
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset where to split the segment.</param>
|
||||
/// <returns>One or two new segments representing the split.</returns>
|
||||
public (Segment First, Segment Second) Split(int offset)
|
||||
{
|
||||
if (offset < 0)
|
||||
{
|
||||
return (this, null);
|
||||
}
|
||||
|
||||
if (offset >= Text.Length)
|
||||
{
|
||||
return (this, null);
|
||||
}
|
||||
|
||||
return (
|
||||
new Segment(Text.Substring(0, offset), Style),
|
||||
new Segment(Text.Substring(offset, Text.Length - offset), Style));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the provided segments into lines.
|
||||
/// </summary>
|
||||
/// <param name="segments">The segments to split.</param>
|
||||
/// <returns>A collection of lines.</returns>
|
||||
public static List<SegmentLine> SplitLines(IEnumerable<Segment> segments)
|
||||
{
|
||||
return SplitLines(segments, int.MaxValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the provided segments into lines with a maximum width.
|
||||
/// </summary>
|
||||
/// <param name="segments">The segments to split into lines.</param>
|
||||
/// <param name="maxWidth">The maximum width.</param>
|
||||
/// <returns>A list of lines.</returns>
|
||||
public static List<SegmentLine> SplitLines(IEnumerable<Segment> segments, int maxWidth)
|
||||
{
|
||||
if (segments is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(segments));
|
||||
}
|
||||
|
||||
var lines = new List<SegmentLine>();
|
||||
var line = new SegmentLine();
|
||||
|
||||
var stack = new Stack<Segment>(segments.Reverse());
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
var segment = stack.Pop();
|
||||
|
||||
if (line.Length + segment.Text.Length > maxWidth)
|
||||
{
|
||||
var diff = -(maxWidth - (line.Length + segment.Text.Length));
|
||||
var offset = segment.Text.Length - diff;
|
||||
|
||||
var (first, second) = segment.Split(offset);
|
||||
|
||||
line.Add(first);
|
||||
lines.Add(line);
|
||||
line = new SegmentLine();
|
||||
|
||||
if (second != null)
|
||||
{
|
||||
stack.Push(second);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (segment.Text.Contains("\n"))
|
||||
{
|
||||
if (segment.Text == "\n")
|
||||
{
|
||||
if (line.Length > 0 || segment.IsLineBreak)
|
||||
{
|
||||
lines.Add(line);
|
||||
line = new SegmentLine();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var text = segment.Text;
|
||||
while (text != null)
|
||||
{
|
||||
var parts = text.SplitLines();
|
||||
if (parts.Length > 0)
|
||||
{
|
||||
if (parts[0].Length > 0)
|
||||
{
|
||||
line.Add(new Segment(parts[0], segment.Style));
|
||||
}
|
||||
}
|
||||
|
||||
if (parts.Length > 1)
|
||||
{
|
||||
if (line.Length > 0)
|
||||
{
|
||||
lines.Add(line);
|
||||
line = new SegmentLine();
|
||||
}
|
||||
|
||||
text = string.Concat(parts.Skip(1).Take(parts.Length - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
text = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
line.Add(segment);
|
||||
}
|
||||
}
|
||||
|
||||
if (line.Count > 0)
|
||||
{
|
||||
lines.Add(line);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
internal static List<List<SegmentLine>> MakeSameHeight(int cellHeight, List<List<SegmentLine>> cells)
|
||||
{
|
||||
foreach (var cell in cells)
|
||||
{
|
||||
if (cell.Count < cellHeight)
|
||||
{
|
||||
while (cell.Count != cellHeight)
|
||||
{
|
||||
cell.Add(new SegmentLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cells;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/Spectre.Console/Composition/SegmentLine.cs
Normal file
18
src/Spectre.Console/Composition/SegmentLine.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a line of segments.
|
||||
/// </summary>
|
||||
[SuppressMessage("Naming", "CA1710:Identifiers should have correct suffix")]
|
||||
public sealed class SegmentLine : List<Segment>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the length of the line.
|
||||
/// </summary>
|
||||
public int Length => this.Sum(line => line.Text.Length);
|
||||
}
|
||||
}
|
||||
124
src/Spectre.Console/Composition/Table.Calculations.cs
Normal file
124
src/Spectre.Console/Composition/Table.Calculations.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Internal;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a table.
|
||||
/// </summary>
|
||||
public sealed partial class Table
|
||||
{
|
||||
// Calculate the widths of each column, including padding, not including borders.
|
||||
// Ported from Rich by Will McGugan, licensed under MIT.
|
||||
// https://github.com/willmcgugan/rich/blob/527475837ebbfc427530b3ee0d4d0741d2d0fc6d/rich/table.py#L394
|
||||
private List<int> CalculateColumnWidths(RenderContext options, int maxWidth)
|
||||
{
|
||||
var width_ranges = _columns.Select(column => MeasureColumn(column, options, maxWidth));
|
||||
var widths = width_ranges.Select(range => range.Max).ToList();
|
||||
|
||||
var tableWidth = widths.Sum();
|
||||
|
||||
if (tableWidth > maxWidth)
|
||||
{
|
||||
var wrappable = _columns.Select(c => !c.NoWrap).ToList();
|
||||
widths = CollapseWidths(widths, wrappable, maxWidth);
|
||||
tableWidth = widths.Sum();
|
||||
|
||||
// last resort, reduce columns evenly
|
||||
if (tableWidth > maxWidth)
|
||||
{
|
||||
var excessWidth = tableWidth - maxWidth;
|
||||
widths = Ratio.Reduce(excessWidth, widths.Select(_ => 1).ToList(), widths, widths);
|
||||
tableWidth = widths.Sum();
|
||||
}
|
||||
}
|
||||
|
||||
if (tableWidth < maxWidth && ShouldExpand())
|
||||
{
|
||||
var padWidths = Ratio.Distribute(maxWidth - tableWidth, widths);
|
||||
widths = widths.Zip(padWidths, (a, b) => (a, b)).Select(f => f.a + f.b).ToList();
|
||||
}
|
||||
|
||||
return widths;
|
||||
}
|
||||
|
||||
// Reduce widths so that the total is less or equal to the max width.
|
||||
// Ported from Rich by Will McGugan, licensed under MIT.
|
||||
// https://github.com/willmcgugan/rich/blob/527475837ebbfc427530b3ee0d4d0741d2d0fc6d/rich/table.py#L442
|
||||
private static List<int> CollapseWidths(List<int> widths, List<bool> wrappable, int maxWidth)
|
||||
{
|
||||
var totalWidth = widths.Sum();
|
||||
var excessWidth = totalWidth - maxWidth;
|
||||
|
||||
if (wrappable.AnyTrue())
|
||||
{
|
||||
while (totalWidth != 0 && excessWidth > 0)
|
||||
{
|
||||
var maxColumn = widths.Zip(wrappable, (first, second) => (width: first, allowWrap: second))
|
||||
.Where(x => x.allowWrap)
|
||||
.Max(x => x.width);
|
||||
|
||||
var secondMaxColumn = widths.Zip(wrappable, (width, allowWrap) => allowWrap && width != maxColumn ? width : 1).Max();
|
||||
var columnDifference = maxColumn - secondMaxColumn;
|
||||
|
||||
var ratios = widths.Zip(wrappable, (width, allowWrap) => width == maxColumn && allowWrap ? 1 : 0).ToList();
|
||||
if (!ratios.Any(x => x != 0) || columnDifference == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var maxReduce = widths.Select(_ => Math.Min(excessWidth, columnDifference)).ToList();
|
||||
widths = Ratio.Reduce(excessWidth, ratios, maxReduce, widths);
|
||||
|
||||
totalWidth = widths.Sum();
|
||||
excessWidth = totalWidth - maxWidth;
|
||||
}
|
||||
}
|
||||
|
||||
return widths;
|
||||
}
|
||||
|
||||
private (int Min, int Max) MeasureColumn(TableColumn column, RenderContext options, int maxWidth)
|
||||
{
|
||||
var padding = column.Padding.GetHorizontalPadding();
|
||||
|
||||
// Predetermined width?
|
||||
if (column.Width != null)
|
||||
{
|
||||
return (column.Width.Value + padding, column.Width.Value + padding);
|
||||
}
|
||||
|
||||
var columnIndex = _columns.IndexOf(column);
|
||||
var rows = _rows.Select(row => row[columnIndex]);
|
||||
|
||||
var minWidths = new List<int>();
|
||||
var maxWidths = new List<int>();
|
||||
|
||||
// Include columns in measurement
|
||||
var measure = ((IRenderable)column.Text).Measure(options, maxWidth);
|
||||
minWidths.Add(measure.Min);
|
||||
maxWidths.Add(measure.Max);
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
measure = ((IRenderable)row).Measure(options, maxWidth);
|
||||
minWidths.Add(measure.Min);
|
||||
maxWidths.Add(measure.Max);
|
||||
}
|
||||
|
||||
return (minWidths.Count > 0 ? minWidths.Max() : padding,
|
||||
maxWidths.Count > 0 ? maxWidths.Max() : maxWidth);
|
||||
}
|
||||
|
||||
private int GetExtraWidth(bool includePadding)
|
||||
{
|
||||
var edges = 2;
|
||||
var separators = _columns.Count - 1;
|
||||
var padding = includePadding ? _columns.Select(x => x.Padding.GetHorizontalPadding()).Sum() : 0;
|
||||
return separators + edges + padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
359
src/Spectre.Console/Composition/Table.cs
Normal file
359
src/Spectre.Console/Composition/Table.cs
Normal file
@@ -0,0 +1,359 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Internal;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a table.
|
||||
/// </summary>
|
||||
public sealed partial class Table : IRenderable
|
||||
{
|
||||
private readonly List<TableColumn> _columns;
|
||||
private readonly List<List<Text>> _rows;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of columns in the table.
|
||||
/// </summary>
|
||||
public int ColumnCount => _columns.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of rows in the table.
|
||||
/// </summary>
|
||||
public int RowCount => _rows.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the kind of border to use.
|
||||
/// </summary>
|
||||
public BorderKind Border { get; set; } = BorderKind.Square;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not table headers should be shown.
|
||||
/// </summary>
|
||||
public bool ShowHeaders { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not the table should
|
||||
/// fit the available space. If <c>false</c>, the table width will be
|
||||
/// auto calculated. Defaults to <c>false</c>.
|
||||
/// </summary>
|
||||
public bool Expand { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the width of the table.
|
||||
/// </summary>
|
||||
public int? Width { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not to use
|
||||
/// a "safe" border on legacy consoles that might not be able
|
||||
/// to render non-ASCII characters. Defaults to <c>true</c>.
|
||||
/// </summary>
|
||||
public bool SafeBorder { get; set; } = true;
|
||||
|
||||
internal bool IsGrid { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Table"/> class.
|
||||
/// </summary>
|
||||
public Table()
|
||||
{
|
||||
_columns = new List<TableColumn>();
|
||||
_rows = new List<List<Text>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a column to the table.
|
||||
/// </summary>
|
||||
/// <param name="column">The column to add.</param>
|
||||
public void AddColumn(string column)
|
||||
{
|
||||
if (column is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(column));
|
||||
}
|
||||
|
||||
_columns.Add(new TableColumn(column));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a column to the table.
|
||||
/// </summary>
|
||||
/// <param name="column">The column to add.</param>
|
||||
public void AddColumn(TableColumn column)
|
||||
{
|
||||
if (column is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(column));
|
||||
}
|
||||
|
||||
_columns.Add(column);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds multiple columns to the table.
|
||||
/// </summary>
|
||||
/// <param name="columns">The columns to add.</param>
|
||||
public void AddColumns(params string[] columns)
|
||||
{
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
_columns.AddRange(columns.Select(column => new TableColumn(column)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds multiple columns to the table.
|
||||
/// </summary>
|
||||
/// <param name="columns">The columns to add.</param>
|
||||
public void AddColumns(params TableColumn[] columns)
|
||||
{
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
_columns.AddRange(columns.Select(column => column));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a row to the table.
|
||||
/// </summary>
|
||||
/// <param name="columns">The row columns to add.</param>
|
||||
public void AddRow(params string[] columns)
|
||||
{
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
if (columns.Length < _columns.Count)
|
||||
{
|
||||
throw new InvalidOperationException("The number of row columns are less than the number of table columns.");
|
||||
}
|
||||
|
||||
if (columns.Length > _columns.Count)
|
||||
{
|
||||
throw new InvalidOperationException("The number of row columns are greater than the number of table columns.");
|
||||
}
|
||||
|
||||
_rows.Add(columns.Select(column => Text.New(column)).ToList());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Measurement IRenderable.Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
if (context is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (Width != null)
|
||||
{
|
||||
maxWidth = Math.Min(Width.Value, maxWidth);
|
||||
}
|
||||
|
||||
maxWidth -= GetExtraWidth(includePadding: true);
|
||||
|
||||
var measurements = _columns.Select(column => MeasureColumn(column, context, maxWidth)).ToList();
|
||||
var min = measurements.Sum(x => x.Min) + GetExtraWidth(includePadding: true);
|
||||
var max = Width ?? measurements.Sum(x => x.Max) + GetExtraWidth(includePadding: true);
|
||||
|
||||
return new Measurement(min, max);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerable<Segment> IRenderable.Render(RenderContext context, int width)
|
||||
{
|
||||
if (context is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var border = Composition.Border.GetBorder(Border, (context.LegacyConsole || !context.Unicode) && SafeBorder);
|
||||
|
||||
var showBorder = Border != BorderKind.None;
|
||||
var hideBorder = Border == BorderKind.None;
|
||||
var hasRows = _rows.Count > 0;
|
||||
|
||||
var maxWidth = width;
|
||||
if (Width != null)
|
||||
{
|
||||
maxWidth = Math.Min(Width.Value, maxWidth);
|
||||
}
|
||||
|
||||
maxWidth -= GetExtraWidth(includePadding: true);
|
||||
|
||||
// Calculate the column and table widths
|
||||
var columnWidths = CalculateColumnWidths(context, maxWidth);
|
||||
|
||||
// Update the table width.
|
||||
width = columnWidths.Sum() + GetExtraWidth(includePadding: true);
|
||||
|
||||
var rows = new List<List<Text>>();
|
||||
if (ShowHeaders)
|
||||
{
|
||||
// Add columns to top of rows
|
||||
rows.Add(new List<Text>(_columns.Select(c => c.Text)));
|
||||
}
|
||||
|
||||
// Add rows.
|
||||
rows.AddRange(_rows);
|
||||
|
||||
// Iterate all rows
|
||||
var result = new List<Segment>();
|
||||
foreach (var (index, firstRow, lastRow, row) in rows.Enumerate())
|
||||
{
|
||||
var cellHeight = 1;
|
||||
|
||||
// Get the list of cells for the row and calculate the cell height
|
||||
var cells = new List<List<SegmentLine>>();
|
||||
foreach (var (columnIndex, _, _, (rowWidth, cell)) in columnWidths.Zip(row).Enumerate())
|
||||
{
|
||||
var justification = _columns[columnIndex].Alignment;
|
||||
var childContext = context.WithJustification(justification);
|
||||
|
||||
var lines = Segment.SplitLines(((IRenderable)cell).Render(childContext, rowWidth));
|
||||
cellHeight = Math.Max(cellHeight, lines.Count);
|
||||
cells.Add(lines);
|
||||
}
|
||||
|
||||
// Show top of header?
|
||||
if (firstRow && showBorder)
|
||||
{
|
||||
result.Add(new Segment(border.GetPart(BorderPart.HeaderTopLeft)));
|
||||
foreach (var (columnIndex, _, lastColumn, columnWidth) in columnWidths.Enumerate())
|
||||
{
|
||||
var padding = _columns[columnIndex].Padding;
|
||||
|
||||
result.Add(new Segment(border.GetPart(BorderPart.HeaderTop, padding.Left))); // Left padding
|
||||
result.Add(new Segment(border.GetPart(BorderPart.HeaderTop, columnWidth)));
|
||||
result.Add(new Segment(border.GetPart(BorderPart.HeaderTop, padding.Right))); // Right padding
|
||||
|
||||
if (!lastColumn)
|
||||
{
|
||||
result.Add(new Segment(border.GetPart(BorderPart.HeaderTopSeparator)));
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(new Segment(border.GetPart(BorderPart.HeaderTopRight)));
|
||||
result.Add(Segment.LineBreak());
|
||||
}
|
||||
|
||||
// Iterate through each cell row
|
||||
foreach (var cellRowIndex in Enumerable.Range(0, cellHeight))
|
||||
{
|
||||
// Make cells the same shape
|
||||
cells = Segment.MakeSameHeight(cellHeight, cells);
|
||||
|
||||
foreach (var (cellIndex, firstCell, lastCell, cell) in cells.Enumerate())
|
||||
{
|
||||
if (firstCell && showBorder)
|
||||
{
|
||||
// Show left column edge
|
||||
result.Add(new Segment(border.GetPart(BorderPart.CellLeft)));
|
||||
}
|
||||
|
||||
// Pad column on left side.
|
||||
if (showBorder || IsGrid)
|
||||
{
|
||||
var leftPadding = _columns[cellIndex].Padding.Left;
|
||||
if (leftPadding > 0)
|
||||
{
|
||||
result.Add(new Segment(new string(' ', leftPadding)));
|
||||
}
|
||||
}
|
||||
|
||||
// Add content
|
||||
result.AddRange(cell[cellRowIndex]);
|
||||
|
||||
// Pad cell content right
|
||||
var length = cell[cellRowIndex].Sum(segment => segment.CellLength(context.Encoding));
|
||||
if (length < columnWidths[cellIndex])
|
||||
{
|
||||
result.Add(new Segment(new string(' ', columnWidths[cellIndex] - length)));
|
||||
}
|
||||
|
||||
// Pad column on the right side
|
||||
if (showBorder || (hideBorder && !lastCell) || (IsGrid && !lastCell))
|
||||
{
|
||||
var rightPadding = _columns[cellIndex].Padding.Right;
|
||||
if (rightPadding > 0)
|
||||
{
|
||||
result.Add(new Segment(new string(' ', rightPadding)));
|
||||
}
|
||||
}
|
||||
|
||||
if (lastCell && showBorder)
|
||||
{
|
||||
// Add right column edge
|
||||
result.Add(new Segment(border.GetPart(BorderPart.CellRight)));
|
||||
}
|
||||
else if (showBorder || (hideBorder && !lastCell))
|
||||
{
|
||||
// Add column separator
|
||||
result.Add(new Segment(border.GetPart(BorderPart.CellSeparator)));
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(Segment.LineBreak());
|
||||
}
|
||||
|
||||
// Show header separator?
|
||||
if (firstRow && showBorder && ShowHeaders && hasRows)
|
||||
{
|
||||
result.Add(new Segment(border.GetPart(BorderPart.HeaderBottomLeft)));
|
||||
foreach (var (columnIndex, first, lastColumn, columnWidth) in columnWidths.Enumerate())
|
||||
{
|
||||
var padding = _columns[columnIndex].Padding;
|
||||
|
||||
result.Add(new Segment(border.GetPart(BorderPart.HeaderBottom, padding.Left))); // Left padding
|
||||
result.Add(new Segment(border.GetPart(BorderPart.HeaderBottom, columnWidth)));
|
||||
result.Add(new Segment(border.GetPart(BorderPart.HeaderBottom, padding.Right))); // Right padding
|
||||
|
||||
if (!lastColumn)
|
||||
{
|
||||
result.Add(new Segment(border.GetPart(BorderPart.HeaderBottomSeparator)));
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(new Segment(border.GetPart(BorderPart.HeaderBottomRight)));
|
||||
result.Add(Segment.LineBreak());
|
||||
}
|
||||
|
||||
// Show bottom of footer?
|
||||
if (lastRow && showBorder)
|
||||
{
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottomLeft)));
|
||||
foreach (var (columnIndex, first, lastColumn, columnWidth) in columnWidths.Enumerate())
|
||||
{
|
||||
var padding = _columns[columnIndex].Padding;
|
||||
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottom, padding.Left))); // Left padding
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottom, columnWidth)));
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottom, padding.Right))); // Right padding
|
||||
|
||||
if (!lastColumn)
|
||||
{
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottomSeparator)));
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottomRight)));
|
||||
result.Add(Segment.LineBreak());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool ShouldExpand()
|
||||
{
|
||||
return Expand || Width != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/Spectre.Console/Composition/TableColumn.cs
Normal file
50
src/Spectre.Console/Composition/TableColumn.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a table column.
|
||||
/// </summary>
|
||||
public sealed class TableColumn
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the text associated with the column.
|
||||
/// </summary>
|
||||
public Text Text { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the width of the column.
|
||||
/// If <c>null</c>, the column will adapt to it's contents.
|
||||
/// </summary>
|
||||
public int? Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the padding of the column.
|
||||
/// </summary>
|
||||
public Padding Padding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether wrapping of
|
||||
/// text within the column should be prevented.
|
||||
/// </summary>
|
||||
public bool NoWrap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the alignment of the column.
|
||||
/// </summary>
|
||||
public Justify? Alignment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TableColumn"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The table column text.</param>
|
||||
public TableColumn(string text)
|
||||
{
|
||||
Text = Text.New(text ?? throw new ArgumentNullException(nameof(text)));
|
||||
Width = null;
|
||||
Padding = new Padding(1, 1);
|
||||
NoWrap = false;
|
||||
Alignment = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
290
src/Spectre.Console/Composition/Text.cs
Normal file
290
src/Spectre.Console/Composition/Text.cs
Normal file
@@ -0,0 +1,290 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Internal;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents text with color and decorations.
|
||||
/// </summary>
|
||||
[SuppressMessage("Naming", "CA1724:Type names should not match namespaces")]
|
||||
[DebuggerDisplay("{_text,nq}")]
|
||||
public sealed class Text : IRenderable
|
||||
{
|
||||
private readonly List<Span> _spans;
|
||||
private string _text;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text alignment.
|
||||
/// </summary>
|
||||
public Justify Alignment { get; set; } = Justify.Left;
|
||||
|
||||
private sealed class Span
|
||||
{
|
||||
public int Start { get; }
|
||||
public int End { get; }
|
||||
public Style Style { get; }
|
||||
|
||||
public Span(int start, int end, Style style)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
Style = style ?? Style.Plain;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Console.Text"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
internal Text(string text)
|
||||
{
|
||||
_text = text?.NormalizeLineEndings() ?? throw new ArgumentNullException(nameof(text));
|
||||
_spans = new List<Span>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Text"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="foreground">The foreground.</param>
|
||||
/// <param name="background">The background.</param>
|
||||
/// <param name="decoration">The text decoration.</param>
|
||||
/// <returns>A <see cref="Text"/> instance.</returns>
|
||||
public static Text New(
|
||||
string text,
|
||||
Color? foreground = null,
|
||||
Color? background = null,
|
||||
Decoration? decoration = null)
|
||||
{
|
||||
var result = MarkupParser.Parse(text, new Style(foreground, background, decoration));
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the text alignment.
|
||||
/// </summary>
|
||||
/// <param name="alignment">The text alignment.</param>
|
||||
/// <returns>The same <see cref="Text"/> instance.</returns>
|
||||
public Text WithAlignment(Justify alignment)
|
||||
{
|
||||
Alignment = alignment;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends some text with the specified color and decorations.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to append.</param>
|
||||
/// <param name="style">The text style.</param>
|
||||
public void Append(string text, Style style)
|
||||
{
|
||||
if (text == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(text));
|
||||
}
|
||||
|
||||
var start = _text.Length;
|
||||
var end = _text.Length + text.Length;
|
||||
|
||||
_text += text;
|
||||
|
||||
Stylize(start, end, style);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stylizes a part of the text.
|
||||
/// </summary>
|
||||
/// <param name="start">The start position.</param>
|
||||
/// <param name="end">The end position.</param>
|
||||
/// <param name="style">The style to apply.</param>
|
||||
public void Stylize(int start, int end, Style style)
|
||||
{
|
||||
if (start >= end)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(start), "Start position must be less than the end position.");
|
||||
}
|
||||
|
||||
start = Math.Max(start, 0);
|
||||
end = Math.Min(end, _text.Length);
|
||||
|
||||
_spans.Add(new Span(start, end, style));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Measurement IRenderable.Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_text))
|
||||
{
|
||||
return new Measurement(1, 1);
|
||||
}
|
||||
|
||||
// TODO: Write some kind of tokenizer for this
|
||||
var min = Segment.SplitLines(((IRenderable)this).Render(context, maxWidth))
|
||||
.SelectMany(line => line.Select(segment => segment.Text.Length))
|
||||
.Max();
|
||||
|
||||
var max = _text.SplitLines().Max(x => Cell.GetCellLength(context.Encoding, x));
|
||||
|
||||
return new Measurement(min, max);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerable<Segment> IRenderable.Render(RenderContext context, int width)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_text))
|
||||
{
|
||||
return Array.Empty<Segment>();
|
||||
}
|
||||
|
||||
if (width == 0)
|
||||
{
|
||||
return Array.Empty<Segment>();
|
||||
}
|
||||
|
||||
var result = new List<Segment>();
|
||||
var segments = SplitLineBreaks(CreateSegments());
|
||||
|
||||
var justification = context.Justification ?? Alignment;
|
||||
|
||||
foreach (var (_, _, last, line) in Segment.SplitLines(segments, width).Enumerate())
|
||||
{
|
||||
var length = line.Sum(l => l.StripLineEndings().CellLength(context.Encoding));
|
||||
|
||||
if (length < width)
|
||||
{
|
||||
// Justify right side
|
||||
if (justification == Justify.Right)
|
||||
{
|
||||
var diff = width - length;
|
||||
result.Add(new Segment(new string(' ', diff)));
|
||||
}
|
||||
else if (justification == Justify.Center)
|
||||
{
|
||||
var diff = (width - length) / 2;
|
||||
result.Add(new Segment(new string(' ', diff)));
|
||||
}
|
||||
}
|
||||
|
||||
// Render the line.
|
||||
foreach (var segment in line)
|
||||
{
|
||||
result.Add(segment.StripLineEndings());
|
||||
}
|
||||
|
||||
// Justify left side
|
||||
if (length < width)
|
||||
{
|
||||
if (justification == Justify.Center)
|
||||
{
|
||||
var diff = (width - length) / 2;
|
||||
result.Add(new Segment(new string(' ', diff)));
|
||||
|
||||
var remainder = (width - length) % 2;
|
||||
if (remainder != 0)
|
||||
{
|
||||
result.Add(new Segment(new string(' ', remainder)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!last)
|
||||
{
|
||||
result.Add(Segment.LineBreak());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private IEnumerable<Segment> SplitLineBreaks(IEnumerable<Segment> segments)
|
||||
{
|
||||
// Creates individual segments of line breaks.
|
||||
var result = new List<Segment>();
|
||||
var queue = new Stack<Segment>(segments.Reverse());
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var segment = queue.Pop();
|
||||
|
||||
var index = segment.Text.IndexOf("\n", StringComparison.OrdinalIgnoreCase);
|
||||
if (index == -1)
|
||||
{
|
||||
result.Add(segment);
|
||||
}
|
||||
else
|
||||
{
|
||||
var (first, second) = segment.Split(index);
|
||||
if (!string.IsNullOrEmpty(first.Text))
|
||||
{
|
||||
result.Add(first);
|
||||
}
|
||||
|
||||
result.Add(Segment.LineBreak());
|
||||
queue.Push(new Segment(second.Text.Substring(1), second.Style));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private IEnumerable<Segment> CreateSegments()
|
||||
{
|
||||
// This excellent algorithm to sort spans was ported and adapted from
|
||||
// https://github.com/willmcgugan/rich/blob/eb2f0d5277c159d8693636ec60c79c5442fd2e43/rich/text.py#L492
|
||||
|
||||
// Create the style map.
|
||||
var styleMap = _spans.SelectIndex((span, index) => (span, index)).ToDictionary(x => x.index + 1, x => x.span.Style);
|
||||
styleMap[0] = Style.Plain;
|
||||
|
||||
// Create a span list.
|
||||
var spans = new List<(int Offset, bool Leaving, int Style)>();
|
||||
spans.AddRange(_spans.SelectIndex((span, index) => (span.Start, false, index + 1)));
|
||||
spans.AddRange(_spans.SelectIndex((span, index) => (span.End, true, index + 1)));
|
||||
spans = spans.OrderBy(x => x.Offset).ThenBy(x => !x.Leaving).ToList();
|
||||
|
||||
// Keep track of applied styles using a stack
|
||||
var styleStack = new Stack<int>();
|
||||
|
||||
// Now build the segments.
|
||||
var result = new List<Segment>();
|
||||
foreach (var (offset, leaving, style, nextOffset) in BuildSkipList(spans))
|
||||
{
|
||||
if (leaving)
|
||||
{
|
||||
// Leaving
|
||||
styleStack.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Entering
|
||||
styleStack.Push(style);
|
||||
}
|
||||
|
||||
if (nextOffset > offset)
|
||||
{
|
||||
// Build the current style from the stack
|
||||
var styleIndices = styleStack.OrderBy(index => index).ToArray();
|
||||
var currentStyle = Style.Plain.Combine(styleIndices.Select(index => styleMap[index]));
|
||||
|
||||
// Create segment
|
||||
var text = _text.Substring(offset, Math.Min(_text.Length - offset, nextOffset - offset));
|
||||
result.Add(new Segment(text, currentStyle));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IEnumerable<(int Offset, bool Leaving, int Style, int NextOffset)> BuildSkipList(
|
||||
List<(int Offset, bool Leaving, int Style)> spans)
|
||||
{
|
||||
return spans.Zip(spans.Skip(1), (first, second) => (first, second)).Select(
|
||||
x => (x.first.Offset, x.first.Leaving, x.first.Style, NextOffset: x.second.Offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
59
src/Spectre.Console/ConsoleExtensions.Markup.cs
Normal file
59
src/Spectre.Console/ConsoleExtensions.Markup.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Spectre.Console.Internal;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
public static partial class ConsoleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the specified markup to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Markup(this IAnsiConsole console, string format, params object[] args)
|
||||
{
|
||||
Markup(console, CultureInfo.CurrentCulture, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Markup(this IAnsiConsole console, IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
console.Render(MarkupParser.Parse(string.Format(provider, format, args)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void MarkupLine(this IAnsiConsole console, string format, params object[] args)
|
||||
{
|
||||
MarkupLine(console, CultureInfo.CurrentCulture, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void MarkupLine(this IAnsiConsole console, IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Markup(console, provider, format, args);
|
||||
console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/Spectre.Console/ConsoleExtensions.Rendering.cs
Normal file
47
src/Spectre.Console/ConsoleExtensions.Rendering.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Internal;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
public static partial class ConsoleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders the specified object to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to render to.</param>
|
||||
/// <param name="renderable">The object to render.</param>
|
||||
public static void Render(this IAnsiConsole console, IRenderable renderable)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
if (renderable is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(renderable));
|
||||
}
|
||||
|
||||
var options = new RenderContext(console.Encoding, console.Capabilities.LegacyConsole);
|
||||
|
||||
foreach (var segment in renderable.Render(options, console.Width))
|
||||
{
|
||||
if (!segment.Style.Equals(Style.Plain))
|
||||
{
|
||||
using (var style = console.PushStyle(segment.Style))
|
||||
{
|
||||
console.Write(segment.Text);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
console.Write(segment.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
339
src/Spectre.Console/ConsoleExtensions.Write.cs
Normal file
339
src/Spectre.Console/ConsoleExtensions.Write.cs
Normal file
@@ -0,0 +1,339 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
public static partial class ConsoleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the specified string value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, string value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
console.Write(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, int value)
|
||||
{
|
||||
Write(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, IFormatProvider provider, int value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, uint value)
|
||||
{
|
||||
Write(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, IFormatProvider provider, uint value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, long value)
|
||||
{
|
||||
Write(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, IFormatProvider provider, long value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, ulong value)
|
||||
{
|
||||
Write(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, IFormatProvider provider, ulong value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, float value)
|
||||
{
|
||||
Write(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, IFormatProvider provider, float value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, double value)
|
||||
{
|
||||
Write(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, IFormatProvider provider, double value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.Write(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, decimal value)
|
||||
{
|
||||
Write(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, IFormatProvider provider, decimal value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
Write(console, value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, bool value)
|
||||
{
|
||||
Write(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, IFormatProvider provider, bool value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
Write(console, value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, char value)
|
||||
{
|
||||
Write(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, IFormatProvider provider, char value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
Write(console, value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, char[] value)
|
||||
{
|
||||
Write(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(this IAnsiConsole console, IFormatProvider provider, char[] value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
for (var index = 0; index < value.Length; index++)
|
||||
{
|
||||
console.Write(value[index].ToString(provider));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// to the console using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Write(this IAnsiConsole console, string format, params object[] args)
|
||||
{
|
||||
Write(console, CultureInfo.CurrentCulture, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// to the console using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Write(this IAnsiConsole console, IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
Write(console, string.Format(provider, format, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
368
src/Spectre.Console/ConsoleExtensions.WriteLine.cs
Normal file
368
src/Spectre.Console/ConsoleExtensions.WriteLine.cs
Normal file
@@ -0,0 +1,368 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
public static partial class ConsoleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes an empty line to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
public static void WriteLine(this IAnsiConsole console)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.Write(Environment.NewLine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified string value, followed by the
|
||||
/// current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, string value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
console.Write(value);
|
||||
}
|
||||
|
||||
console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, int value)
|
||||
{
|
||||
WriteLine(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, IFormatProvider provider, int value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, uint value)
|
||||
{
|
||||
WriteLine(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, IFormatProvider provider, uint value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, long value)
|
||||
{
|
||||
WriteLine(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, IFormatProvider provider, long value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, ulong value)
|
||||
{
|
||||
WriteLine(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, IFormatProvider provider, ulong value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, float value)
|
||||
{
|
||||
WriteLine(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, IFormatProvider provider, float value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, double value)
|
||||
{
|
||||
WriteLine(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, IFormatProvider provider, double value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.WriteLine(value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, decimal value)
|
||||
{
|
||||
WriteLine(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, IFormatProvider provider, decimal value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
WriteLine(console, value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, bool value)
|
||||
{
|
||||
WriteLine(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, IFormatProvider provider, bool value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
WriteLine(console, value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, char value)
|
||||
{
|
||||
WriteLine(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, IFormatProvider provider, char value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
WriteLine(console, value.ToString(provider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, char[] value)
|
||||
{
|
||||
WriteLine(console, CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, IFormatProvider provider, char[] value)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
for (var index = 0; index < value.Length; index++)
|
||||
{
|
||||
console.Write(value[index].ToString(provider));
|
||||
}
|
||||
|
||||
console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// followed by the current line terminator, to the console
|
||||
/// using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, string format, params object[] args)
|
||||
{
|
||||
WriteLine(console, CultureInfo.CurrentCulture, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// followed by the current line terminator, to the console
|
||||
/// using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
WriteLine(console, string.Format(provider, format, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,10 @@ namespace Spectre.Console
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
public static class ConsoleExtensions
|
||||
public static partial class ConsoleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Resets both colors and style for the console.
|
||||
/// Resets colors and text decorations.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to reset.</param>
|
||||
public static void Reset(this IAnsiConsole console)
|
||||
@@ -19,25 +19,25 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
console.ResetColors();
|
||||
console.ResetStyle();
|
||||
console.ResetDecoration();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the current style back to the default one.
|
||||
/// Resets the current applied text decorations.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to reset the style for.</param>
|
||||
public static void ResetStyle(this IAnsiConsole console)
|
||||
/// <param name="console">The console to reset the text decorations for.</param>
|
||||
public static void ResetDecoration(this IAnsiConsole console)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.Style = Styles.None;
|
||||
console.Decoration = Decoration.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the foreground and background colors to the default ones.
|
||||
/// Resets the current applied foreground and background colors.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to reset colors for.</param>
|
||||
public static void ResetColors(this IAnsiConsole console)
|
||||
@@ -50,34 +50,5 @@ namespace Spectre.Console
|
||||
console.Foreground = Color.Default;
|
||||
console.Background = Color.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an empty line to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
public static void WriteLine(this IAnsiConsole console)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.WriteLine(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a line to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="content">The content to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, string content)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.WriteLine(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a style.
|
||||
/// Represents text decoration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Support for different styles is up to the terminal.
|
||||
/// Support for text decorations is up to the terminal.
|
||||
/// </remarks>
|
||||
[Flags]
|
||||
public enum Styles
|
||||
[SuppressMessage("Naming", "CA1714:Flags enums should have plural names")]
|
||||
public enum Decoration
|
||||
{
|
||||
/// <summary>
|
||||
/// No style.
|
||||
/// No text decoration.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
@@ -8,22 +10,27 @@ namespace Spectre.Console
|
||||
/// <summary>
|
||||
/// Gets the console's capabilities.
|
||||
/// </summary>
|
||||
public AnsiConsoleCapabilities Capabilities { get; }
|
||||
Capabilities Capabilities { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffer width of the console.
|
||||
/// </summary>
|
||||
public int Width { get; }
|
||||
int Width { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffer height of the console.
|
||||
/// </summary>
|
||||
public int Height { get; }
|
||||
int Height { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current style.
|
||||
/// Gets the console output encoding.
|
||||
/// </summary>
|
||||
Styles Style { get; set; }
|
||||
Encoding Encoding { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current text decoration.
|
||||
/// </summary>
|
||||
Decoration Decoration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current foreground.
|
||||
@@ -40,13 +47,5 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
/// <param name="text">The string to write.</param>
|
||||
void Write(string text);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string followed by a line terminator to the console.
|
||||
/// </summary>
|
||||
/// <param name="text">
|
||||
/// The string to write. If value is null, only the line terminator is written.
|
||||
/// </param>
|
||||
void WriteLine(string text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ namespace Spectre.Console.Internal
|
||||
public static string GetAnsi(
|
||||
ColorSystem system,
|
||||
string text,
|
||||
Styles style,
|
||||
Decoration decoration,
|
||||
Color foreground,
|
||||
Color background)
|
||||
{
|
||||
var codes = AnsiStyleBuilder.GetAnsiCodes(style);
|
||||
var codes = AnsiDecorationBuilder.GetAnsiCodes(decoration);
|
||||
|
||||
// Got foreground?
|
||||
if (foreground != Color.Default)
|
||||
|
||||
@@ -2,52 +2,52 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class AnsiStyleBuilder
|
||||
internal static class AnsiDecorationBuilder
|
||||
{
|
||||
// TODO: Rewrite this to not yield
|
||||
public static IEnumerable<byte> GetAnsiCodes(Styles style)
|
||||
public static IEnumerable<byte> GetAnsiCodes(Decoration decoration)
|
||||
{
|
||||
if ((style & Styles.Bold) != 0)
|
||||
if ((decoration & Decoration.Bold) != 0)
|
||||
{
|
||||
yield return 1;
|
||||
}
|
||||
|
||||
if ((style & Styles.Dim) != 0)
|
||||
if ((decoration & Decoration.Dim) != 0)
|
||||
{
|
||||
yield return 2;
|
||||
}
|
||||
|
||||
if ((style & Styles.Italic) != 0)
|
||||
if ((decoration & Decoration.Italic) != 0)
|
||||
{
|
||||
yield return 3;
|
||||
}
|
||||
|
||||
if ((style & Styles.Underline) != 0)
|
||||
if ((decoration & Decoration.Underline) != 0)
|
||||
{
|
||||
yield return 4;
|
||||
}
|
||||
|
||||
if ((style & Styles.SlowBlink) != 0)
|
||||
if ((decoration & Decoration.SlowBlink) != 0)
|
||||
{
|
||||
yield return 5;
|
||||
}
|
||||
|
||||
if ((style & Styles.RapidBlink) != 0)
|
||||
if ((decoration & Decoration.RapidBlink) != 0)
|
||||
{
|
||||
yield return 6;
|
||||
}
|
||||
|
||||
if ((style & Styles.Invert) != 0)
|
||||
if ((decoration & Decoration.Invert) != 0)
|
||||
{
|
||||
yield return 7;
|
||||
}
|
||||
|
||||
if ((style & Styles.Conceal) != 0)
|
||||
if ((decoration & Decoration.Conceal) != 0)
|
||||
{
|
||||
yield return 8;
|
||||
}
|
||||
|
||||
if ((style & Styles.Strikethrough) != 0)
|
||||
if ((decoration & Decoration.Strikethrough) != 0)
|
||||
{
|
||||
yield return 9;
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class AnsiDetector
|
||||
{
|
||||
private static readonly Regex[] Regexes = new[]
|
||||
private static readonly Regex[] _regexes = new[]
|
||||
{
|
||||
new Regex("^xterm"), // xterm, PuTTY, Mintty
|
||||
new Regex("^rxvt"), // RXVT
|
||||
@@ -32,12 +32,12 @@ namespace Spectre.Console.Internal
|
||||
new Regex("bvterm"), // Bitvise SSH Client
|
||||
};
|
||||
|
||||
public static bool SupportsAnsi(bool upgrade)
|
||||
public static (bool SupportsAnsi, bool LegacyConsole) Detect(bool upgrade)
|
||||
{
|
||||
// Github action doesn't setup a correct PTY but supports ANSI.
|
||||
if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("GITHUB_ACTION")))
|
||||
{
|
||||
return true;
|
||||
return (true, false);
|
||||
}
|
||||
|
||||
// Running on Windows?
|
||||
@@ -47,23 +47,24 @@ namespace Spectre.Console.Internal
|
||||
var conEmu = Environment.GetEnvironmentVariable("ConEmuANSI");
|
||||
if (!string.IsNullOrEmpty(conEmu) && conEmu.Equals("On", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
return (true, false);
|
||||
}
|
||||
|
||||
return Windows.SupportsAnsi(upgrade);
|
||||
var supportsAnsi = Windows.SupportsAnsi(upgrade, out var legacyConsole);
|
||||
return (supportsAnsi, legacyConsole);
|
||||
}
|
||||
|
||||
// Check if the terminal is of type ANSI/VT100/xterm compatible.
|
||||
var term = Environment.GetEnvironmentVariable("TERM");
|
||||
if (!string.IsNullOrWhiteSpace(term))
|
||||
{
|
||||
if (Regexes.Any(regex => regex.IsMatch(term)))
|
||||
if (_regexes.Any(regex => regex.IsMatch(term)))
|
||||
{
|
||||
return true;
|
||||
return (true, false);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return (false, true);
|
||||
}
|
||||
|
||||
[SuppressMessage("Design", "CA1060:Move pinvokes to native methods class")]
|
||||
@@ -71,8 +72,10 @@ namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore")]
|
||||
private const int STD_OUTPUT_HANDLE = -11;
|
||||
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore")]
|
||||
private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
|
||||
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore")]
|
||||
private const uint DISABLE_NEWLINE_AUTO_RETURN = 0x0008;
|
||||
|
||||
@@ -89,12 +92,14 @@ namespace Spectre.Console.Internal
|
||||
public static extern uint GetLastError();
|
||||
|
||||
[SuppressMessage("Design", "CA1031:Do not catch general exception types")]
|
||||
public static bool SupportsAnsi(bool upgrade)
|
||||
public static bool SupportsAnsi(bool upgrade, out bool isLegacy)
|
||||
{
|
||||
isLegacy = false;
|
||||
|
||||
try
|
||||
{
|
||||
var @out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (!GetConsoleMode(@out, out uint mode))
|
||||
if (!GetConsoleMode(@out, out var mode))
|
||||
{
|
||||
// Could not get console mode.
|
||||
return false;
|
||||
@@ -102,6 +107,8 @@ namespace Spectre.Console.Internal
|
||||
|
||||
if ((mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0)
|
||||
{
|
||||
isLegacy = true;
|
||||
|
||||
if (!upgrade)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
@@ -8,8 +9,9 @@ namespace Spectre.Console.Internal
|
||||
private readonly TextWriter _out;
|
||||
private readonly ColorSystem _system;
|
||||
|
||||
public AnsiConsoleCapabilities Capabilities { get; }
|
||||
public Styles Style { get; set; }
|
||||
public Capabilities Capabilities { get; }
|
||||
public Encoding Encoding { get; }
|
||||
public Decoration Decoration { get; set; }
|
||||
public Color Foreground { get; set; }
|
||||
public Color Background { get; set; }
|
||||
|
||||
@@ -39,29 +41,16 @@ namespace Spectre.Console.Internal
|
||||
}
|
||||
}
|
||||
|
||||
public AnsiConsoleRenderer(TextWriter @out, ColorSystem system)
|
||||
public AnsiConsoleRenderer(TextWriter @out, ColorSystem system, bool legacyConsole)
|
||||
{
|
||||
_out = @out ?? throw new ArgumentNullException(nameof(@out));
|
||||
_system = system;
|
||||
|
||||
Capabilities = new AnsiConsoleCapabilities(true, system);
|
||||
Capabilities = new Capabilities(true, system, legacyConsole);
|
||||
Encoding = @out.IsStandardOut() ? System.Console.OutputEncoding : Encoding.UTF8;
|
||||
Foreground = Color.Default;
|
||||
Background = Color.Default;
|
||||
Style = Styles.None;
|
||||
}
|
||||
|
||||
public void Reset(bool colors, bool styles)
|
||||
{
|
||||
if (colors)
|
||||
{
|
||||
Foreground = Color.Default;
|
||||
Background = Color.Default;
|
||||
}
|
||||
|
||||
if (styles)
|
||||
{
|
||||
Style = Styles.None;
|
||||
}
|
||||
Decoration = Decoration.None;
|
||||
}
|
||||
|
||||
public void Write(string text)
|
||||
@@ -71,29 +60,18 @@ namespace Spectre.Console.Internal
|
||||
return;
|
||||
}
|
||||
|
||||
_out.Write(AnsiBuilder.GetAnsi(
|
||||
_system,
|
||||
text,
|
||||
Style,
|
||||
Foreground,
|
||||
Background));
|
||||
}
|
||||
var parts = text.NormalizeLineEndings().Split(new[] { '\n' });
|
||||
foreach (var (_, _, last, part) in parts.Enumerate())
|
||||
{
|
||||
if (!string.IsNullOrEmpty(part))
|
||||
{
|
||||
_out.Write(AnsiBuilder.GetAnsi(_system, part, Decoration, Foreground, Background));
|
||||
}
|
||||
|
||||
public void WriteLine(string text)
|
||||
{
|
||||
if (text == null)
|
||||
{
|
||||
_out.WriteLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
_out.WriteLine(
|
||||
AnsiBuilder.GetAnsi(
|
||||
_system,
|
||||
text,
|
||||
Style,
|
||||
Foreground,
|
||||
Background));
|
||||
if (!last)
|
||||
{
|
||||
_out.Write(Environment.NewLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
294
src/Spectre.Console/Internal/Colors/ColorPalette.Generated.cs
Normal file
294
src/Spectre.Console/Internal/Colors/ColorPalette.Generated.cs
Normal file
@@ -0,0 +1,294 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Generated 2020-08-03 15:17
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static partial class ColorPalette
|
||||
{
|
||||
private static List<Color> GenerateLegacyPalette()
|
||||
{
|
||||
return new List<Color>
|
||||
{
|
||||
Color.Black,
|
||||
Color.Maroon,
|
||||
Color.Green,
|
||||
Color.Olive,
|
||||
Color.Navy,
|
||||
Color.Purple,
|
||||
Color.Teal,
|
||||
Color.Silver,
|
||||
};
|
||||
}
|
||||
|
||||
private static List<Color> GenerateStandardPalette(IReadOnlyList<Color> legacy)
|
||||
{
|
||||
return new List<Color>(legacy)
|
||||
{
|
||||
Color.Grey,
|
||||
Color.Red,
|
||||
Color.Lime,
|
||||
Color.Yellow,
|
||||
Color.Blue,
|
||||
Color.Fuchsia,
|
||||
Color.Aqua,
|
||||
Color.White,
|
||||
};
|
||||
}
|
||||
|
||||
private static List<Color> GenerateEightBitPalette(IReadOnlyList<Color> standard)
|
||||
{
|
||||
return new List<Color>(standard)
|
||||
{
|
||||
Color.Grey0,
|
||||
Color.NavyBlue,
|
||||
Color.DarkBlue,
|
||||
Color.Blue3,
|
||||
Color.Blue3_1,
|
||||
Color.Blue1,
|
||||
Color.DarkGreen,
|
||||
Color.DeepSkyBlue4,
|
||||
Color.DeepSkyBlue4_1,
|
||||
Color.DeepSkyBlue4_2,
|
||||
Color.DodgerBlue3,
|
||||
Color.DodgerBlue2,
|
||||
Color.Green4,
|
||||
Color.SpringGreen4,
|
||||
Color.Turquoise4,
|
||||
Color.DeepSkyBlue3,
|
||||
Color.DeepSkyBlue3_1,
|
||||
Color.DodgerBlue1,
|
||||
Color.Green3,
|
||||
Color.SpringGreen3,
|
||||
Color.DarkCyan,
|
||||
Color.LightSeaGreen,
|
||||
Color.DeepSkyBlue2,
|
||||
Color.DeepSkyBlue1,
|
||||
Color.Green3_1,
|
||||
Color.SpringGreen3_1,
|
||||
Color.SpringGreen2,
|
||||
Color.Cyan3,
|
||||
Color.DarkTurquoise,
|
||||
Color.Turquoise2,
|
||||
Color.Green1,
|
||||
Color.SpringGreen2_1,
|
||||
Color.SpringGreen1,
|
||||
Color.MediumSpringGreen,
|
||||
Color.Cyan2,
|
||||
Color.Cyan1,
|
||||
Color.DarkRed,
|
||||
Color.DeepPink4,
|
||||
Color.Purple4,
|
||||
Color.Purple4_1,
|
||||
Color.Purple3,
|
||||
Color.BlueViolet,
|
||||
Color.Orange4,
|
||||
Color.Grey37,
|
||||
Color.MediumPurple4,
|
||||
Color.SlateBlue3,
|
||||
Color.SlateBlue3_1,
|
||||
Color.RoyalBlue1,
|
||||
Color.Chartreuse4,
|
||||
Color.DarkSeaGreen4,
|
||||
Color.PaleTurquoise4,
|
||||
Color.SteelBlue,
|
||||
Color.SteelBlue3,
|
||||
Color.CornflowerBlue,
|
||||
Color.Chartreuse3,
|
||||
Color.DarkSeaGreen4_1,
|
||||
Color.CadetBlue,
|
||||
Color.CadetBlue_1,
|
||||
Color.SkyBlue3,
|
||||
Color.SteelBlue1,
|
||||
Color.Chartreuse3_1,
|
||||
Color.PaleGreen3,
|
||||
Color.SeaGreen3,
|
||||
Color.Aquamarine3,
|
||||
Color.MediumTurquoise,
|
||||
Color.SteelBlue1_1,
|
||||
Color.Chartreuse2,
|
||||
Color.SeaGreen2,
|
||||
Color.SeaGreen1,
|
||||
Color.SeaGreen1_1,
|
||||
Color.Aquamarine1,
|
||||
Color.DarkSlateGray2,
|
||||
Color.DarkRed_1,
|
||||
Color.DeepPink4_1,
|
||||
Color.DarkMagenta,
|
||||
Color.DarkMagenta_1,
|
||||
Color.DarkViolet,
|
||||
Color.Purple_1,
|
||||
Color.Orange4_1,
|
||||
Color.LightPink4,
|
||||
Color.Plum4,
|
||||
Color.MediumPurple3,
|
||||
Color.MediumPurple3_1,
|
||||
Color.SlateBlue1,
|
||||
Color.Yellow4,
|
||||
Color.Wheat4,
|
||||
Color.Grey53,
|
||||
Color.LightSlateGrey,
|
||||
Color.MediumPurple,
|
||||
Color.LightSlateBlue,
|
||||
Color.Yellow4_1,
|
||||
Color.DarkOliveGreen3,
|
||||
Color.DarkSeaGreen,
|
||||
Color.LightSkyBlue3,
|
||||
Color.LightSkyBlue3_1,
|
||||
Color.SkyBlue2,
|
||||
Color.Chartreuse2_1,
|
||||
Color.DarkOliveGreen3_1,
|
||||
Color.PaleGreen3_1,
|
||||
Color.DarkSeaGreen3,
|
||||
Color.DarkSlateGray3,
|
||||
Color.SkyBlue1,
|
||||
Color.Chartreuse1,
|
||||
Color.LightGreen,
|
||||
Color.LightGreen_1,
|
||||
Color.PaleGreen1,
|
||||
Color.Aquamarine1_1,
|
||||
Color.DarkSlateGray1,
|
||||
Color.Red3,
|
||||
Color.DeepPink4_2,
|
||||
Color.MediumVioletRed,
|
||||
Color.Magenta3,
|
||||
Color.DarkViolet_1,
|
||||
Color.Purple_2,
|
||||
Color.DarkOrange3,
|
||||
Color.IndianRed,
|
||||
Color.HotPink3,
|
||||
Color.MediumOrchid3,
|
||||
Color.MediumOrchid,
|
||||
Color.MediumPurple2,
|
||||
Color.DarkGoldenrod,
|
||||
Color.LightSalmon3,
|
||||
Color.RosyBrown,
|
||||
Color.Grey63,
|
||||
Color.MediumPurple2_1,
|
||||
Color.MediumPurple1,
|
||||
Color.Gold3,
|
||||
Color.DarkKhaki,
|
||||
Color.NavajoWhite3,
|
||||
Color.Grey69,
|
||||
Color.LightSteelBlue3,
|
||||
Color.LightSteelBlue,
|
||||
Color.Yellow3,
|
||||
Color.DarkOliveGreen3_2,
|
||||
Color.DarkSeaGreen3_1,
|
||||
Color.DarkSeaGreen2,
|
||||
Color.LightCyan3,
|
||||
Color.LightSkyBlue1,
|
||||
Color.GreenYellow,
|
||||
Color.DarkOliveGreen2,
|
||||
Color.PaleGreen1_1,
|
||||
Color.DarkSeaGreen2_1,
|
||||
Color.DarkSeaGreen1,
|
||||
Color.PaleTurquoise1,
|
||||
Color.Red3_1,
|
||||
Color.DeepPink3,
|
||||
Color.DeepPink3_1,
|
||||
Color.Magenta3_1,
|
||||
Color.Magenta3_2,
|
||||
Color.Magenta2,
|
||||
Color.DarkOrange3_1,
|
||||
Color.IndianRed_1,
|
||||
Color.HotPink3_1,
|
||||
Color.HotPink2,
|
||||
Color.Orchid,
|
||||
Color.MediumOrchid1,
|
||||
Color.Orange3,
|
||||
Color.LightSalmon3_1,
|
||||
Color.LightPink3,
|
||||
Color.Pink3,
|
||||
Color.Plum3,
|
||||
Color.Violet,
|
||||
Color.Gold3_1,
|
||||
Color.LightGoldenrod3,
|
||||
Color.Tan,
|
||||
Color.MistyRose3,
|
||||
Color.Thistle3,
|
||||
Color.Plum2,
|
||||
Color.Yellow3_1,
|
||||
Color.Khaki3,
|
||||
Color.LightGoldenrod2,
|
||||
Color.LightYellow3,
|
||||
Color.Grey84,
|
||||
Color.LightSteelBlue1,
|
||||
Color.Yellow2,
|
||||
Color.DarkOliveGreen1,
|
||||
Color.DarkOliveGreen1_1,
|
||||
Color.DarkSeaGreen1_1,
|
||||
Color.Honeydew2,
|
||||
Color.LightCyan1,
|
||||
Color.Red1,
|
||||
Color.DeepPink2,
|
||||
Color.DeepPink1,
|
||||
Color.DeepPink1_1,
|
||||
Color.Magenta2_1,
|
||||
Color.Magenta1,
|
||||
Color.OrangeRed1,
|
||||
Color.IndianRed1,
|
||||
Color.IndianRed1_1,
|
||||
Color.HotPink,
|
||||
Color.HotPink_1,
|
||||
Color.MediumOrchid1_1,
|
||||
Color.DarkOrange,
|
||||
Color.Salmon1,
|
||||
Color.LightCoral,
|
||||
Color.PaleVioletRed1,
|
||||
Color.Orchid2,
|
||||
Color.Orchid1,
|
||||
Color.Orange1,
|
||||
Color.SandyBrown,
|
||||
Color.LightSalmon1,
|
||||
Color.LightPink1,
|
||||
Color.Pink1,
|
||||
Color.Plum1,
|
||||
Color.Gold1,
|
||||
Color.LightGoldenrod2_1,
|
||||
Color.LightGoldenrod2_2,
|
||||
Color.NavajoWhite1,
|
||||
Color.MistyRose1,
|
||||
Color.Thistle1,
|
||||
Color.Yellow1,
|
||||
Color.LightGoldenrod1,
|
||||
Color.Khaki1,
|
||||
Color.Wheat1,
|
||||
Color.Cornsilk1,
|
||||
Color.Grey100,
|
||||
Color.Grey3,
|
||||
Color.Grey7,
|
||||
Color.Grey11,
|
||||
Color.Grey15,
|
||||
Color.Grey19,
|
||||
Color.Grey23,
|
||||
Color.Grey27,
|
||||
Color.Grey30,
|
||||
Color.Grey35,
|
||||
Color.Grey39,
|
||||
Color.Grey42,
|
||||
Color.Grey46,
|
||||
Color.Grey50,
|
||||
Color.Grey54,
|
||||
Color.Grey58,
|
||||
Color.Grey62,
|
||||
Color.Grey66,
|
||||
Color.Grey70,
|
||||
Color.Grey74,
|
||||
Color.Grey78,
|
||||
Color.Grey82,
|
||||
Color.Grey85,
|
||||
Color.Grey89,
|
||||
Color.Grey93,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class ColorPalette
|
||||
internal static partial class ColorPalette
|
||||
{
|
||||
public static IReadOnlyList<Color> Legacy { get; }
|
||||
public static IReadOnlyList<Color> Standard { get; }
|
||||
@@ -12,92 +12,15 @@ namespace Spectre.Console.Internal
|
||||
|
||||
static ColorPalette()
|
||||
{
|
||||
Legacy = new List<Color>
|
||||
{
|
||||
Color.Black, Color.Maroon, Color.Green, Color.Olive,
|
||||
Color.Navy, Color.Purple, Color.Teal, Color.Silver,
|
||||
};
|
||||
|
||||
Standard = new List<Color>(Legacy)
|
||||
{
|
||||
Color.Grey, Color.Red, Color.Lime, Color.Yellow,
|
||||
Color.Blue, Color.Fuchsia, Color.Aqua, Color.White,
|
||||
};
|
||||
|
||||
EightBit = new List<Color>(Standard)
|
||||
{
|
||||
Color.Grey0, Color.NavyBlue, Color.DarkBlue, Color.Blue3,
|
||||
Color.Blue3_1, Color.Blue1, Color.DarkGreen, Color.DeepSkyBlue4,
|
||||
Color.DeepSkyBlue4_1, Color.DeepSkyBlue4_2, Color.DodgerBlue3, Color.DodgerBlue2,
|
||||
Color.Green4, Color.SpringGreen4, Color.Turquoise4, Color.DeepSkyBlue3,
|
||||
Color.DeepSkyBlue3_1, Color.DodgerBlue1, Color.Green3, Color.SpringGreen3,
|
||||
Color.DarkCyan, Color.LightSeaGreen, Color.DeepSkyBlue2, Color.DeepSkyBlue1,
|
||||
Color.Green3_1, Color.SpringGreen3_1, Color.SpringGreen2, Color.Cyan3,
|
||||
Color.DarkTurquoise, Color.Turquoise2, Color.Green1, Color.SpringGreen2_1,
|
||||
Color.SpringGreen1, Color.MediumSpringGreen, Color.Cyan2, Color.Cyan1,
|
||||
Color.DarkRed, Color.DeepPink4, Color.Purple4, Color.Purple4_1,
|
||||
Color.Purple3, Color.BlueViolet, Color.Orange4, Color.Grey37,
|
||||
Color.MediumPurple4, Color.SlateBlue3, Color.SlateBlue3_1, Color.RoyalBlue1,
|
||||
Color.Chartreuse4, Color.DarkSeaGreen4, Color.PaleTurquoise4, Color.SteelBlue,
|
||||
Color.SteelBlue3, Color.CornflowerBlue, Color.Chartreuse3, Color.DarkSeaGreen4_1,
|
||||
Color.CadetBlue, Color.CadetBlue_1, Color.SkyBlue3, Color.SteelBlue1,
|
||||
Color.Chartreuse3_1, Color.PaleGreen3, Color.SeaGreen3, Color.Aquamarine3,
|
||||
Color.MediumTurquoise, Color.SteelBlue1_1, Color.Chartreuse2, Color.SeaGreen2,
|
||||
Color.SeaGreen1, Color.SeaGreen1_1, Color.Aquamarine1, Color.DarkSlateGray2,
|
||||
Color.DarkRed_1, Color.DeepPink4_1, Color.DarkMagenta, Color.DarkMagenta_1,
|
||||
Color.DarkViolet, Color.Purple_1, Color.Orange4_1, Color.LightPink4,
|
||||
Color.Plum4, Color.MediumPurple3, Color.MediumPurple3_1, Color.SlateBlue1,
|
||||
Color.Yellow4, Color.Wheat4, Color.Grey53, Color.LightSlateGrey,
|
||||
Color.MediumPurple, Color.LightSlateBlue, Color.Yellow4_1, Color.DarkOliveGreen3,
|
||||
Color.DarkSeaGreen, Color.LightSkyBlue3, Color.LightSkyBlue3_1, Color.SkyBlue2,
|
||||
Color.Chartreuse2_1, Color.DarkOliveGreen3_1, Color.PaleGreen3_1, Color.DarkSeaGreen3,
|
||||
Color.DarkSlateGray3, Color.SkyBlue1, Color.Chartreuse1, Color.LightGreen,
|
||||
Color.LightGreen_1, Color.PaleGreen1, Color.Aquamarine1_1, Color.DarkSlateGray1,
|
||||
Color.Red3, Color.DeepPink4_2, Color.MediumVioletRed, Color.Magenta3,
|
||||
Color.DarkViolet_1, Color.Purple_2, Color.DarkOrange3, Color.IndianRed,
|
||||
Color.HotPink3, Color.MediumOrchid3, Color.MediumOrchid, Color.MediumPurple2,
|
||||
Color.DarkGoldenrod, Color.LightSalmon3, Color.RosyBrown, Color.Grey63,
|
||||
Color.MediumPurple2_1, Color.MediumPurple1, Color.Gold3, Color.DarkKhaki,
|
||||
Color.NavajoWhite3, Color.Grey69, Color.LightSteelBlue3, Color.LightSteelBlue,
|
||||
Color.Yellow3, Color.DarkOliveGreen3_2, Color.DarkSeaGreen3_1, Color.DarkSeaGreen2,
|
||||
Color.LightCyan3, Color.LightSkyBlue1, Color.GreenYellow, Color.DarkOliveGreen2,
|
||||
Color.PaleGreen1_1, Color.DarkSeaGreen2_1, Color.DarkSeaGreen1, Color.PaleTurquoise1,
|
||||
Color.Red3_1, Color.DeepPink3, Color.DeepPink3_1, Color.Magenta3_1,
|
||||
Color.Magenta3_2, Color.Magenta2, Color.DarkOrange3_1, Color.IndianRed_1,
|
||||
Color.HotPink3_1, Color.HotPink2, Color.Orchid, Color.MediumOrchid1,
|
||||
Color.Orange3, Color.LightSalmon3_1, Color.LightPink3, Color.Pink3,
|
||||
Color.Plum3, Color.Violet, Color.Gold3_1, Color.LightGoldenrod3,
|
||||
Color.Tan, Color.MistyRose3, Color.Thistle3, Color.Plum2,
|
||||
Color.Yellow3_1, Color.Khaki3, Color.LightGoldenrod2, Color.LightYellow3,
|
||||
Color.Grey84, Color.LightSteelBlue1, Color.Yellow2, Color.DarkOliveGreen1,
|
||||
Color.DarkOliveGreen1_1, Color.DarkSeaGreen1_1, Color.Honeydew2, Color.LightCyan1,
|
||||
Color.Red1, Color.DeepPink2, Color.DeepPink1, Color.DeepPink1_1,
|
||||
Color.Magenta2_1, Color.Magenta1, Color.OrangeRed1, Color.IndianRed1,
|
||||
Color.IndianRed1_1, Color.HotPink, Color.HotPink_1, Color.MediumOrchid1_1,
|
||||
Color.DarkOrange, Color.Salmon1, Color.LightCoral, Color.PaleVioletRed1,
|
||||
Color.Orchid2, Color.Orchid1, Color.Orange1, Color.SandyBrown,
|
||||
Color.LightSalmon1, Color.LightPink1, Color.Pink1, Color.Plum1,
|
||||
Color.Gold1, Color.LightGoldenrod2_1, Color.LightGoldenrod2_2, Color.NavajoWhite1,
|
||||
Color.MistyRose1, Color.Thistle1, Color.Yellow1, Color.LightGoldenrod1,
|
||||
Color.Khaki1, Color.Wheat1, Color.Cornsilk1, Color.Grey100,
|
||||
Color.Grey3, Color.Grey7, Color.Grey11, Color.Grey15,
|
||||
Color.Grey19, Color.Grey23, Color.Grey27, Color.Grey30,
|
||||
Color.Grey35, Color.Grey39, Color.Grey42, Color.Grey46,
|
||||
Color.Grey50, Color.Grey54, Color.Grey58, Color.Grey62,
|
||||
Color.Grey66, Color.Grey70, Color.Grey74, Color.Grey78,
|
||||
Color.Grey82, Color.Grey85, Color.Grey89, Color.Grey93,
|
||||
};
|
||||
Legacy = GenerateLegacyPalette();
|
||||
Standard = GenerateStandardPalette(Legacy);
|
||||
EightBit = GenerateEightBitPalette(Standard);
|
||||
}
|
||||
|
||||
internal static Color ExactOrClosest(ColorSystem system, Color color)
|
||||
{
|
||||
var exact = Exact(system, color);
|
||||
if (exact != null)
|
||||
{
|
||||
return exact.Value;
|
||||
}
|
||||
|
||||
return Closest(system, color);
|
||||
return exact ?? Closest(system, color);
|
||||
}
|
||||
|
||||
private static Color? Exact(ColorSystem system, Color color)
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Spectre.Console.Internal
|
||||
{
|
||||
if (supportsAnsi)
|
||||
{
|
||||
var regex = new Regex("^Microsoft Windows (?'major'[0-9]*).(?'minor'[0-9]*).(?'build'[0-9]*)$");
|
||||
var regex = new Regex("^Microsoft Windows (?'major'[0-9]*).(?'minor'[0-9]*).(?'build'[0-9]*)\\s*$");
|
||||
var match = regex.Match(RuntimeInformation.OSDescription);
|
||||
if (match.Success && int.TryParse(match.Groups["major"].Value, out var major))
|
||||
{
|
||||
|
||||
281
src/Spectre.Console/Internal/Colors/ColorTable.Generated.cs
Normal file
281
src/Spectre.Console/Internal/Colors/ColorTable.Generated.cs
Normal file
@@ -0,0 +1,281 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Generated 2020-08-03 15:17
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static partial class ColorTable
|
||||
{
|
||||
private static Dictionary<string, int> GenerateTable()
|
||||
{
|
||||
return new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "black", 0 },
|
||||
{ "maroon", 1 },
|
||||
{ "green", 2 },
|
||||
{ "olive", 3 },
|
||||
{ "navy", 4 },
|
||||
{ "purple", 5 },
|
||||
{ "teal", 6 },
|
||||
{ "silver", 7 },
|
||||
{ "grey", 8 },
|
||||
{ "red", 9 },
|
||||
{ "lime", 10 },
|
||||
{ "yellow", 11 },
|
||||
{ "blue", 12 },
|
||||
{ "fuchsia", 13 },
|
||||
{ "aqua", 14 },
|
||||
{ "white", 15 },
|
||||
{ "grey0", 16 },
|
||||
{ "navyblue", 17 },
|
||||
{ "darkblue", 18 },
|
||||
{ "blue3", 19 },
|
||||
{ "blue3_1", 20 },
|
||||
{ "blue1", 21 },
|
||||
{ "darkgreen", 22 },
|
||||
{ "deepskyblue4", 23 },
|
||||
{ "deepskyblue4_1", 24 },
|
||||
{ "deepskyblue4_2", 25 },
|
||||
{ "dodgerblue3", 26 },
|
||||
{ "dodgerblue2", 27 },
|
||||
{ "green4", 28 },
|
||||
{ "springgreen4", 29 },
|
||||
{ "turquoise4", 30 },
|
||||
{ "deepskyblue3", 31 },
|
||||
{ "deepskyblue3_1", 32 },
|
||||
{ "dodgerblue1", 33 },
|
||||
{ "green3", 34 },
|
||||
{ "springgreen3", 35 },
|
||||
{ "darkcyan", 36 },
|
||||
{ "lightseagreen", 37 },
|
||||
{ "deepskyblue2", 38 },
|
||||
{ "deepskyblue1", 39 },
|
||||
{ "green3_1", 40 },
|
||||
{ "springgreen3_1", 41 },
|
||||
{ "springgreen2", 42 },
|
||||
{ "cyan3", 43 },
|
||||
{ "darkturquoise", 44 },
|
||||
{ "turquoise2", 45 },
|
||||
{ "green1", 46 },
|
||||
{ "springgreen2_1", 47 },
|
||||
{ "springgreen1", 48 },
|
||||
{ "mediumspringgreen", 49 },
|
||||
{ "cyan2", 50 },
|
||||
{ "cyan1", 51 },
|
||||
{ "darkred", 52 },
|
||||
{ "deeppink4", 53 },
|
||||
{ "purple4", 54 },
|
||||
{ "purple4_1", 55 },
|
||||
{ "purple3", 56 },
|
||||
{ "blueviolet", 57 },
|
||||
{ "orange4", 58 },
|
||||
{ "grey37", 59 },
|
||||
{ "mediumpurple4", 60 },
|
||||
{ "slateblue3", 61 },
|
||||
{ "slateblue3_1", 62 },
|
||||
{ "royalblue1", 63 },
|
||||
{ "chartreuse4", 64 },
|
||||
{ "darkseagreen4", 65 },
|
||||
{ "paleturquoise4", 66 },
|
||||
{ "steelblue", 67 },
|
||||
{ "steelblue3", 68 },
|
||||
{ "cornflowerblue", 69 },
|
||||
{ "chartreuse3", 70 },
|
||||
{ "darkseagreen4_1", 71 },
|
||||
{ "cadetblue", 72 },
|
||||
{ "cadetblue_1", 73 },
|
||||
{ "skyblue3", 74 },
|
||||
{ "steelblue1", 75 },
|
||||
{ "chartreuse3_1", 76 },
|
||||
{ "palegreen3", 77 },
|
||||
{ "seagreen3", 78 },
|
||||
{ "aquamarine3", 79 },
|
||||
{ "mediumturquoise", 80 },
|
||||
{ "steelblue1_1", 81 },
|
||||
{ "chartreuse2", 82 },
|
||||
{ "seagreen2", 83 },
|
||||
{ "seagreen1", 84 },
|
||||
{ "seagreen1_1", 85 },
|
||||
{ "aquamarine1", 86 },
|
||||
{ "darkslategray2", 87 },
|
||||
{ "darkred_1", 88 },
|
||||
{ "deeppink4_1", 89 },
|
||||
{ "darkmagenta", 90 },
|
||||
{ "darkmagenta_1", 91 },
|
||||
{ "darkviolet", 92 },
|
||||
{ "purple_1", 93 },
|
||||
{ "orange4_1", 94 },
|
||||
{ "lightpink4", 95 },
|
||||
{ "plum4", 96 },
|
||||
{ "mediumpurple3", 97 },
|
||||
{ "mediumpurple3_1", 98 },
|
||||
{ "slateblue1", 99 },
|
||||
{ "yellow4", 100 },
|
||||
{ "wheat4", 101 },
|
||||
{ "grey53", 102 },
|
||||
{ "lightslategrey", 103 },
|
||||
{ "mediumpurple", 104 },
|
||||
{ "lightslateblue", 105 },
|
||||
{ "yellow4_1", 106 },
|
||||
{ "darkolivegreen3", 107 },
|
||||
{ "darkseagreen", 108 },
|
||||
{ "lightskyblue3", 109 },
|
||||
{ "lightskyblue3_1", 110 },
|
||||
{ "skyblue2", 111 },
|
||||
{ "chartreuse2_1", 112 },
|
||||
{ "darkolivegreen3_1", 113 },
|
||||
{ "palegreen3_1", 114 },
|
||||
{ "darkseagreen3", 115 },
|
||||
{ "darkslategray3", 116 },
|
||||
{ "skyblue1", 117 },
|
||||
{ "chartreuse1", 118 },
|
||||
{ "lightgreen", 119 },
|
||||
{ "lightgreen_1", 120 },
|
||||
{ "palegreen1", 121 },
|
||||
{ "aquamarine1_1", 122 },
|
||||
{ "darkslategray1", 123 },
|
||||
{ "red3", 124 },
|
||||
{ "deeppink4_2", 125 },
|
||||
{ "mediumvioletred", 126 },
|
||||
{ "magenta3", 127 },
|
||||
{ "darkviolet_1", 128 },
|
||||
{ "purple_2", 129 },
|
||||
{ "darkorange3", 130 },
|
||||
{ "indianred", 131 },
|
||||
{ "hotpink3", 132 },
|
||||
{ "mediumorchid3", 133 },
|
||||
{ "mediumorchid", 134 },
|
||||
{ "mediumpurple2", 135 },
|
||||
{ "darkgoldenrod", 136 },
|
||||
{ "lightsalmon3", 137 },
|
||||
{ "rosybrown", 138 },
|
||||
{ "grey63", 139 },
|
||||
{ "mediumpurple2_1", 140 },
|
||||
{ "mediumpurple1", 141 },
|
||||
{ "gold3", 142 },
|
||||
{ "darkkhaki", 143 },
|
||||
{ "navajowhite3", 144 },
|
||||
{ "grey69", 145 },
|
||||
{ "lightsteelblue3", 146 },
|
||||
{ "lightsteelblue", 147 },
|
||||
{ "yellow3", 148 },
|
||||
{ "darkolivegreen3_2", 149 },
|
||||
{ "darkseagreen3_1", 150 },
|
||||
{ "darkseagreen2", 151 },
|
||||
{ "lightcyan3", 152 },
|
||||
{ "lightskyblue1", 153 },
|
||||
{ "greenyellow", 154 },
|
||||
{ "darkolivegreen2", 155 },
|
||||
{ "palegreen1_1", 156 },
|
||||
{ "darkseagreen2_1", 157 },
|
||||
{ "darkseagreen1", 158 },
|
||||
{ "paleturquoise1", 159 },
|
||||
{ "red3_1", 160 },
|
||||
{ "deeppink3", 161 },
|
||||
{ "deeppink3_1", 162 },
|
||||
{ "magenta3_1", 163 },
|
||||
{ "magenta3_2", 164 },
|
||||
{ "magenta2", 165 },
|
||||
{ "darkorange3_1", 166 },
|
||||
{ "indianred_1", 167 },
|
||||
{ "hotpink3_1", 168 },
|
||||
{ "hotpink2", 169 },
|
||||
{ "orchid", 170 },
|
||||
{ "mediumorchid1", 171 },
|
||||
{ "orange3", 172 },
|
||||
{ "lightsalmon3_1", 173 },
|
||||
{ "lightpink3", 174 },
|
||||
{ "pink3", 175 },
|
||||
{ "plum3", 176 },
|
||||
{ "violet", 177 },
|
||||
{ "gold3_1", 178 },
|
||||
{ "lightgoldenrod3", 179 },
|
||||
{ "tan", 180 },
|
||||
{ "mistyrose3", 181 },
|
||||
{ "thistle3", 182 },
|
||||
{ "plum2", 183 },
|
||||
{ "yellow3_1", 184 },
|
||||
{ "khaki3", 185 },
|
||||
{ "lightgoldenrod2", 186 },
|
||||
{ "lightyellow3", 187 },
|
||||
{ "grey84", 188 },
|
||||
{ "lightsteelblue1", 189 },
|
||||
{ "yellow2", 190 },
|
||||
{ "darkolivegreen1", 191 },
|
||||
{ "darkolivegreen1_1", 192 },
|
||||
{ "darkseagreen1_1", 193 },
|
||||
{ "honeydew2", 194 },
|
||||
{ "lightcyan1", 195 },
|
||||
{ "red1", 196 },
|
||||
{ "deeppink2", 197 },
|
||||
{ "deeppink1", 198 },
|
||||
{ "deeppink1_1", 199 },
|
||||
{ "magenta2_1", 200 },
|
||||
{ "magenta1", 201 },
|
||||
{ "orangered1", 202 },
|
||||
{ "indianred1", 203 },
|
||||
{ "indianred1_1", 204 },
|
||||
{ "hotpink", 205 },
|
||||
{ "hotpink_1", 206 },
|
||||
{ "mediumorchid1_1", 207 },
|
||||
{ "darkorange", 208 },
|
||||
{ "salmon1", 209 },
|
||||
{ "lightcoral", 210 },
|
||||
{ "palevioletred1", 211 },
|
||||
{ "orchid2", 212 },
|
||||
{ "orchid1", 213 },
|
||||
{ "orange1", 214 },
|
||||
{ "sandybrown", 215 },
|
||||
{ "lightsalmon1", 216 },
|
||||
{ "lightpink1", 217 },
|
||||
{ "pink1", 218 },
|
||||
{ "plum1", 219 },
|
||||
{ "gold1", 220 },
|
||||
{ "lightgoldenrod2_1", 221 },
|
||||
{ "lightgoldenrod2_2", 222 },
|
||||
{ "navajowhite1", 223 },
|
||||
{ "mistyrose1", 224 },
|
||||
{ "thistle1", 225 },
|
||||
{ "yellow1", 226 },
|
||||
{ "lightgoldenrod1", 227 },
|
||||
{ "khaki1", 228 },
|
||||
{ "wheat1", 229 },
|
||||
{ "cornsilk1", 230 },
|
||||
{ "grey100", 231 },
|
||||
{ "grey3", 232 },
|
||||
{ "grey7", 233 },
|
||||
{ "grey11", 234 },
|
||||
{ "grey15", 235 },
|
||||
{ "grey19", 236 },
|
||||
{ "grey23", 237 },
|
||||
{ "grey27", 238 },
|
||||
{ "grey30", 239 },
|
||||
{ "grey35", 240 },
|
||||
{ "grey39", 241 },
|
||||
{ "grey42", 242 },
|
||||
{ "grey46", 243 },
|
||||
{ "grey50", 244 },
|
||||
{ "grey54", 245 },
|
||||
{ "grey58", 246 },
|
||||
{ "grey62", 247 },
|
||||
{ "grey66", 248 },
|
||||
{ "grey70", 249 },
|
||||
{ "grey74", 250 },
|
||||
{ "grey78", 251 },
|
||||
{ "grey82", 252 },
|
||||
{ "grey85", 253 },
|
||||
{ "grey89", 254 },
|
||||
{ "grey93", 255 },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/Spectre.Console/Internal/Colors/ColorTable.cs
Normal file
54
src/Spectre.Console/Internal/Colors/ColorTable.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static partial class ColorTable
|
||||
{
|
||||
private static readonly Dictionary<int, string> _nameLookup;
|
||||
private static readonly Dictionary<string, int> _numberLookup;
|
||||
|
||||
[SuppressMessage("Performance", "CA1810:Initialize reference type static fields inline")]
|
||||
static ColorTable()
|
||||
{
|
||||
_numberLookup = GenerateTable();
|
||||
_nameLookup = new Dictionary<int, string>();
|
||||
foreach (var pair in _numberLookup)
|
||||
{
|
||||
_nameLookup.Add(pair.Value, pair.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public static Color GetColor(int number)
|
||||
{
|
||||
if (number < 0 || number > 255)
|
||||
{
|
||||
throw new InvalidOperationException("Color number must be between 0 and 255");
|
||||
}
|
||||
|
||||
return ColorPalette.EightBit[number];
|
||||
}
|
||||
|
||||
public static Color? GetColor(string name)
|
||||
{
|
||||
if (!_numberLookup.TryGetValue(name, out var number))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (number > ColorPalette.EightBit.Count - 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ColorPalette.EightBit[number];
|
||||
}
|
||||
|
||||
public static string GetName(int number)
|
||||
{
|
||||
_nameLookup.TryGetValue(number, out var name);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal sealed class Composer : IRenderable
|
||||
{
|
||||
private readonly BlockElement _root;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length => _root.Length;
|
||||
|
||||
public Composer()
|
||||
{
|
||||
_root = new BlockElement();
|
||||
}
|
||||
|
||||
public static Composer New()
|
||||
{
|
||||
return new Composer();
|
||||
}
|
||||
|
||||
public Composer Text(string text)
|
||||
{
|
||||
_root.Append(new TextElement(text));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Foreground(Color color, Action<Composer> action)
|
||||
{
|
||||
if (action is null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
var content = new Composer();
|
||||
action(content);
|
||||
_root.Append(new ForegroundElement(color, content));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Background(Color color, Action<Composer> action)
|
||||
{
|
||||
if (action is null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
var content = new Composer();
|
||||
action(content);
|
||||
_root.Append(new BackgroundElement(color, content));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Style(Styles style, Action<Composer> action)
|
||||
{
|
||||
if (action is null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
var content = new Composer();
|
||||
action(content);
|
||||
_root.Append(new StyleElement(style, content));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
_root.Render(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Not used (yet)")]
|
||||
internal sealed class BackgroundElement : IRenderable
|
||||
{
|
||||
private readonly Color _color;
|
||||
private readonly IRenderable _element;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length => _element.Length;
|
||||
|
||||
public BackgroundElement(Color color, IRenderable element)
|
||||
{
|
||||
_color = color;
|
||||
_element = element ?? throw new ArgumentNullException(nameof(element));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
if (renderer is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(renderer));
|
||||
}
|
||||
|
||||
using (renderer.PushColor(_color, foreground: false))
|
||||
{
|
||||
_element.Render(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Not used (yet)")]
|
||||
internal sealed class BlockElement : IRenderable
|
||||
{
|
||||
private readonly List<IRenderable> _elements;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length { get; private set; }
|
||||
|
||||
public IReadOnlyList<IRenderable> Elements => _elements;
|
||||
|
||||
public BlockElement()
|
||||
{
|
||||
_elements = new List<IRenderable>();
|
||||
}
|
||||
|
||||
public BlockElement Append(IRenderable element)
|
||||
{
|
||||
if (element != null)
|
||||
{
|
||||
_elements.Add(element);
|
||||
Length += element.Length;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
foreach (var element in _elements)
|
||||
{
|
||||
element.Render(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Not used (yet)")]
|
||||
internal sealed class ForegroundElement : IRenderable
|
||||
{
|
||||
private readonly Color _color;
|
||||
private readonly IRenderable _element;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length => _element.Length;
|
||||
|
||||
public ForegroundElement(Color color, IRenderable element)
|
||||
{
|
||||
_color = color;
|
||||
_element = element ?? throw new ArgumentNullException(nameof(element));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
if (renderer is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(renderer));
|
||||
}
|
||||
|
||||
using (renderer.PushColor(_color, foreground: true))
|
||||
{
|
||||
_element.Render(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Not used (yet)")]
|
||||
internal sealed class LineBreakElement : IRenderable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public int Length => 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
renderer.Write(Environment.NewLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Not used (yet)")]
|
||||
internal sealed class StyleElement : IRenderable
|
||||
{
|
||||
private readonly Styles _style;
|
||||
private readonly IRenderable _element;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length => _element.Length;
|
||||
|
||||
public StyleElement(Styles style, IRenderable element)
|
||||
{
|
||||
_style = style;
|
||||
_element = element ?? throw new ArgumentNullException(nameof(element));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
if (renderer is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(renderer));
|
||||
}
|
||||
|
||||
using (renderer.PushStyle(_style))
|
||||
{
|
||||
_element.Render(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Not used (yet)")]
|
||||
internal sealed class TextElement : IRenderable
|
||||
{
|
||||
private readonly string _text;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length => _text.Length;
|
||||
|
||||
public TextElement(string text)
|
||||
{
|
||||
_text = text ?? throw new System.ArgumentNullException(nameof(text));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
renderer.Write(_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents something that can be rendered to a console.
|
||||
/// </summary>
|
||||
internal interface IRenderable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the length of the element.
|
||||
/// </summary>
|
||||
int Length { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Renders the element using the specified renderer.
|
||||
/// </summary>
|
||||
/// <param name="console">The renderer to use.</param>
|
||||
void Render(IAnsiConsole console);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using Spectre.Console.Internal;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class ConsoleBuilder
|
||||
{
|
||||
@@ -14,9 +14,41 @@ namespace Spectre.Console
|
||||
|
||||
var buffer = settings.Out ?? System.Console.Out;
|
||||
|
||||
var supportsAnsi = settings.Ansi == AnsiSupport.Detect
|
||||
? AnsiDetector.SupportsAnsi(true)
|
||||
: settings.Ansi == AnsiSupport.Yes;
|
||||
var supportsAnsi = settings.Ansi == AnsiSupport.Yes;
|
||||
var legacyConsole = false;
|
||||
|
||||
if (settings.Ansi == AnsiSupport.Detect)
|
||||
{
|
||||
(supportsAnsi, legacyConsole) = AnsiDetector.Detect(true);
|
||||
|
||||
// Check whether or not this is a legacy console from the existing instance (if any).
|
||||
// We need to do this because once we upgrade the console to support ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
// on Windows, there is no way of detecting whether or not we're running on a legacy console or not.
|
||||
if (AnsiConsole.Created && !legacyConsole && buffer.IsStandardOut() && AnsiConsole.Capabilities.LegacyConsole)
|
||||
{
|
||||
legacyConsole = AnsiConsole.Capabilities.LegacyConsole;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buffer.IsStandardOut())
|
||||
{
|
||||
// Are we running on Windows?
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
// Not the first console we're creating?
|
||||
if (AnsiConsole.Created)
|
||||
{
|
||||
legacyConsole = AnsiConsole.Capabilities.LegacyConsole;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try detecting whether or not this
|
||||
(_, legacyConsole) = AnsiDetector.Detect(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var colorSystem = settings.ColorSystem == ColorSystemSupport.Detect
|
||||
? ColorSystemDetector.Detect(supportsAnsi)
|
||||
@@ -24,13 +56,13 @@ namespace Spectre.Console
|
||||
|
||||
if (supportsAnsi)
|
||||
{
|
||||
return new AnsiConsoleRenderer(buffer, colorSystem)
|
||||
return new AnsiConsoleRenderer(buffer, colorSystem, legacyConsole)
|
||||
{
|
||||
Style = Styles.None,
|
||||
Decoration = Decoration.None,
|
||||
};
|
||||
}
|
||||
|
||||
return new FallbackConsoleRenderer(buffer, colorSystem);
|
||||
return new FallbackConsoleRenderer(buffer, colorSystem, legacyConsole);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
35
src/Spectre.Console/Internal/DecorationTable.cs
Normal file
35
src/Spectre.Console/Internal/DecorationTable.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class DecorationTable
|
||||
{
|
||||
private static readonly Dictionary<string, Decoration?> _lookup;
|
||||
|
||||
[SuppressMessage("Performance", "CA1810:Initialize reference type static fields inline")]
|
||||
static DecorationTable()
|
||||
{
|
||||
_lookup = new Dictionary<string, Decoration?>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "none", Decoration.None },
|
||||
{ "bold", Decoration.Bold },
|
||||
{ "dim", Decoration.Dim },
|
||||
{ "italic", Decoration.Italic },
|
||||
{ "underline", Decoration.Underline },
|
||||
{ "invert", Decoration.Invert },
|
||||
{ "conceal", Decoration.Conceal },
|
||||
{ "slowblink", Decoration.SlowBlink },
|
||||
{ "rapidblink", Decoration.RapidBlink },
|
||||
{ "strikethrough", Decoration.Strikethrough },
|
||||
};
|
||||
}
|
||||
|
||||
public static Decoration? GetDecoration(string name)
|
||||
{
|
||||
_lookup.TryGetValue(name, out var result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,25 @@ namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class ConsoleExtensions
|
||||
{
|
||||
public static IDisposable PushStyle(this IAnsiConsole console, Style style)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
if (style is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(style));
|
||||
}
|
||||
|
||||
var current = new Style(console.Foreground, console.Background, console.Decoration);
|
||||
console.SetColor(style.Foreground, true);
|
||||
console.SetColor(style.Background, false);
|
||||
console.Decoration = style.Decoration;
|
||||
return new StyleScope(console, current);
|
||||
}
|
||||
|
||||
public static IDisposable PushColor(this IAnsiConsole console, Color color, bool foreground)
|
||||
{
|
||||
if (console is null)
|
||||
@@ -12,21 +31,21 @@ namespace Spectre.Console.Internal
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
var current = console.Foreground;
|
||||
var current = foreground ? console.Foreground : console.Background;
|
||||
console.SetColor(color, foreground);
|
||||
return new ColorScope(console, current, foreground);
|
||||
}
|
||||
|
||||
public static IDisposable PushStyle(this IAnsiConsole console, Styles style)
|
||||
public static IDisposable PushDecoration(this IAnsiConsole console, Decoration decoration)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
var current = console.Style;
|
||||
console.Style = style;
|
||||
return new StyleScope(console, current);
|
||||
var current = console.Decoration;
|
||||
console.Decoration = decoration;
|
||||
return new DecorationScope(console, current);
|
||||
}
|
||||
|
||||
public static void SetColor(this IAnsiConsole console, Color color, bool foreground)
|
||||
@@ -47,6 +66,33 @@ namespace Spectre.Console.Internal
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class StyleScope : IDisposable
|
||||
{
|
||||
private readonly IAnsiConsole _console;
|
||||
private readonly Style _style;
|
||||
|
||||
public StyleScope(IAnsiConsole console, Style style)
|
||||
{
|
||||
_console = console ?? throw new ArgumentNullException(nameof(console));
|
||||
_style = style ?? throw new ArgumentNullException(nameof(style));
|
||||
}
|
||||
|
||||
[SuppressMessage("Design", "CA1065:Do not raise exceptions in unexpected locations")]
|
||||
[SuppressMessage("Performance", "CA1821:Remove empty Finalizers")]
|
||||
~StyleScope()
|
||||
{
|
||||
throw new InvalidOperationException("Style scope was not disposed.");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
_console.SetColor(_style.Foreground, true);
|
||||
_console.SetColor(_style.Background, false);
|
||||
_console.Decoration = _style.Decoration;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ColorScope : IDisposable
|
||||
{
|
||||
private readonly IAnsiConsole _console;
|
||||
@@ -74,28 +120,28 @@ namespace Spectre.Console.Internal
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class StyleScope : IDisposable
|
||||
internal sealed class DecorationScope : IDisposable
|
||||
{
|
||||
private readonly IAnsiConsole _console;
|
||||
private readonly Styles _style;
|
||||
private readonly Decoration _decoration;
|
||||
|
||||
public StyleScope(IAnsiConsole console, Styles color)
|
||||
public DecorationScope(IAnsiConsole console, Decoration decoration)
|
||||
{
|
||||
_console = console ?? throw new ArgumentNullException(nameof(console));
|
||||
_style = color;
|
||||
_decoration = decoration;
|
||||
}
|
||||
|
||||
[SuppressMessage("Design", "CA1065:Do not raise exceptions in unexpected locations")]
|
||||
[SuppressMessage("Performance", "CA1821:Remove empty Finalizers")]
|
||||
~StyleScope()
|
||||
~DecorationScope()
|
||||
{
|
||||
throw new InvalidOperationException("Style scope was not disposed.");
|
||||
throw new InvalidOperationException("Decoration scope was not disposed.");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
_console.Style = _style;
|
||||
_console.Decoration = _decoration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class EnumerableExtensions
|
||||
{
|
||||
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||
{
|
||||
foreach (var item in source)
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool AnyTrue(this IEnumerable<bool> source)
|
||||
{
|
||||
return source.Any(b => b);
|
||||
}
|
||||
|
||||
public static IEnumerable<(int Index, bool First, bool Last, T Item)> Enumerate<T>(this IEnumerable<T> source)
|
||||
{
|
||||
if (source is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
return Enumerate(source.GetEnumerator());
|
||||
}
|
||||
|
||||
public static IEnumerable<(int Index, bool First, bool Last, T Item)> Enumerate<T>(this IEnumerator<T> source)
|
||||
{
|
||||
if (source is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
var first = true;
|
||||
var last = !source.MoveNext();
|
||||
T current;
|
||||
|
||||
for (var index = 0; !last; index++)
|
||||
{
|
||||
current = source.Current;
|
||||
last = !source.MoveNext();
|
||||
yield return (index, first, last, current);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<TResult> SelectIndex<T, TResult>(this IEnumerable<T> source, Func<T, int, TResult> func)
|
||||
{
|
||||
return source.Select((value, index) => func(value, index));
|
||||
}
|
||||
|
||||
public static IEnumerable<(TFirst First, TSecond Second)> Zip<TFirst, TSecond>(
|
||||
this IEnumerable<TFirst> source, IEnumerable<TSecond> first)
|
||||
{
|
||||
return source.Zip(first, (first, second) => (first, second));
|
||||
}
|
||||
|
||||
public static IEnumerable<(TFirst First, TSecond Second, TThird Third)> Zip<TFirst, TSecond, TThird>(
|
||||
this IEnumerable<TFirst> first, IEnumerable<TSecond> second, IEnumerable<TThird> third)
|
||||
{
|
||||
return first.Zip(second, (a, b) => (a, b))
|
||||
.Zip(third, (a, b) => (a.a, a.b, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user