Compare commits

...

53 Commits

Author SHA1 Message Date
Patrik Svensson
e429f6434b Update examples 2020-10-01 14:43:08 +02:00
Patrik Svensson
93ec7401c8 Add support for markdown tables
Closes #85

* Split Border into BoxBorder and TableBorder
* Change how different table parts are composed
* Add markdown table border
2020-10-01 14:43:08 +02:00
Patrik Svensson
697273917e Move console encoder to rendering namespace 2020-09-21 17:07:05 +02:00
Patrik Svensson
2943535973 Make segments immutable 2020-09-21 17:03:17 +02:00
Patrik Svensson
cd0d182f12 Add support for recording console output
This commit adds support for recording console output
as well as exporting it to either text or HTML. A user can
also provide their own encoder if they wish.
2020-09-21 13:33:28 +02:00
Patrik Svensson
b197f278ed Add support for rows
Closes #69
2020-09-20 19:17:33 +02:00
Patrik Svensson
3847a8949f Fix bug with uris being interpreted as emojis
Closes #82
2020-09-20 13:00:44 +02:00
Patrik Svensson
eeb3f967b6 Update emoji support
* Add constants for emojis
* Move emoji shortcode rendering to Markup
* Add documentation
* Add example
* Add tests
2020-09-18 16:11:51 +02:00
Patrik Svensson
090b30f731 Use Wcwidth library 2020-09-18 15:31:12 +02:00
Patrik Svensson
df291ef84e Fix Info example emoji problem
The emojis that previously were used, used Unicode combinators
which are not fully supported. Changing to :thumbs_up: and :thumbs_down:
instead.
2020-09-17 10:58:50 +02:00
Patrik Svensson
7d6104ace4 Add padder widget
This commit adds a padder can be use to pad other IRenderable
objects such as tables, panels, grids, text, etc.
2020-09-17 10:58:50 +02:00
Kristian Hellang
314456ca17 Add emoji codes to example 2020-09-17 10:35:15 +02:00
Kristian Hellang
b7f654cd7f Replace emoji in segment text 2020-09-17 10:35:15 +02:00
Kristian Hellang
fea8a36e8a Add generated Emoji class with corresponding non-generated file 2020-09-17 10:35:15 +02:00
Kristian Hellang
0632b38477 Fix relative path in existing color script 2020-09-17 10:35:15 +02:00
Kristian Hellang
a7b7d4e556 Add Generator command to generate emoji lookup table 2020-09-17 10:35:15 +02:00
Kristian Hellang
11d331e31d Add .DS_Store to .gitignore 2020-09-17 10:35:15 +02:00
Patrik Svensson
ce670a7ca9 Add link identity generator 2020-09-12 14:47:32 +02:00
Patrik Svensson
101e244059 Minor clean up 2020-09-12 10:46:57 +02:00
Patrik Svensson
504746c5dc Add link support for supported terminals
Also refactors the code quite a bit, to make it a bit more
easier to add features like this in the future.

Closes #75
2020-09-11 17:44:56 +02:00
Patrik Svensson
1601ef24b3 Update border documentation 2020-09-09 14:27:40 +02:00
Patrik Svensson
b46d0fa4f6 Group IAnsiConsole extensions in csproj 2020-09-09 08:47:55 +02:00
Patrik Svensson
4f06687104 Restructure solution a bit 2020-09-09 08:43:48 +02:00
Patrik Svensson
003e15686f Add documentation for tables
Also moves "Colors" and "Styles" sections to appendix.
2020-09-08 18:21:52 +02:00
Patrik Svensson
3e9796849b Add more borders for grids, tables, and panels
* Ascii2
* AsciiDoubleHead
* Double
* DoubleEdge
* Heavy
* HeavyEdge
* HeavyHead
* Horizontal
* Minimal
* MinimalDoubleHead
* MinimalHeavyHead
* Simple
* SimpleHeavy
2020-09-08 00:16:20 +02:00
Patrik Svensson
3cc19520b0 Add implicit conversion op from string to Style
Closes #71
2020-09-06 23:03:51 +02:00
Patrik Svensson
87bde3e5a2 Remove BorderKind in favour of Border 2020-09-06 12:29:48 +02:00
Patrik Svensson
e6e9a4d950 Add description for 'Info' example 2020-09-05 08:52:06 +02:00
Patrik Svensson
29ce14e1e8 Rename 'Diagnostic' example to 'Info' 2020-09-05 08:50:00 +02:00
Patrik Svensson
ceb3572d6a Make table and grid extension methods fluent 2020-09-05 08:49:36 +02:00
Patrik Svensson
13c56eca01 Allow mutation of segments 2020-09-05 08:39:48 +02:00
Patrik Svensson
a477884d36 Move Panel extensions to Spectre.Console namespace 2020-09-05 08:20:13 +02:00
Patrik Svensson
ae6d2c63a3 Add column support
Adds support for rendering arbitrary data into columns.

Closes #67
2020-09-05 07:45:38 +02:00
Patrik Svensson
e946289bd9 Make styles composable
Also adds some new extension methods and make some APIs a bit more consistent.

Closes #64
2020-09-03 21:26:20 +02:00
Patrik Svensson
bcaaa6b2d3 Update table of contents (skip-ci) 2020-09-03 20:04:06 +02:00
Patrik Svensson
d3588a4b06 Remove styles and colors (skip-ci) 2020-09-03 20:03:26 +02:00
Patrik Svensson
7471e9d38c Add panel header support
Closes #63
2020-09-03 19:02:29 +02:00
Patrik Svensson
9f8ca6d648 Add text overflow support
Closes #61
2020-09-03 14:57:57 +02:00
Patrik Svensson
88edfe68ec Add border for color representations 2020-09-02 09:55:44 +02:00
Patrik Svensson
5d32764a64 Fix typo: SRG -> SGR 2020-09-02 09:02:59 +02:00
Patrik Svensson
4f6c9c62c7 Set fetch depth to 0 2020-09-01 22:05:46 +02:00
Patrik Svensson
f2677213a4 Separate build and run when publishing docs 2020-09-01 22:00:44 +02:00
Patrik Svensson
bdaf00a556 Remove empty documentation pages 2020-09-01 21:51:25 +02:00
Patrik Svensson
7de4b6c7b9 Build docs as part of CI 2020-09-01 21:50:36 +02:00
Patrik Svensson
0bc801e3eb Build docs when source change 2020-09-01 21:40:49 +02:00
Patrik Svensson
88a82cdad0 Build docs in release mode 2020-09-01 21:39:40 +02:00
Patrik Svensson
0cecb555d5 Show documentation version in footer 2020-09-01 21:33:15 +02:00
Patrik Svensson
52e3ee17b0 Fix logo link 2020-09-01 21:28:52 +02:00
Dave Glick
caf7661e66 Moves all the pages up a level and hardcodes the section name 2020-09-01 21:23:01 +02:00
Dave Glick
65f0a085cc Updated to the latest Statiq Web with breakage fixes 2020-09-01 21:03:47 +02:00
Patrik Svensson
a123806cd8 Add docs for escaping [ and ] in markup 2020-09-01 16:52:40 +02:00
Patrik Svensson
173645cdd2 Added documentation for markup text 2020-08-31 14:05:28 +02:00
Patrik Svensson
7fd2efaeb5 Merge segments before rendering
This will reduce the number of segments to render
and produce cleaner ANSI escape code sequences.

Closes #46
2020-08-30 12:40:34 +02:00
220 changed files with 24858 additions and 3237 deletions

View File

@@ -6,6 +6,35 @@ env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
###################################################
# DOCS
###################################################
docs:
name: Documentation
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
- name: Setup dotnet
uses: actions/setup-dotnet@v1
with:
dotnet-version: '3.1.301' # SDK Version to use.
- name: Build
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cd docs
dotnet run --configuration Release
###################################################
# BUILD
###################################################
build:
name: Build
if: "!contains(github.event.head_commit.message, 'skip-ci')"
@@ -35,11 +64,12 @@ jobs:
shell: bash
run: |
dotnet tool restore
dotnet example diagnostic
dotnet example table
dotnet example grid
dotnet example panel
dotnet example info
dotnet example tables
dotnet example grids
dotnet example panels
dotnet example colors
dotnet example emojis
- name: Build
shell: bash

View File

@@ -4,14 +4,22 @@ on:
push:
paths:
- 'docs/**'
- 'src/**'
jobs:
###################################################
# DOCS
###################################################
build:
name: Deploy
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@master
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup dotnet
uses: actions/setup-dotnet@v1
@@ -24,4 +32,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cd docs
dotnet run -- deploy
dotnet run --configuration Release -- deploy

View File

@@ -6,6 +6,8 @@ on:
- '*'
branches:
- main
paths:
- 'src/**'
env:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
@@ -13,12 +15,37 @@ env:
jobs:
###################################################
# DOCS
###################################################
docs:
name: Documentation
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
- name: Setup dotnet
uses: actions/setup-dotnet@v1
with:
dotnet-version: '3.1.301' # SDK Version to use.
- name: Build
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cd docs
dotnet run --configuration Release
###################################################
# BUILD
###################################################
build:
name: Build
needs: [docs]
if: "!contains(github.event.head_commit.message, 'skip-ci') || startsWith(github.ref, 'refs/tags/')"
strategy:
matrix:

1
.gitignore vendored
View File

@@ -5,6 +5,7 @@
[Pp]ackages/
/.artifacts/
/[Tt]ools/
.DS_Store
# Cakeup
cakeup-x86_64-latest.exe

281
README.md
View File

@@ -14,8 +14,6 @@ for Python.
3.1. [Using the static API](#using-the-static-api)
3.2. [Creating a console](#creating-a-console)
4. [Running examples](#running-examples)
5. [Available styles](#available-styles)
6. [Predefined colors](#predefined-colors)
## Features
@@ -122,281 +120,4 @@ And to run an example:
│ Bonjour │ le │ monde! │
│ Hej │ Världen! │ │
└──────────┴──────────┴────────┘
```
## 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`
```

View File

@@ -1,10 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>
<DefaultItemExcludes>$(DefaultItemExcludes);output\**;.gitignore</DefaultItemExcludes>
<MinVerSkip Condition="'$(Configuration)' == 'Debug'">true</MinVerSkip>
</PropertyGroup>
<ItemGroup>
@@ -22,8 +23,27 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Statiq.Web" Version="1.0.0-alpha.9" />
<PackageReference Include="NJsonSchema" Version="10.1.12" />
<None Remove="src\Data\emojis.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="src\Data\emojis.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Statiq.Web" Version="1.0.0-beta.5" />
<PackageReference Include="MinVer" PrivateAssets="All" Version="2.3.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="input\assets\images\emojis\" />
</ItemGroup>
<Target Name="Versioning" BeforeTargets="MinVer">
<PropertyGroup Label="Build">
<MinVerDefaultPreReleasePhase>preview</MinVerDefaultPreReleasePhase>
<MinVerVerbosity>normal</MinVerVerbosity>
</PropertyGroup>
</Target>
</Project>

1
docs/Preview.ps1 Normal file
View File

@@ -0,0 +1 @@
dotnet run -- preview --virtual-dir "spectre.console"

View File

@@ -19,6 +19,7 @@ namespace Docs
.ConfigureDeployment(deployBranch: "docs")
.AddShortcode("Children", typeof(ChildrenShortcode))
.AddShortcode("ColorTable", typeof(ColorTableShortcode))
.AddShortcode("EmojiTable", typeof(EmojiTableShortcode))
.AddPipelines()
.RunAsync();

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
@@ -29,7 +29,7 @@
<nav id="topnav" class="navbar navbar-expand-lg navbar-light">
<div class="container py-3">
<a class="navbar-brand" href="/spectre.console/docs"><img id="logo" src="/spectre.console/assets/logo.svg" alt="Spectre.Console"> Spectre.Console</a>
<a class="navbar-brand" href="/spectre.console"><img id="logo" src="/spectre.console/assets/logo.svg" alt="Spectre.Console"> Spectre.Console</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
@@ -52,8 +52,8 @@
{
@RenderSection(Constants.Sections.Splash, false)
}
@{
string section = Document.Destination.Segments.Length > 1 ? Document.Destination.Segments[0].ToString() : null;
@{
string section = "docs";
}
<div class="flex-grow-1 d-flex bg-body flex-column @(section != null ? "section-" + section : null)">
@@ -62,7 +62,7 @@
<div id="titlebar" class="py-4">
<div class="container">
<div class="row">
@{
@{
string titleBarClasses = Document.GetBool(Constants.NoSidebar) ? string.Empty : "offset-md-3 offset-lg-2";
}
<div class="@titleBarClasses px-3 px-md-0">
@@ -97,7 +97,7 @@
</div>
</div>
}
<div class="flex-grow-1 d-flex flex-column bg-body">
@if (Document.GetBool(Constants.NoContainer))
{
@@ -126,21 +126,36 @@
}
else
{
IDocument root = Outputs[nameof(Content)].First(x => x.Destination == section + "/index.html");
IDocument root = OutputPages["index.html"].First();
<div class="sidebar-nav-item @(Document.IdEquals(root) ? "active" : null)">
@Html.DocumentLink(root)
@if(root.ShowLink())
{
@Html.DocumentLink(root)
}
else
{
@root.GetTitle()
}
</div>
@foreach (IDocument document in root.GetChildren().OnlyVisible())
@foreach (IDocument document in OutputPages.GetChildrenOf(root).OnlyVisible())
{
<div class="sidebar-nav-item @(Document.IdEquals(document) ? "active" : null) @(document.HasChildren() ? "has-children" : null)">
@Html.DocumentLink(document)
DocumentList<IDocument> documentChildren = OutputPages.GetChildrenOf(document);
<div class="sidebar-nav-item @(Document.IdEquals(document) ? "active" : null) @(documentChildren.Any() ? "has-children" : null)">
@if(document.ShowLink())
{
@Html.DocumentLink(document)
}
else
{
@document.GetTitle()
}
</div>
@if (document.HasVisibleChildren())
@if (documentChildren.OnlyVisible().Any())
{
<div class="sidebar-nav-children @(Document.IdEquals(document) || document.GetChildren().Any(x => Document.IdEquals(x)) ? "active" : null)">
@foreach (IDocument child in document.GetChildren().OnlyVisible())
<div class="sidebar-nav-children @(Document.IdEquals(document) || documentChildren.Any(x => Document.IdEquals(x)) ? "active" : null)">
@foreach (IDocument child in documentChildren.OnlyVisible())
{
<div class="sidebar-nav-child @(Document.IdEquals(child) ? "active" : null)">
@Html.DocumentLink(child)
@@ -182,7 +197,10 @@
</div>
<div id="footer" class="p-3 text-white font-size-sm">
<div class="container">
<div>© @DateTime.Today.Year Spectre Systems AB</div>
<div>
<span>© @DateTime.Today.Year Spectre Systems AB</span>
<span class="float-right" style="color: #888888;">@VersionUtilities.GetVersion()</span>
</div>
</div>
</div>
<script>
@@ -195,7 +213,7 @@
},
startOnLoad: false,
cloneCssStyles: false
});
});
mermaid.init(undefined, ".mermaid");
// Remove the max-width setting that Mermaid sets
@@ -214,13 +232,13 @@
center: true,
maxZoom: 20,
zoomScaleSensitivity: 0.6
});
});
// Do the reset once right away to fit the diagram
panZoom.resize();
panZoom.fit();
panZoom.center();
$(window).resize(function(){
panZoom.resize();
panZoom.fit();

View File

@@ -3,5 +3,6 @@
@using Statiq.Web
@using Statiq.Web.Pipelines
@using Docs
@using Docs.Utilities;
@inherits StatiqRazorPage<IDocument>

View File

@@ -0,0 +1,33 @@
Title: Borders
Order: 2
---
There is different built-in borders you can use for tables and panels.
# Table borders
<img src="../assets/images/borders/table.png" style="max-width: 100%;">
## Example
To set a table border to `SimpleHeavy`:
```csharp
var table = new Table();
table.Border = TableBorder.SimpleHeavy;
```
---
# Panel borders
<img src="../assets/images/borders/panel.png" style="max-width: 100%;">
## Example
To set a panel border to `Rounded`:
```csharp
var panel = new Panel("Hello World");
panel.Border = BoxBorder.Rounded;
```

View File

@@ -1,5 +1,5 @@
Title: Colors
Order: 2
Order: 0
---
The following is a list of the standard 8-bit colors supported in terminals.

View File

@@ -0,0 +1,38 @@
Title: Emojis
Order: 3
---
Please note that what emojis that can be used is completely up to
the operating system and/or terminal you're using, and no guarantees
can be made of how it will look. Calculating the width of emojis
is also not an exact science in many ways, so milage might vary when
used in tables, panels or grids.
To ensure best compatibility, consider only using emojis introduced
before Unicode 13.0 that belongs in the `Emoji_Presentation` category
in the official emoji list at
https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
# Usage
```csharp
// Markup
AnsiConsole.MarkupLine("Hello :globe_showing_europe_africa:!");
// Constant
var hello = "Hello " + Emoji.Known.GlobeShowingEuropeAfrica;
```
# Replacing emojis in text
```csharp
var phrase = "Mmmm :birthday_cake:";
var rendered = Emoji.Replace(phrase);
```
# Emojis
_The images in the table below might not render correctly in your
browser for the same reasons mentioned in the `Compatibility` section._
<?# EmojiTable /?>

View File

@@ -0,0 +1,10 @@
Title: Appendix
Order: 10
---
# Sections
* [Styles](xref:styles)
* [Colors](xref:colors)
* [Borders](xref:borders)
* [Emojis](xref:emojis)

View File

@@ -0,0 +1,44 @@
Title: Styles
Order: 1
---
Note that what styles that can be used is defined by the system or your terminal software, and may not appear as they should.
<table class="table">
<tr>
<td><code>bold</code></td>
<td>Bold text</td>
</tr>
<tr>
<td><code>dim</code></td>
<td>Dim or faint text</td>
</tr>
<tr>
<td><code>italic</code></td>
<td>Italic text</td>
</tr>
<tr>
<td><code>underline</code></td>
<td>Underlined text</td>
</tr>
<tr>
<td><code>invert</code></td>
<td>Swaps the foreground and background colors</td>
</tr>
<tr>
<td><code>conceal</code></td>
<td>Hides the text</td>
</tr>
<tr>
<td><code>slowblink</code></td>
<td>Makes text blink slowly</td>
</tr>
<tr>
<td><code>rapidblink</code></td>
<td>Makes text blink</td>
</tr>
<tr>
<td><code>strikethrough</code></td>
<td>Shows text with a horizontal line through the center</td>
</tr>
</table>

View File

@@ -18,6 +18,7 @@ $thebackground: $gray-200;
display: inline-block;
width: 60px;
height: 15px;
border: 2px solid #000000;
}
#topnav {

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

@@ -1,6 +0,0 @@
Title: Console API
Order: 2
Hidden: True
---
__To be written__

View File

@@ -1,6 +0,0 @@
Title: Grids
Order: 4
Hidden: True
---
__To be written__

View File

@@ -1,6 +0,0 @@
Title: Panels
Order: 5
Hidden: True
---
__To be written__

View File

@@ -1,6 +0,0 @@
Title: Tables
Order: 3
Hidden: True
---
__To be written__

View File

@@ -1,15 +0,0 @@
Title: Start
NoContainer: true
---
@section Splash {
<div id="hero" class="jumbotron jumbotron-fluid mb-0">
<div class="container">
<div class="display-4 text-white">Spectre.Console</div>
<p class="lead text-white">
A .NET Standard library that makes it easier to create beautiful console applications.
<br /><br />
<a class="btn btn-primary" href="/spectre.console/docs" role="button">Take me to the documentation</a>
</p>
</div>
</div>
}

View File

@@ -13,7 +13,7 @@ for Python written by Will McGugan.
* Supports tables, grids, panels, and a [Rich](https://github.com/willmcgugan/rich)
inspired markup language.
* Supports the most common
[SRG parameters](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters)
[SGR parameters](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters)
when it comes to text styling such as bold, dim, italic, underline, strikethrough,
and blinking text.
* Supports `3`/`4`/`8`/`24`-bit colors in the terminal.

72
docs/input/markup.md Normal file
View File

@@ -0,0 +1,72 @@
Title: Markup
Order: 2
---
The class `Markup` allows you to output rich text to the console.
# Syntax
Console markup uses a syntax inspired by bbcode. If you write the style (see Styles)
in square brackets, e.g. `[bold red]`, that style will apply until it is closed with a `[/]`.
```csharp
AnsiConsole.Render(new Markup("[bold yellow]Hello[/] [red]World![/]"));
```
The `Markup` class implements `IRenderable` which means that you
can use this in tables, grids, and panels. Most classes that support
rendering of `IRenderable` also have overloads for rendering rich text.
```csharp
var table = new Table();
table.AddColumn(new TableColumn(new Markup("[yellow]Foo[/]")));
table.AddColumn(new TableColumn("[blue]Bar[/]"));
```
# Convenience methods
There is also convenience methods on `AnsiConsole` that can be used
to write markup text to the console without instantiating a new `Markup`
instance.
```csharp
AnsiConsole.Markup("[underline green]Hello[/] ");
AnsiConsole.MarkupLine("[bold]World[/]");
```
# Escaping format characters
To output a `[` you use `[[`, and to output a `]` you use `]]`.
```csharp
AnsiConsole.Markup("[[Hello]] "); // [Hello]
AnsiConsole.Markup("[red][[World]][/]"); // [World]
```
# Setting background color
You can set the background color in markup by prefixing the color with
`on`.
```
[bold yellow on blue]Hello[/]
[default on blue]World[/]
```
# Rendering emojis
To output an emoji as part of markup, you can use emoji shortcodes.
```csharp
AnsiConsole.MarkupLine("Hello :globe_showing_europe_africa:!");
```
For a list of emoji, see the [Emojis](xref:styles) appendix section.
# Colors
For a list of colors, see the [Colors](xref:colors) appendix section.
# Styles
For a list of styles, see the [Styles](xref:styles) appendix section.

120
docs/input/tables.md Normal file
View File

@@ -0,0 +1,120 @@
Title: Tables
Order: 3
---
Tables are a perfect way of displaying tabular data in a terminal.
`Spectre.Console` is super smart about rendering tables and will adjust
all columns to fit whatever is inside them. Anything that implements
`IRenderable` can be used as a column header or column cell, even another table!
# Usage
<!------------------------->
<!--- USAGE --->
<!------------------------->
To render a table, create a `Table` instance, add the number of
columns that you need, and then add the rows. Finish by passing the
table to a console's `Render` method.
```csharp
// Create a table
var table = new Table();
// Add some columns
table.AddColumn("Foo");
table.AddColumn(new TableColumn("Bar").Centered());
// Add some rows
table.AddRow("Baz", "[green]Qux[/]");
table.AddRow(new Markup("[blue]Corgi[/]"), new Panel("Waldo"));
// Render the table to the console
AnsiConsole.Render(table);
```
This will render the following output:
![Table](assets/images/table.png)
# Table appearance
<!------------------------->
<!--- TABLE APPEARANCE --->
<!------------------------->
## Borders
For a list of borders, see the [Borders](xref:borders) appendix section.
```csharp
// Sets the border
table.SetBorder(Border.None);
table.SetBorder(Border.Ascii);
table.SetBorder(Border.Square);
table.SetBorder(Border.Rounded);
```
## Expand / Collapse
```csharp
// Table will take up as much space as it can
// with respect to other things.
table.Expand();
// Table will take up minimal width
table.Collapse();
```
## Hide headers
```csharp
// Hides all column headers
table.HideHeaders();
```
## Set table width
```csharp
// Sets the table width to 50 cells
table.SetWidth(50);
```
# Column appearance
<!------------------------->
<!--- COLUMN APPEARANCE --->
<!------------------------->
## Alignment
```csharp
// Set the alignment explicitly
column.SetAlignment(Justify.Right);
```
## Padding
```csharp
// Set left and right padding
column.SetPadding(left: 3, right: 5);
// Set padding individually.
column.PadLeft(3);
column.PadRight(5);
```
## Disable column wrapping
```csharp
// Disable column wrapping
column.NoWrap();
```
## Set column width
```csharp
// Set the column width (no fluent extension method for this yet)
column.Width = 15;
```

View File

@@ -1,14 +1,20 @@
namespace Docs
namespace Docs
{
public static class Constants
{
public const string NoContainer = nameof(NoContainer);
public const string NoSidebar = nameof(NoSidebar);
public const string NoLink = nameof(NoLink);
public const string Topic = nameof(Topic);
public const string EditLink = nameof(EditLink);
public const string Description = nameof(Description);
public const string Hidden = nameof(Hidden);
public static class Emojis
{
public const string Root = "EMOJIS_ROOT";
}
public static class Colors
{
public const string Url = "https://raw.githubusercontent.com/spectresystems/spectre.console/main/resources/scripts/Generator/Data/colors.json";

7946
docs/src/Data/emojis.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
using Statiq.Common;
using Statiq.Common;
using System.Collections.Generic;
using System.Linq;
@@ -11,20 +11,16 @@ namespace Docs
return document?.GetString(Constants.Description, string.Empty) ?? string.Empty;
}
public static bool HasVisibleChildren(this IDocument document)
{
if (document != null)
{
return document.HasChildren() && document.GetChildren().Any(x => x.IsVisible());
}
return false;
}
public static bool IsVisible(this IDocument document)
{
return !document.GetBool(Constants.Hidden, false);
}
public static bool ShowLink(this IDocument document)
{
return !document.GetBool(Constants.NoLink, false);
}
public static IEnumerable<IDocument> OnlyVisible(this IEnumerable<IDocument> source)
{
return source.Where(x => x.IsVisible());

20
docs/src/Models/Emoji.cs Normal file
View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
namespace Docs.Models
{
public sealed class Emoji
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Code { get; set; }
public static List<Emoji> Parse(string json)
{
return JsonConvert.DeserializeObject<List<Emoji>>(json);
}
}
}

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Statiq.Common;
namespace Docs.Modules
{
public sealed class ReadEmbedded : Module
{
private readonly System.Reflection.Assembly _assembly;
private readonly string _resource;
public ReadEmbedded(System.Reflection.Assembly assembly, string resource)
{
_assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
_resource = resource ?? throw new ArgumentNullException(nameof(resource));
}
protected override Task<IEnumerable<IDocument>> ExecuteContextAsync(IExecutionContext context)
{
return Task.FromResult((IEnumerable<IDocument>)new[]
{
context.CreateDocument(ReadResource()),
});
}
private Stream ReadResource()
{
var resourceName = _resource.Replace("/", ".");
var stream = _assembly.GetManifestResourceStream(resourceName);
if (stream == null)
{
throw new InvalidOperationException("Could not load manifest resource stream.");
}
return stream;
}
}
}

View File

@@ -1,8 +1,7 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Docs.Models;
using NJsonSchema;
using Statiq.Common;
using Statiq.Core;
@@ -27,13 +26,8 @@ namespace Docs.Pipelines
new ExecuteConfig(
Config.FromDocument(async (doc, ctx) =>
{
var colors = Color.Parse(await doc.GetContentStringAsync()).ToList();
var definitions = new List<IDocument> { colors.ToDocument(Constants.Colors.Root) };
return doc.Clone(new MetadataDictionary
{
[Constants.Colors.Root] = definitions
});
var data = Color.Parse(await doc.GetContentStringAsync()).ToList();
return data.ToDocument(Constants.Colors.Root);
}))
};
}

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using Docs.Models;
using Docs.Modules;
using Statiq.Common;
using Statiq.Core;
namespace Docs.Pipelines
{
public class EmojiPipeline : Pipeline
{
public EmojiPipeline()
{
InputModules = new ModuleList
{
new ExecuteConfig(
Config.FromContext(ctx => {
return new ReadEmbedded(
typeof(EmojiPipeline).Assembly,
"Docs/src/Data/emojis.json");
}))
};
ProcessModules = new ModuleList
{
new ExecuteConfig(
Config.FromDocument(async (doc, ctx) =>
{
var data = Emoji.Parse(await doc.GetContentStringAsync());
return data.ToDocument(Constants.Emojis.Root);
}))
};
}
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NJsonSchema;
using Statiq.Common;
using System.Xml.Linq;
using Docs.Pipelines;
@@ -18,11 +17,10 @@ namespace Docs.Shortcodes
// Get the definition.
var colors = context.Outputs
.FromPipeline(nameof(ColorsPipeline))
.First()
.GetChildren(Constants.Colors.Root)
.OfType<ObjectDocument<List<Color>>>()
.First().Object;
// Headers
var table = new XElement("table", new XAttribute("class", "table"));
var header = new XElement("tr", new XAttribute("class", "color-row"));
header.Add(new XElement("th", ""));

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Statiq.Common;
using System.Xml.Linq;
using Docs.Pipelines;
using Docs.Models;
namespace Docs.Shortcodes
{
public class EmojiTableShortcode : SyncShortcode
{
public override ShortcodeResult Execute(KeyValuePair<string, string>[] args, string content, IDocument document, IExecutionContext context)
{
var emojis = context.Outputs
.FromPipeline(nameof(EmojiPipeline))
.OfType<ObjectDocument<List<Emoji>>>()
.First().Object;
// Headers
var table = new XElement("table", new XAttribute("class", "table"));
var header = new XElement("tr", new XAttribute("class", "emoji-row"));
header.Add(new XElement("th", ""));
header.Add(new XElement("th", "Markup"));
header.Add(new XElement("th", "Constant"));
table.Add(header);
foreach (var emoji in emojis)
{
var code = emoji.Code.Replace("U+0000", "U+").Replace("U+000", "U+");
var icon = string.Format("&#x{0};", emoji.Code.Replace("U+", string.Empty));
var row = new XElement("tr");
row.Add(new XElement("td", icon));
row.Add(new XElement("td", new XElement("code", $":{emoji.Id}:")));
row.Add(new XElement("td", new XElement("code", emoji.Name)));
table.Add(row);
}
return table.ToString()
.Replace("&amp;#x", "&#x");
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
namespace Docs.Utilities
{
public static class VersionUtilities
{
public static string GetVersion()
{
return GetVersion(typeof(VersionUtilities).Assembly);
}
private static string GetVersion(Assembly assembly)
{
if (assembly == null)
{
return "?";
}
try
{
var info = FileVersionInfo.GetVersionInfo(assembly.Location);
return info.ProductVersion ?? "?";
}
catch
{
return "?";
}
}
}
}

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<Title>Borders</Title>
<Description>Demonstrates the different kind of borders.</Description>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" />
</ItemGroup>
</Project>

View File

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

View File

@@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<Title>Colors</Title>
<Description>Demonstrates how to use [yellow]c[/][red]o[/][green]l[/][blue]o[/][aqua]r[/][lime]s[/] in the console.</Description>
</PropertyGroup>

View File

@@ -4,7 +4,7 @@ namespace ColorExample
{
public static class Program
{
public static void Main(string[] args)
public static void Main()
{
if (AnsiConsole.Capabilities.ColorSystem == ColorSystem.NoColors)
{

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<Title>Columns</Title>
<Description>Demonstrates how to render data into columns.</Description>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,39 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using Spectre.Console;
namespace ColumnsExample
{
public static class Program
{
public static async Task Main()
{
// Download some random users
using var client = new HttpClient();
dynamic users = JObject.Parse(
await client.GetStringAsync("https://randomuser.me/api/?results=15"));
// Create a card for each user
var cards = new List<Panel>();
foreach(var user in users.results)
{
cards.Add(new Panel(GetCard(user))
.SetHeader($"{user.location.country}")
.RoundedBorder().Expand());
}
// Render all cards in columns
AnsiConsole.Render(new Columns(cards));
}
private static string GetCard(dynamic user)
{
var name = $"{user.name.first} {user.name.last}";
var country = $"{user.location.city}";
return $"[b]{name}[/]\n[yellow]{country}[/]";
}
}
}

View File

@@ -1,18 +0,0 @@
using System;
using Spectre.Console;
namespace Diagnostic
{
public class Program
{
public static void Main(string[] args)
{
AnsiConsole.MarkupLine("Color system: [bold]{0}[/]", AnsiConsole.Capabilities.ColorSystem);
AnsiConsole.MarkupLine("Supports ansi? [bold]{0}[/]", AnsiConsole.Capabilities.SupportsAnsi);
AnsiConsole.MarkupLine("Legacy console? [bold]{0}[/]", AnsiConsole.Capabilities.LegacyConsole);
AnsiConsole.WriteLine();
AnsiConsole.MarkupLine("Buffer width: [bold]{0}[/]", AnsiConsole.Console.Width);
AnsiConsole.MarkupLine("Buffer height: [bold]{0}[/]", AnsiConsole.Console.Height);
}
}
}

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<Title>Emojis</Title>
<Description>Demonstrates how to render emojis.</Description>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,16 @@
using Spectre.Console;
namespace EmojiExample
{
public static class Program
{
public static void Main(string[] args)
{
// Markup
AnsiConsole.Render(
new Panel("[yellow]Hello :globe_showing_europe_africa:![/]")
.RoundedBorder()
.SetHeader("Markup"));
}
}
}

View File

@@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<Title>Grids</Title>
<Description>Demonstrates how to render grids in a console.</Description>
</PropertyGroup>

View File

@@ -1,25 +1,25 @@
using Spectre.Console;
namespace GridExample
{
public sealed class Program
{
static void Main(string[] args)
{
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.");
grid.AddRow(" [blue]-v[/], [blue]--verbosity[/] <LEVEL>", "", "Set the [grey]MSBuild[/] verbosity level.");
AnsiConsole.Render(grid);
}
}
}
using Spectre.Console;
namespace GridExample
{
public static class Program
{
public static void Main()
{
AnsiConsole.WriteLine();
AnsiConsole.MarkupLine("Usage: [grey]dotnet [blue]run[/] [[options]] [[[[--]] <additional arguments>...]]]][/]");
AnsiConsole.WriteLine();
var grid = new Grid();
grid.AddColumn(new GridColumn { NoWrap = 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.");
grid.AddRow(" [blue]-v[/], [blue]--verbosity[/] <LEVEL>", "", "Set the [grey]MSBuild[/] verbosity level.");
AnsiConsole.Render(grid);
}
}
}

View File

@@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<Title>Info</Title>
<Description>Displays the capabilities of the current console.</Description>
</PropertyGroup>

28
examples/Info/Program.cs Normal file
View File

@@ -0,0 +1,28 @@
using Spectre.Console;
namespace InfoExample
{
public static class Program
{
public static void Main()
{
var grid = new Grid()
.AddColumn(new GridColumn().NoWrap().PadRight(4))
.AddColumn()
.AddRow("[b]Color system[/]", $"{AnsiConsole.Capabilities.ColorSystem}")
.AddRow("[b]Supports ansi?[/]", $"{YesNo(AnsiConsole.Capabilities.SupportsAnsi)}")
.AddRow("[b]Legacy console?[/]", $"{YesNo(AnsiConsole.Capabilities.LegacyConsole)}")
.AddRow("[b]Buffer width[/]", $"{AnsiConsole.Console.Width}")
.AddRow("[b]Buffer height[/]", $"{AnsiConsole.Console.Height}");
AnsiConsole.Render(
new Panel(grid)
.SetHeader("Information"));
}
private static string YesNo(bool value)
{
return value ? "Yes" : "No";
}
}
}

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<Title>Links</Title>
<Description>Demonstrates how to render links in a console.</Description>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" />
</ItemGroup>
</Project>

21
examples/Links/Program.cs Normal file
View File

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

View File

@@ -1,44 +0,0 @@
using Spectre.Console;
namespace PanelExample
{
class Program
{
static void Main(string[] args)
{
var content = new Markup(
"[underline]I[/] heard [underline on blue]you[/] like panels\n\n\n\n" +
"So I put a panel in a panel").Centered();
AnsiConsole.Render(
new Panel(
new Panel(content)
{
Border = BorderKind.Rounded
}));
// Left adjusted panel with text
AnsiConsole.Render(new Panel(
new Text("Left adjusted\nLeft").LeftAligned())
{
Expand = true,
});
// Centered ASCII panel with text
AnsiConsole.Render(new Panel(
new Text("Centered\nCenter").Centered())
{
Expand = true,
Border = BorderKind.Ascii,
});
// Right adjusted, rounded panel with text
AnsiConsole.Render(new Panel(
new Text("Right adjusted\nRight").RightAligned())
{
Expand = true,
Border = BorderKind.Rounded,
});
}
}
}

View File

@@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<Title>Panels</Title>
<Description>Demonstrates how to render items in panels.</Description>
</PropertyGroup>

View File

@@ -0,0 +1,40 @@
using Spectre.Console;
namespace PanelExample
{
public static class Program
{
public static void Main()
{
var content = new Markup(
"[underline]I[/] heard [underline on blue]you[/] like panels\n\n\n\n" +
"So I put a panel in a panel").Centered();
AnsiConsole.Render(
new Panel(
new Panel(content)
.SetBorder(BoxBorder.Rounded)));
// Left adjusted panel with text
AnsiConsole.Render(
new Panel(new Text("Left adjusted\nLeft").LeftAligned())
.Expand()
.SquareBorder()
.SetHeader("Left", Style.WithForeground(Color.Red)));
// Centered ASCII panel with text
AnsiConsole.Render(
new Panel(new Text("Centered\nCenter").Centered())
.Expand()
.AsciiBorder()
.SetHeader("Center", Style.WithForeground(Color.Green), Justify.Center));
// Right adjusted, rounded panel with text
AnsiConsole.Render(
new Panel(new Text("Right adjusted\nRight").RightAligned())
.Expand()
.RoundedBorder()
.SetHeader("Right", Style.WithForeground(Color.Blue), Justify.Right));
}
}
}

View File

@@ -1,11 +1,10 @@
using Spectre.Console;
using Spectre.Console.Rendering;
namespace TableExample
{
public static class Program
{
public static void Main(string[] args)
public static void Main()
{
// A simple table
RenderSimpleTable();
@@ -36,7 +35,7 @@ namespace TableExample
private static void RenderBigTable()
{
// Create the table.
var table = new Table().SetBorder(BorderKind.Rounded);
var table = new Table().SetBorder(TableBorder.Rounded);
table.AddColumn("[red underline]Foo[/]");
table.AddColumn(new TableColumn("[blue]Bar[/]") { Alignment = Justify.Right, NoWrap = true });
@@ -58,7 +57,7 @@ namespace TableExample
private static void RenderNestedTable()
{
// Create simple table.
var simple = new Table().SetBorder(BorderKind.Rounded).SetBorderColor(Color.Red);
var simple = new Table().SetBorder(TableBorder.Rounded).SetBorderColor(Color.Red);
simple.AddColumn(new TableColumn("[u]Foo[/]").Centered());
simple.AddColumn(new TableColumn("[u]Bar[/]"));
simple.AddColumn(new TableColumn("[u]Baz[/]"));
@@ -67,7 +66,7 @@ namespace TableExample
simple.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
// Create other table.
var second = new Table().SetBorder(BorderKind.Square).SetBorderColor(Color.Green);
var second = new Table().SetBorder(TableBorder.Square).SetBorderColor(Color.Green);
second.AddColumn(new TableColumn("[u]Foo[/]"));
second.AddColumn(new TableColumn("[u]Bar[/]"));
second.AddColumn(new TableColumn("[u]Baz[/]"));
@@ -75,7 +74,7 @@ namespace TableExample
second.AddRow(simple, new Text("Whaaat"), new Text("Lolz"));
second.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
var table = new Table().SetBorder(BorderKind.Rounded);
var table = new Table().SetBorder(TableBorder.Rounded);
table.AddColumn(new TableColumn(new Panel("[u]Foo[/]").SetBorderColor(Color.Red)));
table.AddColumn(new TableColumn(new Panel("[u]Bar[/]").SetBorderColor(Color.Green)));
table.AddColumn(new TableColumn(new Panel("[u]Baz[/]").SetBorderColor(Color.Blue)));

View File

@@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<Title>Tables</Title>
<Description>Demonstrates how to render tables in a console.</Description>
</PropertyGroup>

View File

@@ -2,6 +2,6 @@
"projects": [ "src" ],
"sdk": {
"version": "3.1.301",
"rollForward": "latestMajor"
"rollForward": "latestPatch"
}
}

View File

@@ -3,7 +3,7 @@
##########################################################
$Output = Join-Path $PSScriptRoot "Temp"
$Source = Join-Path $PSScriptRoot "/../src/Spectre.Console"
$Source = Join-Path $PSScriptRoot "/../../src/Spectre.Console"
if(!(Test-Path $Output -PathType Container)) {
New-Item -ItemType Directory -Path $Output | Out-Null

View File

@@ -0,0 +1,24 @@
##########################################################
# Script that generates the emoji lookup table.
##########################################################
$Output = Join-Path $PSScriptRoot "Temp"
$Source = Join-Path $PSScriptRoot "/../../src/Spectre.Console"
$Docs = Join-Path $PSScriptRoot "/../../docs/src/Data"
if(!(Test-Path $Output -PathType Container)) {
New-Item -ItemType Directory -Path $Output | Out-Null
}
# Generate the files
Push-Location Generator
&dotnet run -- emoji "$Output" --input $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" "Emoji.Generated.cs") -Destination "$Source/Emoji.Generated.cs"
Copy-Item (Join-Path "$Output" "emojis.json") -Destination "$Docs/emojis.json"

View File

@@ -55,5 +55,8 @@ namespace Generator.Commands
{
[CommandArgument(0, "<OUTPUT>")]
public string Output { get; set; }
[CommandOption("-i|--input <PATH>")]
public string Input { get; set; }
}
}

View File

@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using AngleSharp.Html.Parser;
using Generator.Models;
using Scriban;
using Scriban.Runtime;
using Spectre.Cli;
using Spectre.IO;
using Path = Spectre.IO.Path;
using SpectreEnvironment = Spectre.IO.Environment;
namespace Generator.Commands
{
public sealed class EmojiGeneratorCommand : AsyncCommand<GeneratorCommandSettings>
{
private readonly IFileSystem _fileSystem;
private readonly IEnvironment _environment;
private readonly IHtmlParser _parser;
private readonly Dictionary<string, string> _templates = new Dictionary<string, string>
{
{ "Templates/Emoji.Generated.template", "Emoji.Generated.cs" },
{ "Templates/Emoji.Json.template", "emojis.json" },
};
public EmojiGeneratorCommand()
{
_fileSystem = new FileSystem();
_environment = new SpectreEnvironment();
_parser = new HtmlParser();
}
public override async Task<int> ExecuteAsync(CommandContext context, GeneratorCommandSettings settings)
{
var output = new DirectoryPath(settings.Output);
if (!_fileSystem.Directory.Exists(settings.Output))
{
_fileSystem.Directory.Create(settings.Output);
}
var stream = await FetchEmojis(settings);
var document = await _parser.ParseDocumentAsync(stream);
var emojis = Emoji.Parse(document).OrderBy(x => x.Name)
.Where(emoji => !emoji.HasCombinators)
.ToList();
// Render all templates
foreach (var (templateFilename, outputFilename) in _templates)
{
var result = await RenderTemplate(new FilePath(templateFilename), emojis);
var outputPath = output.CombineWithFilePath(outputFilename);
await File.WriteAllTextAsync(outputPath.FullPath, result);
}
return 0;
}
private async Task<Stream> FetchEmojis(GeneratorCommandSettings settings)
{
var input = string.IsNullOrEmpty(settings.Input)
? _environment.WorkingDirectory
: new DirectoryPath(settings.Input);
var file = _fileSystem.File.Retrieve(input.CombineWithFilePath("emoji-list.html"));
if (!file.Exists)
{
using var http = new HttpClient();
using var httpStream = await http.GetStreamAsync("http://www.unicode.org/emoji/charts/emoji-list.html");
using var outStream = file.OpenWrite();
await httpStream.CopyToAsync(outStream);
}
return file.OpenRead();
}
private static async Task<string> RenderTemplate(Path path, IReadOnlyCollection<Emoji> emojis)
{
var text = await File.ReadAllTextAsync(path.FullPath);
var template = Template.Parse(text);
var templateContext = new TemplateContext
{
// Because of the insane amount of Emojis,
// we need to get rid of some secure defaults :P
LoopLimit = int.MaxValue,
};
var scriptObject = new ScriptObject();
scriptObject.Import(new { Emojis = emojis });
templateContext.PushGlobal(scriptObject);
return await template.RenderAsync(templateContext);
}
}
}

View File

@@ -24,9 +24,17 @@
<None Update="Templates\ColorPalette.Generated.template">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\Emoji.Json.template">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\Emoji.Generated.template">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="AngleSharp" Version="0.14.0" />
<PackageReference Include="Humanizer.Core" Version="2.8.26" />
<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" />

View File

@@ -0,0 +1,95 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AngleSharp.Dom;
using AngleSharp.Html.Dom;
using Humanizer;
namespace Generator.Models
{
public class Emoji
{
private static readonly string[] _headers = { "count", "code", "sample", "name" };
private Emoji(string identifier, string name, string code, string description)
{
Identifier = identifier;
Name = name;
Code = code;
Description = description;
NormalizedCode = Code.Replace("\\U", "U+");
HasCombinators = Code.Split(new[] { "\\U" }, System.StringSplitOptions.RemoveEmptyEntries).Length > 1;
}
public string Identifier { get; set; }
public string Code { get; }
public string NormalizedCode { get; }
public string Name { get; }
public string Description { get; set; }
public bool HasCombinators { get; set; }
public static IEnumerable<Emoji> Parse(IHtmlDocument document)
{
var rows = document
.GetNodes<IHtmlTableRowElement>(predicate: row =>
row.Cells.Length >= _headers.Length && // Filter out rows that don't have enough cells.
row.Cells.All(x => x.LocalName == TagNames.Td)); // We're only interested in td cells, not th.
foreach (var row in rows)
{
var dictionary = _headers
.Zip(row.Cells, (header, cell) => (Header: header, cell.TextContent.Trim()))
.ToDictionary(x => x.Item1, x => x.Item2);
var code = TransformCode(dictionary["code"]);
var identifier = TransformName(dictionary["name"])
.Replace("-", "_")
.Replace("(", string.Empty)
.Replace(")", string.Empty);
var description = dictionary["name"].Humanize();
var name = identifier
.Replace("1st", "first")
.Replace("2nd", "second")
.Replace("3rd", "third")
.Pascalize();
yield return new Emoji(identifier, name, code, description);
}
}
private static string TransformName(string name)
{
return name.Replace(":", string.Empty)
.Replace(",", string.Empty)
.Replace(".", string.Empty)
.Replace("\u201c", string.Empty)
.Replace("\u201d", string.Empty)
.Replace("\u229b", string.Empty)
.Replace(' ', '_')
.Replace("s", "s")
.Replace("", "_")
.Replace("&", "and")
.Replace("#", "hash")
.Replace("*", "star")
.Replace("!", string.Empty)
.Trim()
.ToLowerInvariant();
}
private static string TransformCode(string code)
{
var builder = new StringBuilder();
foreach (var part in code.Split(' '))
{
builder.Append(part.Length == 6
? part.Replace("+", "0000")
: part.Replace("+", "000"));
}
return builder.ToString().Replace("U", "\\U");
}
}
}

View File

@@ -11,6 +11,7 @@ namespace Generator
app.Configure(config =>
{
config.AddCommand<ColorGeneratorCommand>("colors");
config.AddCommand<EmojiGeneratorCommand>("emoji");
});
return app.Run(args);

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Generated {{ date.now | date.to_string `%Y-%m-%d %k:%M` }}
// Generated {{ date.now | date.to_string `%F %R` }}
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Generated {{ date.now | date.to_string `%Y-%m-%d %k:%M` }}
// Generated {{ date.now | date.to_string `%F %R` }}
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Generated {{ date.now | date.to_string `%Y-%m-%d %k:%M` }}
// Generated {{ date.now | date.to_string `%F %R` }}
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.

View File

@@ -0,0 +1,43 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Generated {{ date.now | date.to_string `%F %R` }}
//
// 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
{
/// <summary>
/// Utility for working with emojis.
/// </summary>
public static partial class Emoji
{
private static readonly Dictionary<string, string> _emojis
= new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
{
{{~ for emoji in emojis ~}}
{ "{{ emoji.identifier }}", Emoji.Known.{{ emoji.name }} },
{{~ end ~}}
};
/// <summary>
/// Contains all predefined emojis.
/// </summary>
public static class Known
{
{{- for emoji in emojis }}
/// <summary>
/// Gets the "{{ emoji.identifier }}" emoji.
/// Description: {{ emoji.description }}.
/// </summary>
public const string {{ emoji.name }} = "{{ emoji.code }}";
{{~ end ~}}
}
}
}

View File

@@ -0,0 +1,10 @@
[
{{~ for x in 0..(emojis.size-1) ~}}
{
"id": "{{ emojis[x].identifier }}",
"name": "{{ emojis[x].name }}",
"description": "{{ emojis[x].description }}",
"code": "{{ emojis[x].normalized_code }}"
}{{ if x != (emojis.size-1) }},{{ end }}
{{~ end ~}}
]

View File

@@ -82,5 +82,8 @@ dotnet_diagnostic.RCS1079.severity = warning
# RCS1057: Add empty line between declarations.
dotnet_diagnostic.RCS1057.severity = none
# RCS1057: Validate arguments correctly
dotnet_diagnostic.RCS1227.severity = none
# IDE0004: Remove Unnecessary Cast
dotnet_diagnostic.IDE0004.severity = warning

View File

@@ -42,7 +42,7 @@
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.113">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Roslynator.Analyzers" Version="2.3.0">
<PackageReference Include="Roslynator.Analyzers" Version="3.0.0">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>

View File

@@ -1,24 +0,0 @@
using System;
namespace Spectre.Console.Tests
{
public static class ConsoleExtensions
{
public static void SetColor(this IAnsiConsole console, Color color, bool foreground)
{
if (console is null)
{
throw new ArgumentNullException(nameof(console));
}
if (foreground)
{
console.Foreground = color;
}
else
{
console.Background = color;
}
}
}
}

View File

@@ -0,0 +1,15 @@
namespace Spectre.Console.Tests
{
internal static class StyleExtensions
{
public static Style SetColor(this Style style, Color color, bool foreground)
{
if (foreground)
{
return style.WithForeground(color);
}
return style.WithBackground(color);
}
}
}

View File

@@ -1,32 +0,0 @@
using System;
using System.IO;
namespace Spectre.Console.Tests
{
public sealed class AnsiConsoleFixture : IDisposable
{
private readonly StringWriter _writer;
public IAnsiConsole Console { get; }
public string Output => _writer.ToString();
public AnsiConsoleFixture(ColorSystem system, AnsiSupport ansi = AnsiSupport.Yes, int width = 80)
{
_writer = new StringWriter();
Console = new ConsoleWithWidth(
AnsiConsole.Create(new AnsiConsoleSettings
{
Ansi = ansi,
ColorSystem = (ColorSystemSupport)system,
Out = _writer,
}), width);
}
public void Dispose()
{
_writer?.Dispose();
}
}
}

View File

@@ -1,31 +0,0 @@
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);
}
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.IO;
using System.Text;
using Spectre.Console.Rendering;
using Spectre.Console.Tests.Tools;
namespace Spectre.Console.Tests
{
public sealed class TestableAnsiConsole : IDisposable, IAnsiConsole
{
private readonly StringWriter _writer;
private readonly IAnsiConsole _console;
public string Output => _writer.ToString();
public Capabilities Capabilities => _console.Capabilities;
public Encoding Encoding => _console.Encoding;
public int Width { get; }
public int Height => _console.Height;
public TestableAnsiConsole(ColorSystem system, AnsiSupport ansi = AnsiSupport.Yes, int width = 80)
{
_writer = new StringWriter();
_console = AnsiConsole.Create(new AnsiConsoleSettings
{
Ansi = ansi,
ColorSystem = (ColorSystemSupport)system,
Out = _writer,
LinkIdentityGenerator = new TestLinkIdentityGenerator(),
});
Width = width;
}
public void Dispose()
{
_writer?.Dispose();
}
public void Write(Segment segment)
{
_console.Write(segment);
}
}
}

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Spectre.Console.Rendering;
namespace Spectre.Console.Tests
{
@@ -16,6 +17,7 @@ namespace Spectre.Console.Tests
public Decoration Decoration { get; set; }
public Color Foreground { get; set; }
public Color Background { get; set; }
public string Link { get; set; }
public StringWriter Writer { get; }
public string RawOutput => Writer.ToString();
@@ -39,9 +41,14 @@ namespace Spectre.Console.Tests
Writer.Dispose();
}
public void Write(string text)
public void Write(Segment segment)
{
Writer.Write(text);
if (segment is null)
{
throw new ArgumentNullException(nameof(segment));
}
Writer.Write(segment.Text);
}
}
}

View File

@@ -0,0 +1,10 @@
namespace Spectre.Console.Tests.Tools
{
public sealed class TestLinkIdentityGenerator : ILinkIdentityGenerator
{
public int GenerateId(string link, string text)
{
return 1024;
}
}
}

View File

@@ -13,14 +13,13 @@ namespace Spectre.Console.Tests.Unit
public void Should_Return_Correct_Code(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
fixture.Console.SetColor(new Color(128, 0, 128), foreground);
var console = new TestableAnsiConsole(ColorSystem.TrueColor);
// When
fixture.Console.Write("Hello");
console.Write("Hello", new Style().SetColor(new Color(128, 0, 128), foreground));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
[Theory]
@@ -29,14 +28,13 @@ namespace Spectre.Console.Tests.Unit
public void Should_Return_Eight_Bit_Ansi_Code_For_Known_Colors(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
fixture.Console.SetColor(Color.Purple, foreground);
var console = new TestableAnsiConsole(ColorSystem.TrueColor);
// When
fixture.Console.Write("Hello");
console.Write("Hello", new Style().SetColor(Color.Purple, foreground));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
}
@@ -48,14 +46,13 @@ namespace Spectre.Console.Tests.Unit
public void Should_Return_Correct_Code_For_Known_Color(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.EightBit);
fixture.Console.SetColor(Color.Olive, foreground);
var console = new TestableAnsiConsole(ColorSystem.EightBit);
// When
fixture.Console.Write("Hello");
console.Write("Hello", new Style().SetColor(Color.Olive, foreground));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
[Theory]
@@ -64,14 +61,13 @@ namespace Spectre.Console.Tests.Unit
public void Should_Map_TrueColor_To_Nearest_Eight_Bit_Color_If_Possible(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.EightBit);
fixture.Console.SetColor(new Color(128, 128, 0), foreground);
var console = new TestableAnsiConsole(ColorSystem.EightBit);
// When
fixture.Console.Write("Hello");
console.Write("Hello", new Style().SetColor(new Color(128, 128, 0), foreground));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
[Theory]
@@ -80,14 +76,13 @@ namespace Spectre.Console.Tests.Unit
public void Should_Estimate_TrueColor_To_Nearest_Eight_Bit_Color(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.EightBit);
fixture.Console.SetColor(new Color(126, 127, 0), foreground);
var console = new TestableAnsiConsole(ColorSystem.EightBit);
// When
fixture.Console.Write("Hello");
console.Write("Hello", new Style().SetColor(new Color(126, 127, 0), foreground));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
}
@@ -99,14 +94,13 @@ namespace Spectre.Console.Tests.Unit
public void Should_Return_Correct_Code_For_Known_Color(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.SetColor(Color.Olive, foreground);
var console = new TestableAnsiConsole(ColorSystem.Standard);
// When
fixture.Console.Write("Hello");
console.Write("Hello", new Style().SetColor(Color.Olive, foreground));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
[Theory]
@@ -120,14 +114,13 @@ namespace Spectre.Console.Tests.Unit
string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.SetColor(new Color(r, g, b), foreground);
var console = new TestableAnsiConsole(ColorSystem.Standard);
// When
fixture.Console.Write("Hello");
console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
[Theory]
@@ -141,14 +134,13 @@ namespace Spectre.Console.Tests.Unit
string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.SetColor(new Color(r, g, b), foreground);
var console = new TestableAnsiConsole(ColorSystem.Standard);
// When
fixture.Console.Write("Hello");
console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
}
@@ -160,14 +152,13 @@ namespace Spectre.Console.Tests.Unit
public void Should_Return_Correct_Code_For_Known_Color(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Legacy);
fixture.Console.SetColor(Color.Olive, foreground);
var console = new TestableAnsiConsole(ColorSystem.Legacy);
// When
fixture.Console.Write("Hello");
console.Write("Hello", new Style().SetColor(Color.Olive, foreground));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
[Theory]
@@ -181,14 +172,13 @@ namespace Spectre.Console.Tests.Unit
string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Legacy);
fixture.Console.SetColor(new Color(r, g, b), foreground);
var console = new TestableAnsiConsole(ColorSystem.Legacy);
// When
fixture.Console.Write("Hello");
console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
[Theory]
@@ -202,14 +192,13 @@ namespace Spectre.Console.Tests.Unit
string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Legacy);
fixture.Console.SetColor(new Color(r, g, b), foreground);
var console = new TestableAnsiConsole(ColorSystem.Legacy);
// When
fixture.Console.Write("Hello");
console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
}
}

View File

@@ -12,31 +12,33 @@ namespace Spectre.Console.Tests.Unit
{
[Theory]
[InlineData("[yellow]Hello[/]", "Hello")]
[InlineData("[yellow]Hello [italic]World[/]![/]", "Hello World!")]
[InlineData("[yellow]Hello [italic]World[/]![/]", "Hello World!")]
[InlineData("[link=https://patriksvensson.se]Click to visit my blog[/]", "]8;id=1024;https://patriksvensson.se\\Click to visit my blog]8;;\\")]
[InlineData("[link]https://patriksvensson.se[/]", "]8;id=1024;https://patriksvensson.se\\https://patriksvensson.se]8;;\\")]
public void Should_Output_Expected_Ansi_For_Markup(string markup, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
var console = new TestableAnsiConsole(ColorSystem.Standard, AnsiSupport.Yes);
// When
fixture.Console.Markup(markup);
console.Markup(markup);
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
[Theory]
[InlineData("[yellow]Hello [[ World[/]", "Hello [ World")]
[InlineData("[yellow]Hello [[ World[/]", "Hello [ World")]
public void Should_Be_Able_To_Escape_Tags(string markup, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
var console = new TestableAnsiConsole(ColorSystem.Standard, AnsiSupport.Yes);
// When
fixture.Console.Markup(markup);
console.Markup(markup);
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
[Theory]
@@ -47,10 +49,10 @@ namespace Spectre.Console.Tests.Unit
public void Should_Throw_If_Encounters_Malformed_Tag(string markup, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
var console = new TestableAnsiConsole(ColorSystem.Standard, AnsiSupport.Yes);
// When
var result = Record.Exception(() => fixture.Console.Markup(markup));
var result = Record.Exception(() => console.Markup(markup));
// Then
result.ShouldBeOfType<InvalidOperationException>()
@@ -61,10 +63,10 @@ namespace Spectre.Console.Tests.Unit
public void Should_Throw_If_Tags_Are_Unbalanced()
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
var console = new TestableAnsiConsole(ColorSystem.Standard, AnsiSupport.Yes);
// When
var result = Record.Exception(() => fixture.Console.Markup("[yellow][blue]Hello[/]"));
var result = Record.Exception(() => console.Markup("[yellow][blue]Hello[/]"));
// Then
result.ShouldBeOfType<InvalidOperationException>()
@@ -75,10 +77,10 @@ namespace Spectre.Console.Tests.Unit
public void Should_Throw_If_Encounters_Closing_Tag()
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
var console = new TestableAnsiConsole(ColorSystem.Standard, AnsiSupport.Yes);
// When
var result = Record.Exception(() => fixture.Console.Markup("Hello[/]World"));
var result = Record.Exception(() => console.Markup("Hello[/]World"));
// Then
result.ShouldBeOfType<InvalidOperationException>()

View File

@@ -18,14 +18,13 @@ namespace Spectre.Console.Tests.Unit
public void Should_Write_Decorated_Text_Correctly(Decoration decoration, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
fixture.Console.Decoration = decoration;
var console = new TestableAnsiConsole(ColorSystem.TrueColor);
// When
fixture.Console.Write("Hello World");
console.Write("Hello World", Style.WithDecoration(decoration));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
[Theory]
@@ -34,14 +33,13 @@ namespace Spectre.Console.Tests.Unit
public void Should_Write_Text_With_Multiple_Decorations_Correctly(Decoration decoration, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
fixture.Console.Decoration = decoration;
var console = new TestableAnsiConsole(ColorSystem.TrueColor);
// When
fixture.Console.Write("Hello World");
console.Write("Hello World", Style.WithDecoration(decoration));
// Then
fixture.Output.ShouldBe(expected);
console.Output.ShouldBe(expected);
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Globalization;
using Shouldly;
using Xunit;
@@ -11,237 +10,68 @@ namespace Spectre.Console.Tests.Unit
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;
var console = new TestableAnsiConsole(ColorSystem.Standard);
// When
fixture.Console.Write("Hello");
console.Write(
"Hello",
Style.WithForeground(Color.RoyalBlue1)
.WithBackground(Color.NavajoWhite1)
.WithDecoration(Decoration.Italic));
// Then
fixture.Output.ShouldBe("\u001b[3;90;47mHello\u001b[0m");
console.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;
var console = new TestableAnsiConsole(ColorSystem.Standard);
// When
fixture.Console.Write("Hello");
console.Write(
"Hello",
Style.WithForeground(Color.Default)
.WithBackground(Color.NavajoWhite1)
.WithDecoration(Decoration.Italic));
// Then
fixture.Output.ShouldBe("\u001b[3;47mHello\u001b[0m");
console.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;
var console = new TestableAnsiConsole(ColorSystem.Standard);
// When
fixture.Console.Write("Hello");
console.Write(
"Hello",
Style.WithForeground(Color.RoyalBlue1)
.WithBackground(Color.Default)
.WithDecoration(Decoration.Italic));
// Then
fixture.Output.ShouldBe("\u001b[3;90mHello\u001b[0m");
console.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;
var console = new TestableAnsiConsole(ColorSystem.Standard);
// When
fixture.Console.Write("Hello");
console.Write(
"Hello",
Style.WithForeground(Color.RoyalBlue1)
.WithBackground(Color.NavajoWhite1)
.WithDecoration(Decoration.None));
// 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");
}
console.Output.ShouldBe("\u001b[90;47mHello\u001b[0m");
}
public sealed class WriteLine
@@ -250,16 +80,14 @@ namespace Spectre.Console.Tests.Unit
public void Should_Reset_Colors_Correctly_After_Line_Break()
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
var console = new TestableAnsiConsole(ColorSystem.Standard, AnsiSupport.Yes);
// When
fixture.Console.Background = ConsoleColor.Red;
fixture.Console.WriteLine("Hello");
fixture.Console.Background = ConsoleColor.Green;
fixture.Console.WriteLine("World");
console.WriteLine("Hello", Style.WithBackground(ConsoleColor.Red));
console.WriteLine("World", Style.WithBackground(ConsoleColor.Green));
// Then
fixture.Output.NormalizeLineEndings()
console.Output.NormalizeLineEndings()
.ShouldBe("Hello\nWorld\n");
}
@@ -267,186 +95,15 @@ namespace Spectre.Console.Tests.Unit
public void Should_Reset_Colors_Correctly_After_Line_Break_In_Text()
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
var console = new TestableAnsiConsole(ColorSystem.Standard, AnsiSupport.Yes);
// When
fixture.Console.Background = ConsoleColor.Red;
fixture.Console.WriteLine("Hello\nWorld");
console.WriteLine("Hello\nWorld", Style.WithBackground(ConsoleColor.Red));
// Then
fixture.Output.NormalizeLineEndings()
console.Output.NormalizeLineEndings()
.ShouldBe("Hello\nWorld\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);
}
}
}
}

View File

@@ -1,42 +0,0 @@
using System;
using Shouldly;
using Spectre.Console.Rendering;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
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");
}
}
}
}

View File

@@ -0,0 +1,210 @@
using Shouldly;
using Spectre.Console.Rendering;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public sealed class BoxBorderTests
{
public sealed class NoBorder
{
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = BoxBorder.None.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(BoxBorder.None);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var panel = Fixture.GetPanel().NoBorder();
// When
console.Render(panel);
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe(" Greeting ");
console.Lines[1].ShouldBe(" Hello World ");
console.Lines[2].ShouldBe(" ");
}
}
public sealed class AsciiBorder
{
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = BoxBorder.Ascii.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(BoxBorder.Ascii);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var panel = Fixture.GetPanel().AsciiBorder();
// When
console.Render(panel);
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("+-Greeting----+");
console.Lines[1].ShouldBe("| Hello World |");
console.Lines[2].ShouldBe("+-------------+");
}
}
public sealed class DoubleBorder
{
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = BoxBorder.Double.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(BoxBorder.Double);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var panel = Fixture.GetPanel().DoubleBorder();
// When
console.Render(panel);
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("╔═Greeting════╗");
console.Lines[1].ShouldBe("║ Hello World ║");
console.Lines[2].ShouldBe("╚═════════════╝");
}
}
public sealed class HeavyBorder
{
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = BoxBorder.Heavy.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(BoxBorder.Square);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var panel = Fixture.GetPanel().HeavyBorder();
// When
console.Render(panel);
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("┏━Greeting━━━━┓");
console.Lines[1].ShouldBe("┃ Hello World ┃");
console.Lines[2].ShouldBe("┗━━━━━━━━━━━━━┛");
}
}
public sealed class RoundedBorder
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = BoxBorder.Rounded.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(BoxBorder.Square);
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var panel = Fixture.GetPanel().RoundedBorder();
// When
console.Render(panel);
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("╭─Greeting────╮");
console.Lines[1].ShouldBe("│ Hello World │");
console.Lines[2].ShouldBe("╰─────────────╯");
}
}
public sealed class SquareBorder
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = BoxBorder.Square.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(BoxBorder.Square);
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var panel = Fixture.GetPanel().SquareBorder();
// When
console.Render(panel);
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("┌─Greeting────┐");
console.Lines[1].ShouldBe("│ Hello World │");
console.Lines[2].ShouldBe("└─────────────┘");
}
}
private static class Fixture
{
public static Panel GetPanel()
{
return new Panel("Hello World")
.SetHeader("Greeting");
}
}
}
}

View File

@@ -0,0 +1,46 @@
using System.Collections.Generic;
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public sealed class ColumnsTests
{
private sealed class User
{
public string Name { get; set; }
public string Country { get; set; }
}
[Fact]
public void Should_Render_Columns_Correctly()
{
// Given
var console = new PlainConsole(width: 61);
var users = new[]
{
new User { Name = "Savannah Thompson", Country = "Australia" },
new User { Name = "Sophie Ramos", Country = "United States" },
new User { Name = "Katrin Goldberg", Country = "Germany" },
};
var cards = new List<Panel>();
foreach (var user in users)
{
cards.Add(
new Panel($"[b]{user.Name}[/]\n[yellow]{user.Country}[/]")
.RoundedBorder().Expand());
}
// When
console.Render(new Columns(cards));
// Then
console.Lines.Count.ShouldBe(4);
console.Lines[0].ShouldBe("╭────────────────────╮ ╭────────────────╮ ╭─────────────────╮");
console.Lines[1].ShouldBe("│ Savannah Thompson │ │ Sophie Ramos │ │ Katrin Goldberg │");
console.Lines[2].ShouldBe("│ Australia │ │ United States │ │ Germany │");
console.Lines[3].ShouldBe("╰────────────────────╯ ╰────────────────╯ ╰─────────────────╯");
}
}
}

View File

@@ -0,0 +1,44 @@
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public sealed class EmojiTests
{
[Fact]
public void Should_Substitute_Emoji_Shortcodes_In_Markdown()
{
// Given
var console = new TestableAnsiConsole(ColorSystem.Standard, AnsiSupport.Yes);
// When
console.Markup("Hello :globe_showing_europe_africa:!");
// Then
console.Output.ShouldBe("Hello 🌍!");
}
[Fact]
public void Should_Contain_Predefined_Emojis()
{
// Given, When
const string result = "Hello " + Emoji.Known.GlobeShowingEuropeAfrica + "!";
// Then
result.ShouldBe("Hello 🌍!");
}
public sealed class TheReplaceMethod
{
[Fact]
public void Should_Replace_Emojis_In_Text()
{
// Given, When
var result = Emoji.Replace("Hello :globe_showing_europe_africa:!");
// Then
result.ShouldBe("Hello 🌍!");
}
}
}
}

View File

@@ -42,7 +42,7 @@ namespace Spectre.Console.Tests.Unit
}
[Fact]
public void Should_Throw_If_Row_Columns_Is_Less_Than_Number_Of_Columns()
public void Should_Add_Empty_Items_If_User_Provides_Less_Row_Items_Than_Columns()
{
// Given
var grid = new Grid();
@@ -50,11 +50,10 @@ namespace Spectre.Console.Tests.Unit
grid.AddColumn();
// When
var result = Record.Exception(() => grid.AddRow("Foo"));
grid.AddRow("Foo");
// Then
result.ShouldBeOfType<InvalidOperationException>();
result.Message.ShouldBe("The number of row columns are less than the number of grid columns.");
grid.RowCount.ShouldBe(1);
}
[Fact]
@@ -191,9 +190,9 @@ namespace Spectre.Console.Tests.Unit
// Given
var console = new PlainConsole(width: 80);
var grid = new Grid();
grid.AddColumn(new GridColumn { Padding = new Padding(3, 0) });
grid.AddColumn(new GridColumn { Padding = new Padding(0, 0) });
grid.AddColumn(new GridColumn { Padding = new Padding(0, 3) });
grid.AddColumn(new GridColumn { Padding = new Padding(3, 0, 0, 0) });
grid.AddColumn(new GridColumn { Padding = new Padding(0, 0, 0, 0) });
grid.AddColumn(new GridColumn { Padding = new Padding(0, 0, 3, 0) });
grid.AddRow("Foo", "Bar", "Baz");
grid.AddRow("Qux", "Corgi", "Waldo");
grid.AddRow("Grault", "Garply", "Fred");
@@ -214,7 +213,7 @@ namespace Spectre.Console.Tests.Unit
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.AddColumn(new GridColumn { Padding = new Padding(2, 0, 0, 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[/].");

View File

@@ -12,7 +12,7 @@ namespace Spectre.Console.Tests.Unit
public void Should_Throw_If_Closing_Tag_Is_Not_Properly_Escaped(string input)
{
// Given
var fixture = new PlainConsole();
var console = new PlainConsole();
// When
var result = Record.Exception(() => new Markup(input));
@@ -27,14 +27,30 @@ namespace Spectre.Console.Tests.Unit
public void Should_Escape_Markup_Blocks_As_Expected()
{
// Given
var fixture = new PlainConsole();
var console = new PlainConsole();
var markup = new Markup("Hello [[ World ]] !");
// When
fixture.Render(markup);
console.Render(markup);
// Then
fixture.Output.ShouldBe("Hello [ World ] !");
console.Output.ShouldBe("Hello [ World ] !");
}
[Theory]
[InlineData("Hello [link=http://example.com]example.com[/]", "Hello example.com")]
[InlineData("Hello [link=http://example.com]http://example.com[/]", "Hello http://example.com")]
public void Should_Render_Links_As_Expected(string input, string output)
{
// Given
var console = new PlainConsole();
var markup = new Markup(input);
// When
console.Render(markup);
// Then
console.Output.ShouldBe(output);
}
}
}

View File

@@ -0,0 +1,107 @@
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public sealed class PadderTests
{
[Fact]
public void Should_Render_Padded_Object_Correctly()
{
// Given
var console = new PlainConsole(width: 60);
var table = new Table();
table.AddColumn("Foo");
table.AddColumn("Bar");
table.AddRow("Baz", "Qux");
table.AddRow("Corgi", "Waldo");
// When
console.Render(new Padder(table).SetPadding(1, 2, 3, 4));
// Then
console.Lines.Count.ShouldBe(12);
console.Lines[00].ShouldBe(" ");
console.Lines[01].ShouldBe(" ");
console.Lines[02].ShouldBe(" ┌───────┬───────┐ ");
console.Lines[03].ShouldBe(" │ Foo │ Bar │ ");
console.Lines[04].ShouldBe(" ├───────┼───────┤ ");
console.Lines[05].ShouldBe(" │ Baz │ Qux │ ");
console.Lines[06].ShouldBe(" │ Corgi │ Waldo │ ");
console.Lines[07].ShouldBe(" └───────┴───────┘ ");
console.Lines[08].ShouldBe(" ");
console.Lines[09].ShouldBe(" ");
console.Lines[10].ShouldBe(" ");
console.Lines[11].ShouldBe(" ");
}
[Fact]
public void Should_Render_Expanded_Padded_Object_Correctly()
{
// Given
var console = new PlainConsole(width: 60);
var table = new Table();
table.AddColumn("Foo");
table.AddColumn("Bar");
table.AddRow("Baz", "Qux");
table.AddRow("Corgi", "Waldo");
// When
console.Render(new Padder(table)
.SetPadding(1, 2, 3, 4)
.Expand());
// Then
console.Lines.Count.ShouldBe(12);
console.Lines[00].ShouldBe(" ");
console.Lines[01].ShouldBe(" ");
console.Lines[02].ShouldBe(" ┌───────┬───────┐ ");
console.Lines[03].ShouldBe(" │ Foo │ Bar │ ");
console.Lines[04].ShouldBe(" ├───────┼───────┤ ");
console.Lines[05].ShouldBe(" │ Baz │ Qux │ ");
console.Lines[06].ShouldBe(" │ Corgi │ Waldo │ ");
console.Lines[07].ShouldBe(" └───────┴───────┘ ");
console.Lines[08].ShouldBe(" ");
console.Lines[09].ShouldBe(" ");
console.Lines[10].ShouldBe(" ");
console.Lines[11].ShouldBe(" ");
}
[Fact]
public void Should_Render_Padded_Object_Correctly_When_Nested_Within_Other_Object()
{
// Given
var console = new PlainConsole(width: 60);
var table = new Table();
table.AddColumn("Foo");
table.AddColumn("Bar", c => c.PadLeft(0).PadRight(0));
table.AddRow("Baz", "Qux");
table.AddRow(new Text("Corgi"), new Padder(new Panel("Waldo"))
.SetPadding(2, 1, 2, 1));
// When
console.Render(new Padder(table)
.SetPadding(1, 2, 3, 4)
.Expand());
// Then
console.Lines.Count.ShouldBe(16);
console.Lines[00].ShouldBe(" ");
console.Lines[01].ShouldBe(" ");
console.Lines[02].ShouldBe(" ┌───────┬─────────────┐ ");
console.Lines[03].ShouldBe(" │ Foo │Bar │ ");
console.Lines[04].ShouldBe(" ├───────┼─────────────┤ ");
console.Lines[05].ShouldBe(" │ Baz │Qux │ ");
console.Lines[06].ShouldBe(" │ Corgi │ │ ");
console.Lines[07].ShouldBe(" │ │ ┌───────┐ │ ");
console.Lines[08].ShouldBe(" │ │ │ Waldo │ │ ");
console.Lines[09].ShouldBe(" │ │ └───────┘ │ ");
console.Lines[10].ShouldBe(" │ │ │ ");
console.Lines[11].ShouldBe(" └───────┴─────────────┘ ");
console.Lines[12].ShouldBe(" ");
console.Lines[13].ShouldBe(" ");
console.Lines[14].ShouldBe(" ");
console.Lines[15].ShouldBe(" ");
}
}
}

View File

@@ -21,6 +21,25 @@ namespace Spectre.Console.Tests.Unit
console.Lines[2].ShouldBe("└─────────────┘");
}
[Fact]
public void Should_Render_Panel_With_Padding_Set_To_Zero()
{
// Given
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel(new Text("Hello World"))
{
Padding = new Padding(0, 0, 0, 0),
});
// 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()
{
@@ -30,14 +49,119 @@ namespace Spectre.Console.Tests.Unit
// When
console.Render(new Panel(new Text("Hello World"))
{
Padding = new Padding(3, 5),
Padding = new Padding(3, 1, 5, 2),
});
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("┌───────────────────┐");
console.Lines[1].ShouldBe("│ │");
console.Lines[2].ShouldBe("│ Hello World │");
console.Lines[3].ShouldBe("│ │");
console.Lines[4].ShouldBe("│ │");
console.Lines[5].ShouldBe("└───────────────────┘");
}
[Fact]
public void Should_Render_Panel_With_Header()
{
// Given
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel("Hello World")
{
Header = new PanelHeader("Greeting"),
Expand = true,
Padding = new Padding(2, 0, 2, 0),
});
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("┌───────────────────┐");
console.Lines[1].ShouldBe("│ Hello World │");
console.Lines[2].ShouldBe("└───────────────────┘");
console.Lines[0].ShouldBe("┌─Greeting─────────────────────────────────────────────────────────────────────┐");
console.Lines[1].ShouldBe("│ Hello World │");
console.Lines[2].ShouldBe("└──────────────────────────────────────────────────────────────────────────────┘");
}
[Fact]
public void Should_Render_Panel_With_Left_Aligned_Header()
{
// Given
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel("Hello World")
{
Header = new PanelHeader("Greeting").LeftAligned(),
Expand = true,
});
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("┌─Greeting─────────────────────────────────────────────────────────────────────┐");
console.Lines[1].ShouldBe("│ Hello World │");
console.Lines[2].ShouldBe("└──────────────────────────────────────────────────────────────────────────────┘");
}
[Fact]
public void Should_Render_Panel_With_Centered_Header()
{
// Given
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel("Hello World")
{
Header = new PanelHeader("Greeting").Centered(),
Expand = true,
});
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("┌───────────────────────────────────Greeting───────────────────────────────────┐");
console.Lines[1].ShouldBe("│ Hello World │");
console.Lines[2].ShouldBe("└──────────────────────────────────────────────────────────────────────────────┘");
}
[Fact]
public void Should_Render_Panel_With_Right_Aligned_Header()
{
// Given
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel("Hello World")
{
Header = new PanelHeader("Greeting").RightAligned(),
Expand = true,
});
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("┌─────────────────────────────────────────────────────────────────────Greeting─┐");
console.Lines[1].ShouldBe("│ Hello World │");
console.Lines[2].ShouldBe("└──────────────────────────────────────────────────────────────────────────────┘");
}
[Fact]
public void Should_Collapse_Header_If_It_Will_Not_Fit()
{
// Given
var console = new PlainConsole(width: 10);
// When
console.Render(new Panel("Hello World")
{
Header = new PanelHeader("Greeting"),
Expand = true,
});
// Then
console.Lines.Count.ShouldBe(4);
console.Lines[0].ShouldBe("┌─Greet…─┐");
console.Lines[1].ShouldBe("│ Hello │");
console.Lines[2].ShouldBe("│ World │");
console.Lines[3].ShouldBe("└────────┘");
}
[Fact]

View File

@@ -0,0 +1,66 @@
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public sealed class RecorderTests
{
[Fact]
public void Should_Export_Text_As_Expected()
{
// Given
var console = new PlainConsole();
var recorder = new Recorder(console);
recorder.Render(new Table()
.AddColumns("Foo", "Bar", "Qux")
.AddRow("Corgi", "Waldo", "Zap")
.AddRow(new Panel("Hello World").RoundedBorder()));
// When
var result = recorder.ExportText().Split(new[] { '\n' });
// Then
result.Length.ShouldBe(8);
result[0].ShouldBe("┌─────────────────┬───────┬─────┐");
result[1].ShouldBe("│ Foo │ Bar │ Qux │");
result[2].ShouldBe("├─────────────────┼───────┼─────┤");
result[3].ShouldBe("│ Corgi │ Waldo │ Zap │");
result[4].ShouldBe("│ ╭─────────────╮ │ │ │");
result[5].ShouldBe("│ │ Hello World │ │ │ │");
result[6].ShouldBe("│ ╰─────────────╯ │ │ │");
result[7].ShouldBe("└─────────────────┴───────┴─────┘");
}
[Fact]
public void Should_Export_Html_As_Expected()
{
// Given
var console = new PlainConsole();
var recorder = new Recorder(console);
recorder.Render(new Table()
.AddColumns("[red on black]Foo[/]", "[green bold]Bar[/]", "[blue italic]Qux[/]")
.AddRow("[invert underline]Corgi[/]", "[bold strikethrough]Waldo[/]", "[dim]Zap[/]")
.AddRow(new Panel("[blue]Hello World[/]")
.SetBorderColor(Color.Red).RoundedBorder()));
// When
var html = recorder.ExportHtml();
var result = html.Split(new[] { '\n' });
// Then
result.Length.ShouldBe(10);
result[0].ShouldBe("<pre style=\"font-size:90%;font-family:consolas,'Courier New',monospace\">");
result[1].ShouldBe("<span>┌─────────────────┬───────┬─────┐</span>");
result[2].ShouldBe("<span>│ </span><span style=\"color: #FF0000;background-color: #000000\">Foo</span><span> │ </span><span style=\"color: #008000;font-weight: bold;font-style: italic\">Bar</span><span> │ </span><span style=\"color: #0000FF\">Qux</span><span> │</span>");
result[3].ShouldBe("<span>├─────────────────┼───────┼─────┤</span>");
result[4].ShouldBe("<span>│ </span><span style=\"text-decoration: underline\">Corgi</span><span> │ </span><span style=\"font-weight: bold;font-style: italic;text-decoration: line-through\">Waldo</span><span> │ </span><span style=\"color: #7F7F7F\">Zap</span><span> │</span>");
result[5].ShouldBe("<span>│ </span><span style=\"color: #FF0000\">╭─────────────╮</span><span> │ │ │</span>");
result[6].ShouldBe("<span>│ </span><span style=\"color: #FF0000\">│</span><span> </span><span style=\"color: #0000FF\">Hello World</span><span> </span><span style=\"color: #FF0000\">│</span><span> │ │ │</span>");
result[7].ShouldBe("<span>│ </span><span style=\"color: #FF0000\">╰─────────────╯</span><span> │ │ │</span>");
result[8].ShouldBe("<span>└─────────────────┴───────┴─────┘</span>");
result[9].ShouldBe("</pre>");
}
}
}

View File

@@ -0,0 +1,96 @@
using Shouldly;
using Spectre.Console.Rendering;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public sealed class RowsTests
{
[Fact]
public void Should_Render_Rows()
{
// Given
var console = new PlainConsole(width: 60);
var rows = new Rows(
new IRenderable[]
{
new Markup("Hello"),
new Table()
.AddColumns("Foo", "Bar")
.AddRow("Baz", "Qux"),
new Markup("World"),
});
// When
console.Render(rows);
// Then
console.Lines.Count.ShouldBe(7);
console.Lines[0].ShouldBe("Hello");
console.Lines[1].ShouldBe("┌─────┬─────┐");
console.Lines[2].ShouldBe("│ Foo │ Bar │");
console.Lines[3].ShouldBe("├─────┼─────┤");
console.Lines[4].ShouldBe("│ Baz │ Qux │");
console.Lines[5].ShouldBe("└─────┴─────┘");
console.Lines[6].ShouldBe("World");
}
[Fact]
public void Should_Render_Rows_Correctly_Inside_Other_Widget()
{
// Given
var console = new PlainConsole(width: 60);
var table = new Table()
.AddColumns("Foo", "Bar")
.AddRow("HELLO WORLD")
.AddRow(
new Rows(new IRenderable[]
{
new Markup("Hello"),
new Markup("World"),
}), new Text("Qux"));
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(7);
console.Lines[0].ShouldBe("┌─────────────┬─────┐");
console.Lines[1].ShouldBe("│ Foo │ Bar │");
console.Lines[2].ShouldBe("├─────────────┼─────┤");
console.Lines[3].ShouldBe("│ HELLO WORLD │ │");
console.Lines[4].ShouldBe("│ Hello │ Qux │");
console.Lines[5].ShouldBe("│ World │ │");
console.Lines[6].ShouldBe("└─────────────┴─────┘");
}
[Fact]
public void Should_Render_Rows_Correctly_Inside_Other_Widget_When_Expanded()
{
// Given
var console = new PlainConsole(width: 60);
var table = new Table()
.AddColumns("Foo", "Bar")
.AddRow("HELLO WORLD")
.AddRow(
new Rows(new IRenderable[]
{
new Markup("Hello"),
new Markup("World"),
}).Expand(), new Text("Qux"));
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(7);
console.Lines[0].ShouldBe("┌────────────────────────────────────────────────────┬─────┐");
console.Lines[1].ShouldBe("│ Foo │ Bar │");
console.Lines[2].ShouldBe("├────────────────────────────────────────────────────┼─────┤");
console.Lines[3].ShouldBe("│ HELLO WORLD │ │");
console.Lines[4].ShouldBe("│ Hello │ Qux │");
console.Lines[5].ShouldBe("│ World │ │");
console.Lines[6].ShouldBe("└────────────────────────────────────────────────────┴─────┘");
}
}
}

View File

@@ -11,7 +11,7 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic);
var other = new Style(Color.Green, Color.Silver, Decoration.Underline);
var other = new Style(Color.Green, Color.Silver, Decoration.Underline, "https://example.com");
// When
var result = first.Combine(other);
@@ -20,6 +20,77 @@ namespace Spectre.Console.Tests.Unit
result.Foreground.ShouldBe(Color.Green);
result.Background.ShouldBe(Color.Silver);
result.Decoration.ShouldBe(Decoration.Bold | Decoration.Italic | Decoration.Underline);
result.Link.ShouldBe("https://example.com");
}
[Fact]
public void Should_Consider_Two_Identical_Styles_Equal()
{
// Given
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
var second = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
// When
var result = first.Equals(second);
// Then
result.ShouldBeTrue();
}
[Fact]
public void Should_Not_Consider_Two_Styles_With_Different_Foreground_Colors_Equal()
{
// Given
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
var second = new Style(Color.Blue, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
// When
var result = first.Equals(second);
// Then
result.ShouldBeFalse();
}
[Fact]
public void Should_Not_Consider_Two_Styles_With_Different_Background_Colors_Equal()
{
// Given
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
var second = new Style(Color.White, Color.Blue, Decoration.Bold | Decoration.Italic, "http://example.com");
// When
var result = first.Equals(second);
// Then
result.ShouldBeFalse();
}
[Fact]
public void Should_Not_Consider_Two_Styles_With_Different_Decorations_Equal()
{
// Given
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
var second = new Style(Color.White, Color.Yellow, Decoration.Bold, "http://example.com");
// When
var result = first.Equals(second);
// Then
result.ShouldBeFalse();
}
[Fact]
public void Should_Not_Consider_Two_Styles_With_Different_Links_Equal()
{
// Given
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
var second = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://foo.com");
// When
var result = first.Equals(second);
// Then
result.ShouldBeFalse();
}
public sealed class TheParseMethod
@@ -62,16 +133,36 @@ namespace Spectre.Console.Tests.Unit
}
[Fact]
public void Should_Parse_Text_And_Decoration()
public void Should_Parse_Link_Without_Address()
{
// Given, When
var result = Style.Parse("bold underline blue on green");
var result = Style.Parse("link");
// Then
result.ShouldNotBeNull();
result.Decoration.ShouldBe(Decoration.Bold | Decoration.Underline);
result.Foreground.ShouldBe(Color.Blue);
result.Background.ShouldBe(Color.Green);
result.Link.ShouldBe("https://emptylink");
}
[Fact]
public void Should_Parse_Link()
{
// Given, When
var result = Style.Parse("link=https://example.com");
// Then
result.ShouldNotBeNull();
result.Link.ShouldBe("https://example.com");
}
[Fact]
public void Should_Throw_If_Link_Is_Set_Twice()
{
// Given, When
var result = Record.Exception(() => Style.Parse("link=https://example.com link=https://example.com"));
// Then
result.ShouldBeOfType<InvalidOperationException>();
result.Message.ShouldBe("A link has already been set.");
}
[Fact]
@@ -131,6 +222,20 @@ namespace Spectre.Console.Tests.Unit
result.Message.ShouldBe("Could not find color 'lol'.");
}
[Fact]
public void Should_Parse_Colors_And_Decoration_And_Link()
{
// Given, When
var result = Style.Parse("link=https://example.com 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);
result.Link.ShouldBe("https://example.com");
}
[Theory]
[InlineData("#FF0000 on #0000FF")]
[InlineData("#F00 on #00F")]

View File

@@ -0,0 +1,907 @@
using Shouldly;
using Spectre.Console.Rendering;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public sealed class TableBorderTests
{
public sealed class NoBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.None.Visible;
// Then
visibility.ShouldBeFalse();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.None.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.None);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().NoBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("Header 1 Header 2");
console.Lines[1].ShouldBe("Cell Cell ");
console.Lines[2].ShouldBe("Cell Cell ");
}
}
public sealed class AsciiBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.Ascii.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.Ascii.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Ascii);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().AsciiBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("+---------------------+");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("|----------+----------|");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe("+---------------------+");
}
}
public sealed class Ascii2Border
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.Ascii2.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.Ascii2.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Ascii2);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().Ascii2Border();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("+----------+----------+");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("|----------+----------|");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe("+----------+----------+");
}
}
public sealed class AsciiDoubleHeadBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.AsciiDoubleHead.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.AsciiDoubleHead.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.AsciiDoubleHead);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().AsciiDoubleHeadBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("+----------+----------+");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("|==========+==========|");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe("+----------+----------+");
}
}
public sealed class SquareBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.Square.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.Square.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Square);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().SquareBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("┌──────────┬──────────┐");
console.Lines[1].ShouldBe("│ Header 1 │ Header 2 │");
console.Lines[2].ShouldBe("├──────────┼──────────┤");
console.Lines[3].ShouldBe("│ Cell │ Cell │");
console.Lines[4].ShouldBe("│ Cell │ Cell │");
console.Lines[5].ShouldBe("└──────────┴──────────┘");
}
}
public sealed class RoundedBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.Rounded.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.Rounded.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Square);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().RoundedBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("╭──────────┬──────────╮");
console.Lines[1].ShouldBe("│ Header 1 │ Header 2 │");
console.Lines[2].ShouldBe("├──────────┼──────────┤");
console.Lines[3].ShouldBe("│ Cell │ Cell │");
console.Lines[4].ShouldBe("│ Cell │ Cell │");
console.Lines[5].ShouldBe("╰──────────┴──────────╯");
}
}
public sealed class MinimalBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.Minimal.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.Minimal.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Minimal);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().MinimalBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe(" Header 1 │ Header 2 ");
console.Lines[2].ShouldBe(" ──────────┼────────── ");
console.Lines[3].ShouldBe(" Cell │ Cell ");
console.Lines[4].ShouldBe(" Cell │ Cell ");
console.Lines[5].ShouldBe(" ");
}
}
public sealed class MinimalHeavyHeadBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.MinimalHeavyHead.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.MinimalHeavyHead.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Minimal);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().MinimalHeavyHeadBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe(" Header 1 │ Header 2 ");
console.Lines[2].ShouldBe(" ━━━━━━━━━━┿━━━━━━━━━━ ");
console.Lines[3].ShouldBe(" Cell │ Cell ");
console.Lines[4].ShouldBe(" Cell │ Cell ");
console.Lines[5].ShouldBe(" ");
}
}
public sealed class MinimalDoubleHeadBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.MinimalDoubleHead.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.MinimalDoubleHead.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.MinimalDoubleHead);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().MinimalDoubleHeadBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe(" Header 1 │ Header 2 ");
console.Lines[2].ShouldBe(" ══════════╪══════════ ");
console.Lines[3].ShouldBe(" Cell │ Cell ");
console.Lines[4].ShouldBe(" Cell │ Cell ");
console.Lines[5].ShouldBe(" ");
}
}
public sealed class SimpleBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.Simple.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.Simple.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Simple);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().SimpleBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe(" Header 1 Header 2 ");
console.Lines[2].ShouldBe("───────────────────────");
console.Lines[3].ShouldBe(" Cell Cell ");
console.Lines[4].ShouldBe(" Cell Cell ");
console.Lines[5].ShouldBe(" ");
}
}
public sealed class HorizontalBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.Horizontal.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.Horizontal.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Horizontal);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().HorizontalBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("───────────────────────");
console.Lines[1].ShouldBe(" Header 1 Header 2 ");
console.Lines[2].ShouldBe("───────────────────────");
console.Lines[3].ShouldBe(" Cell Cell ");
console.Lines[4].ShouldBe(" Cell Cell ");
console.Lines[5].ShouldBe("───────────────────────");
}
}
public sealed class SimpleHeavyBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.SimpleHeavy.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.SimpleHeavy.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Simple);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().SimpleHeavyBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe(" Header 1 Header 2 ");
console.Lines[2].ShouldBe("━━━━━━━━━━━━━━━━━━━━━━━");
console.Lines[3].ShouldBe(" Cell Cell ");
console.Lines[4].ShouldBe(" Cell Cell ");
console.Lines[5].ShouldBe(" ");
}
}
public sealed class HeavyBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.Heavy.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.Heavy.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Square);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().HeavyBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("┏━━━━━━━━━━┳━━━━━━━━━━┓");
console.Lines[1].ShouldBe("┃ Header 1 ┃ Header 2 ┃");
console.Lines[2].ShouldBe("┣━━━━━━━━━━╋━━━━━━━━━━┫");
console.Lines[3].ShouldBe("┃ Cell ┃ Cell ┃");
console.Lines[4].ShouldBe("┃ Cell ┃ Cell ┃");
console.Lines[5].ShouldBe("┗━━━━━━━━━━┻━━━━━━━━━━┛");
}
}
public sealed class HeavyEdgeBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.HeavyEdge.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.HeavyEdge.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Square);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().HeavyEdgeBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("┏━━━━━━━━━━┯━━━━━━━━━━┓");
console.Lines[1].ShouldBe("┃ Header 1 │ Header 2 ┃");
console.Lines[2].ShouldBe("┠──────────┼──────────┨");
console.Lines[3].ShouldBe("┃ Cell │ Cell ┃");
console.Lines[4].ShouldBe("┃ Cell │ Cell ┃");
console.Lines[5].ShouldBe("┗━━━━━━━━━━┷━━━━━━━━━━┛");
}
}
public sealed class HeavyHeadBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.HeavyHead.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.HeavyHead.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Square);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().HeavyHeadBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("┏━━━━━━━━━━┳━━━━━━━━━━┓");
console.Lines[1].ShouldBe("┃ Header 1 ┃ Header 2 ┃");
console.Lines[2].ShouldBe("┡━━━━━━━━━━╇━━━━━━━━━━┩");
console.Lines[3].ShouldBe("│ Cell │ Cell │");
console.Lines[4].ShouldBe("│ Cell │ Cell │");
console.Lines[5].ShouldBe("└──────────┴──────────┘");
}
}
public sealed class DoubleBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.Double.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.Double.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Double);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().DoubleBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("╔══════════╦══════════╗");
console.Lines[1].ShouldBe("║ Header 1 ║ Header 2 ║");
console.Lines[2].ShouldBe("╠══════════╬══════════╣");
console.Lines[3].ShouldBe("║ Cell ║ Cell ║");
console.Lines[4].ShouldBe("║ Cell ║ Cell ║");
console.Lines[5].ShouldBe("╚══════════╩══════════╝");
}
}
public sealed class DoubleEdgeBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.DoubleEdge.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.DoubleEdge.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.DoubleEdge);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().DoubleEdgeBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("╔══════════╤══════════╗");
console.Lines[1].ShouldBe("║ Header 1 │ Header 2 ║");
console.Lines[2].ShouldBe("╟──────────┼──────────╢");
console.Lines[3].ShouldBe("║ Cell │ Cell ║");
console.Lines[4].ShouldBe("║ Cell │ Cell ║");
console.Lines[5].ShouldBe("╚══════════╧══════════╝");
}
}
public sealed class MarkdownBorder
{
[Fact]
public void Should_Return_Correct_Visibility()
{
// Given, When
var visibility = TableBorder.Markdown.Visible;
// Then
visibility.ShouldBeTrue();
}
public sealed class TheSafeGetBorderMethod
{
[Fact]
public void Should_Return_Safe_Border()
{
// Given, When
var border = TableBorder.Markdown.GetSafeBorder(safe: true);
// Then
border.ShouldBeSameAs(TableBorder.Markdown);
}
}
[Fact]
public void Should_Render_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable().MarkdownBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("| -------- | -------- |");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe(" ");
}
[Fact]
public void Should_Render_Left_Aligned_Table_Columns_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable(header2: Justify.Left).MarkdownBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("| -------- | :------- |");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe(" ");
}
[Fact]
public void Should_Render_Center_Aligned_Table_Columns_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable(header2: Justify.Center).MarkdownBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("| -------- | :------: |");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe(" ");
}
[Fact]
public void Should_Render_Right_Aligned_Table_Columns_As_Expected()
{
// Given
var console = new PlainConsole();
var table = Fixture.GetTable(header2: Justify.Right).MarkdownBorder();
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("| -------- | -------: |");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe(" ");
}
}
private static class Fixture
{
public static Table GetTable(Justify? header1 = null, Justify? header2 = null)
{
var table = new Table();
table.AddColumn("Header 1", c => c.Alignment = header1);
table.AddColumn("Header 2", c => c.Alignment = header2);
table.AddRow("Cell", "Cell");
table.AddRow("Cell", "Cell");
return table;
}
}
}
}

View File

@@ -87,7 +87,7 @@ namespace Spectre.Console.Tests.Unit
}
[Fact]
public void Should_Throw_If_Row_Columns_Is_Less_Than_Number_Of_Columns()
public void Should_Add_Empty_Items_If_User_Provides_Less_Row_Items_Than_Columns()
{
// Given
var table = new Table();
@@ -95,11 +95,10 @@ namespace Spectre.Console.Tests.Unit
table.AddColumn("World");
// When
var result = Record.Exception(() => table.AddRow("Foo"));
table.AddRow("Foo");
// Then
result.ShouldBeOfType<InvalidOperationException>();
result.Message.ShouldBe("The number of row columns are less than the number of table columns.");
table.RowCount.ShouldBe(1);
}
[Fact]
@@ -174,7 +173,7 @@ namespace Spectre.Console.Tests.Unit
{
// A simple table
var console = new PlainConsole(width: 80);
var table = new Table() { Border = BorderKind.Rounded };
var table = new Table() { Border = TableBorder.Rounded };
table.AddColumn("Foo");
table.AddColumn("Bar");
table.AddColumn(new TableColumn("Baz") { Alignment = Justify.Right });
@@ -184,7 +183,7 @@ namespace Spectre.Console.Tests.Unit
// Render a table in some panels.
console.Render(new Panel(new Panel(table)
{
Border = BorderKind.Ascii,
Border = BoxBorder.Ascii,
}));
// Then
@@ -256,7 +255,7 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table { Border = BorderKind.Ascii };
var table = new Table { Border = TableBorder.Ascii };
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
@@ -279,7 +278,7 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table { Border = BorderKind.Rounded };
var table = new Table { Border = TableBorder.Rounded };
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
@@ -302,7 +301,7 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table { Border = BorderKind.None };
var table = new Table { Border = TableBorder.None };
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
@@ -348,7 +347,7 @@ namespace Spectre.Console.Tests.Unit
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.AddColumn(new TableColumn("Baz") { Padding = new Padding(3, 0, 2, 0) });
table.AddRow("Qux\nQuuux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
@@ -373,7 +372,7 @@ namespace Spectre.Console.Tests.Unit
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.AddColumn(new TableColumn("Baz") { Padding = new Padding(3, 0, 2, 0) });
// When
console.Render(table);

View File

@@ -37,14 +37,14 @@ namespace Spectre.Console.Tests.Unit
public void Should_Render_Unstyled_Text_As_Expected()
{
// Given
var fixture = new PlainConsole(width: 80);
var console = new PlainConsole(width: 80);
var text = new Text("Hello World");
// When
fixture.Render(text);
console.Render(text);
// Then
fixture.Output
console.Output
.NormalizeLineEndings()
.ShouldBe("Hello World");
}
@@ -55,14 +55,29 @@ namespace Spectre.Console.Tests.Unit
public void Should_Write_Line_Breaks(string input)
{
// Given
var fixture = new PlainConsole(width: 5);
var console = new PlainConsole(width: 5);
var text = new Text(input);
// When
fixture.Render(text);
console.Render(text);
// Then
fixture.RawOutput.ShouldBe("Hello\n\nWorld\n\n");
console.RawOutput.ShouldBe("Hello\n\nWorld\n\n");
}
[Fact]
public void Should_Render_Panel_2()
{
// Given
var console = new PlainConsole(width: 80);
// When
console.Render(new Markup("[b]Hello World[/]\n[yellow]Hello World[/]"));
// Then
console.Lines.Count.ShouldBe(2);
console.Lines[0].ShouldBe("Hello World");
console.Lines[1].ShouldBe("Hello World");
}
[Theory]
@@ -72,14 +87,34 @@ namespace Spectre.Console.Tests.Unit
int width, string input, string expected)
{
// Given
var fixture = new PlainConsole(width);
var console = new PlainConsole(width);
var text = new Text(input);
// When
fixture.Render(text);
console.Render(text);
// Then
fixture.Output
console.Output
.NormalizeLineEndings()
.ShouldBe(expected);
}
[Theory]
[InlineData(Overflow.Fold, "foo \npneumonoultram\nicroscopicsili\ncovolcanoconio\nsis bar qux")]
[InlineData(Overflow.Crop, "foo \npneumonoultram\nbar qux")]
[InlineData(Overflow.Ellipsis, "foo \npneumonoultra…\nbar qux")]
public void Should_Overflow_Text_Correctly(Overflow overflow, string expected)
{
// Given
var console = new PlainConsole(14);
var text = new Text("foo pneumonoultramicroscopicsilicovolcanoconiosis bar qux")
.SetOverflow(overflow);
// When
console.Render(text);
// Then
console.Output
.NormalizeLineEndings()
.ShouldBe(expected);
}

View File

@@ -17,15 +17,23 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{F0575243-121F-4DEE-9F6B-246E26DC0844}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Table", "..\examples\Table\Table.csproj", "{94ECCBA8-7EBF-4B53-8379-52EB2327417E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tables", "..\examples\Tables\Tables.csproj", "{94ECCBA8-7EBF-4B53-8379-52EB2327417E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Panel", "..\examples\Panel\Panel.csproj", "{BFF37228-B376-4ADD-9657-4E501F929713}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Panels", "..\examples\Panels\Panels.csproj", "{BFF37228-B376-4ADD-9657-4E501F929713}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grid", "..\examples\Grid\Grid.csproj", "{C7FF6FDB-FB59-4517-8669-521C96AB7323}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grids", "..\examples\Grids\Grids.csproj", "{C7FF6FDB-FB59-4517-8669-521C96AB7323}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Colors", "..\examples\Colors\Colors.csproj", "{1F51C55C-BA4C-4856-9001-0F7924FFB179}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Diagnostic", "..\examples\Diagnostic\Diagnostic.csproj", "{4337F255-88E9-4408-81A3-DF1AF58AC753}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Columns", "..\examples\Columns\Columns.csproj", "{33357599-C79D-4299-888F-634E2C3EACEF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Info", "..\examples\Info\Info.csproj", "{225CE0D4-06AB-411A-8D29-707504FE53B3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Borders", "..\examples\Borders\Borders.csproj", "{094245E6-4C94-485D-B5AC-3153E878B112}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Links", "..\examples\Links\Links.csproj", "{6AF8C93B-AA41-4F44-8B1B-B8D166576174}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emojis", "..\examples\Emojis\Emojis.csproj", "{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -109,18 +117,66 @@ Global
{1F51C55C-BA4C-4856-9001-0F7924FFB179}.Release|x64.Build.0 = Release|Any CPU
{1F51C55C-BA4C-4856-9001-0F7924FFB179}.Release|x86.ActiveCfg = Release|Any CPU
{1F51C55C-BA4C-4856-9001-0F7924FFB179}.Release|x86.Build.0 = Release|Any CPU
{4337F255-88E9-4408-81A3-DF1AF58AC753}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4337F255-88E9-4408-81A3-DF1AF58AC753}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4337F255-88E9-4408-81A3-DF1AF58AC753}.Debug|x64.ActiveCfg = Debug|Any CPU
{4337F255-88E9-4408-81A3-DF1AF58AC753}.Debug|x64.Build.0 = Debug|Any CPU
{4337F255-88E9-4408-81A3-DF1AF58AC753}.Debug|x86.ActiveCfg = Debug|Any CPU
{4337F255-88E9-4408-81A3-DF1AF58AC753}.Debug|x86.Build.0 = Debug|Any CPU
{4337F255-88E9-4408-81A3-DF1AF58AC753}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4337F255-88E9-4408-81A3-DF1AF58AC753}.Release|Any CPU.Build.0 = Release|Any CPU
{4337F255-88E9-4408-81A3-DF1AF58AC753}.Release|x64.ActiveCfg = Release|Any CPU
{4337F255-88E9-4408-81A3-DF1AF58AC753}.Release|x64.Build.0 = Release|Any CPU
{4337F255-88E9-4408-81A3-DF1AF58AC753}.Release|x86.ActiveCfg = Release|Any CPU
{4337F255-88E9-4408-81A3-DF1AF58AC753}.Release|x86.Build.0 = Release|Any CPU
{33357599-C79D-4299-888F-634E2C3EACEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{33357599-C79D-4299-888F-634E2C3EACEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{33357599-C79D-4299-888F-634E2C3EACEF}.Debug|x64.ActiveCfg = Debug|Any CPU
{33357599-C79D-4299-888F-634E2C3EACEF}.Debug|x64.Build.0 = Debug|Any CPU
{33357599-C79D-4299-888F-634E2C3EACEF}.Debug|x86.ActiveCfg = Debug|Any CPU
{33357599-C79D-4299-888F-634E2C3EACEF}.Debug|x86.Build.0 = Debug|Any CPU
{33357599-C79D-4299-888F-634E2C3EACEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{33357599-C79D-4299-888F-634E2C3EACEF}.Release|Any CPU.Build.0 = Release|Any CPU
{33357599-C79D-4299-888F-634E2C3EACEF}.Release|x64.ActiveCfg = Release|Any CPU
{33357599-C79D-4299-888F-634E2C3EACEF}.Release|x64.Build.0 = Release|Any CPU
{33357599-C79D-4299-888F-634E2C3EACEF}.Release|x86.ActiveCfg = Release|Any CPU
{33357599-C79D-4299-888F-634E2C3EACEF}.Release|x86.Build.0 = Release|Any CPU
{225CE0D4-06AB-411A-8D29-707504FE53B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{225CE0D4-06AB-411A-8D29-707504FE53B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{225CE0D4-06AB-411A-8D29-707504FE53B3}.Debug|x64.ActiveCfg = Debug|Any CPU
{225CE0D4-06AB-411A-8D29-707504FE53B3}.Debug|x64.Build.0 = Debug|Any CPU
{225CE0D4-06AB-411A-8D29-707504FE53B3}.Debug|x86.ActiveCfg = Debug|Any CPU
{225CE0D4-06AB-411A-8D29-707504FE53B3}.Debug|x86.Build.0 = Debug|Any CPU
{225CE0D4-06AB-411A-8D29-707504FE53B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{225CE0D4-06AB-411A-8D29-707504FE53B3}.Release|Any CPU.Build.0 = Release|Any CPU
{225CE0D4-06AB-411A-8D29-707504FE53B3}.Release|x64.ActiveCfg = Release|Any CPU
{225CE0D4-06AB-411A-8D29-707504FE53B3}.Release|x64.Build.0 = Release|Any CPU
{225CE0D4-06AB-411A-8D29-707504FE53B3}.Release|x86.ActiveCfg = Release|Any CPU
{225CE0D4-06AB-411A-8D29-707504FE53B3}.Release|x86.Build.0 = Release|Any CPU
{094245E6-4C94-485D-B5AC-3153E878B112}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{094245E6-4C94-485D-B5AC-3153E878B112}.Debug|Any CPU.Build.0 = Debug|Any CPU
{094245E6-4C94-485D-B5AC-3153E878B112}.Debug|x64.ActiveCfg = Debug|Any CPU
{094245E6-4C94-485D-B5AC-3153E878B112}.Debug|x64.Build.0 = Debug|Any CPU
{094245E6-4C94-485D-B5AC-3153E878B112}.Debug|x86.ActiveCfg = Debug|Any CPU
{094245E6-4C94-485D-B5AC-3153E878B112}.Debug|x86.Build.0 = Debug|Any CPU
{094245E6-4C94-485D-B5AC-3153E878B112}.Release|Any CPU.ActiveCfg = Release|Any CPU
{094245E6-4C94-485D-B5AC-3153E878B112}.Release|Any CPU.Build.0 = Release|Any CPU
{094245E6-4C94-485D-B5AC-3153E878B112}.Release|x64.ActiveCfg = Release|Any CPU
{094245E6-4C94-485D-B5AC-3153E878B112}.Release|x64.Build.0 = Release|Any CPU
{094245E6-4C94-485D-B5AC-3153E878B112}.Release|x86.ActiveCfg = Release|Any CPU
{094245E6-4C94-485D-B5AC-3153E878B112}.Release|x86.Build.0 = Release|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Debug|x64.ActiveCfg = Debug|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Debug|x64.Build.0 = Debug|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Debug|x86.ActiveCfg = Debug|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Debug|x86.Build.0 = Debug|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Release|Any CPU.Build.0 = Release|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Release|x64.ActiveCfg = Release|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Release|x64.Build.0 = Release|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Release|x86.ActiveCfg = Release|Any CPU
{6AF8C93B-AA41-4F44-8B1B-B8D166576174}.Release|x86.Build.0 = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Debug|x64.ActiveCfg = Debug|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Debug|x64.Build.0 = Debug|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Debug|x86.ActiveCfg = Debug|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Debug|x86.Build.0 = Debug|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|Any CPU.Build.0 = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|x64.ActiveCfg = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|x64.Build.0 = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|x86.ActiveCfg = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -130,7 +186,11 @@ Global
{BFF37228-B376-4ADD-9657-4E501F929713} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{C7FF6FDB-FB59-4517-8669-521C96AB7323} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{1F51C55C-BA4C-4856-9001-0F7924FFB179} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{4337F255-88E9-4408-81A3-DF1AF58AC753} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{33357599-C79D-4299-888F-634E2C3EACEF} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{225CE0D4-06AB-411A-8D29-707504FE53B3} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{094245E6-4C94-485D-B5AC-3153E878B112} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{6AF8C93B-AA41-4F44-8B1B-B8D166576174} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5729B071-67A0-48FB-8B1B-275E6822086C}

View File

@@ -0,0 +1,67 @@
using System;
using Spectre.Console.Rendering;
namespace Spectre.Console
{
/// <summary>
/// A console capable of writing ANSI escape sequences.
/// </summary>
public static partial class AnsiConsole
{
/// <summary>
/// Starts recording the console output.
/// </summary>
public static void Record()
{
_recorder = new Recorder(_console.Value);
}
/// <summary>
/// Exports all recorded console output as text.
/// </summary>
/// <returns>The recorded output as text.</returns>
public static string ExportText()
{
if (_recorder == null)
{
throw new InvalidOperationException("Cannot export text since a recording hasn't been started.");
}
return _recorder.ExportText();
}
/// <summary>
/// Exports all recorded console output as HTML.
/// </summary>
/// <returns>The recorded output as HTML.</returns>
public static string ExportHtml()
{
if (_recorder == null)
{
throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started.");
}
return _recorder.ExportHtml();
}
/// <summary>
/// Exports all recorded console output using a custom encoder.
/// </summary>
/// <param name="encoder">The encoder to use.</param>
/// <returns>The recorded output.</returns>
public static string ExportCustom(IAnsiConsoleEncoder encoder)
{
if (_recorder == null)
{
throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started.");
}
if (encoder is null)
{
throw new ArgumentNullException(nameof(encoder));
}
return _recorder.Export(encoder);
}
}
}

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