mirror of
https://github.com/spectreconsole/spectre.console.git
synced 2025-10-25 15:19:23 +00:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae6d2c63a3 | ||
|
|
e946289bd9 | ||
|
|
bcaaa6b2d3 | ||
|
|
d3588a4b06 | ||
|
|
7471e9d38c | ||
|
|
9f8ca6d648 | ||
|
|
88edfe68ec | ||
|
|
5d32764a64 | ||
|
|
4f6c9c62c7 | ||
|
|
f2677213a4 | ||
|
|
bdaf00a556 | ||
|
|
7de4b6c7b9 | ||
|
|
0bc801e3eb | ||
|
|
88a82cdad0 | ||
|
|
0cecb555d5 | ||
|
|
52e3ee17b0 | ||
|
|
caf7661e66 | ||
|
|
65f0a085cc | ||
|
|
a123806cd8 | ||
|
|
173645cdd2 | ||
|
|
7fd2efaeb5 | ||
|
|
47fd646d21 | ||
|
|
a06859dcb5 | ||
|
|
7d3a67e6ae | ||
|
|
f4497b1278 | ||
|
|
a16daade6c | ||
|
|
ab73d16583 | ||
|
|
f2566f2ca4 | ||
|
|
358b0225b4 |
39
.github/workflows/ci.yaml
vendored
39
.github/workflows/ci.yaml
vendored
@@ -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')"
|
||||
@@ -31,6 +60,16 @@ jobs:
|
||||
with:
|
||||
dotnet-version: 3.1.301
|
||||
|
||||
- name: Integration Tests
|
||||
shell: bash
|
||||
run: |
|
||||
dotnet tool restore
|
||||
dotnet example diagnostic
|
||||
dotnet example table
|
||||
dotnet example grid
|
||||
dotnet example panel
|
||||
dotnet example colors
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
12
.github/workflows/docs.yaml
vendored
12
.github/workflows/docs.yaml
vendored
@@ -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
|
||||
|
||||
31
.github/workflows/publish.yaml
vendored
31
.github/workflows/publish.yaml
vendored
@@ -6,6 +6,8 @@ on:
|
||||
- '*'
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'src/**'
|
||||
|
||||
env:
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
|
||||
@@ -13,13 +15,38 @@ 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
|
||||
if: "!contains(github.event.head_commit.message, 'skip-ci')"
|
||||
needs: [docs]
|
||||
if: "!contains(github.event.head_commit.message, 'skip-ci') || startsWith(github.ref, 'refs/tags/')"
|
||||
strategy:
|
||||
matrix:
|
||||
kind: ['linux', 'windows', 'macOS']
|
||||
@@ -55,7 +82,7 @@ jobs:
|
||||
publish:
|
||||
name: Publish
|
||||
needs: [build]
|
||||
if: "!contains(github.event.head_commit.message, 'skip-ci')"
|
||||
if: "!contains(github.event.head_commit.message, 'skip-ci') || startsWith(github.ref, 'refs/tags/')"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
279
README.md
279
README.md
@@ -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
|
||||
|
||||
@@ -123,280 +121,3 @@ And to run an example:
|
||||
│ 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`
|
||||
|
||||
@@ -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,15 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Statiq.Web" Version="1.0.0-alpha.9" />
|
||||
<PackageReference Include="NJsonSchema" Version="10.1.12" />
|
||||
<PackageReference Include="Statiq.Web" Version="1.0.0-beta.5" />
|
||||
<PackageReference Include="MinVer" PrivateAssets="All" Version="2.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Versioning" BeforeTargets="MinVer">
|
||||
<PropertyGroup Label="Build">
|
||||
<MinVerDefaultPreReleasePhase>preview</MinVerDefaultPreReleasePhase>
|
||||
<MinVerVerbosity>normal</MinVerVerbosity>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
1
docs/Preview.ps1
Normal file
1
docs/Preview.ps1
Normal file
@@ -0,0 +1 @@
|
||||
dotnet run -- preview --virtual-dir "spectre.console"
|
||||
8
docs/README.md
Normal file
8
docs/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Documentation
|
||||
|
||||
Preview the documentation locally by running the following
|
||||
from your favourite shell:
|
||||
|
||||
```
|
||||
> dotnet run -- preview --virtual-dir "spectre.console"
|
||||
```
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
@@ -27,12 +27,33 @@
|
||||
<body class="d-flex flex-column">
|
||||
<div class="flex-grow-1 d-flex flex-column">
|
||||
|
||||
<nav id="topnav" class="navbar navbar-expand-lg navbar-light">
|
||||
<div class="container py-3">
|
||||
<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>
|
||||
<div class="collapse navbar-collapse" id="navbarText">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link font-weight-light font-size-lg text-red" href="https://github.com/sponsors/patriksvensson"><i class="far fa-heart"></i> Sponsor</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link font-weight-light font-size-lg" href="https://github.com/spectresystems/spectre.console"><i class="fab fa-github"></i> GitHub</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@if (IsSectionDefined(Constants.Sections.Splash))
|
||||
{
|
||||
@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)">
|
||||
@@ -105,21 +126,22 @@
|
||||
}
|
||||
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)
|
||||
</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)">
|
||||
DocumentList<IDocument> documentChildren = OutputPages.GetChildrenOf(document);
|
||||
<div class="sidebar-nav-item @(Document.IdEquals(document) ? "active" : null) @(documentChildren.Any() ? "has-children" : null)">
|
||||
@Html.DocumentLink(document)
|
||||
</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)
|
||||
@@ -161,7 +183,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>
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
@using Statiq.Web
|
||||
@using Statiq.Web.Pipelines
|
||||
@using Docs
|
||||
@using Docs.Utilities;
|
||||
|
||||
@inherits StatiqRazorPage<IDocument>
|
||||
@@ -18,6 +18,18 @@ $thebackground: $gray-200;
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
height: 15px;
|
||||
border: 2px solid #000000;
|
||||
}
|
||||
|
||||
#topnav {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#topnav .container {
|
||||
padding-top: 0px !important;
|
||||
padding-bottom: 0px !important;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
@media screen {
|
||||
|
||||
BIN
docs/input/assets/images/helloworld.png
Normal file
BIN
docs/input/assets/images/helloworld.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
@@ -1,5 +1,5 @@
|
||||
Title: Colors
|
||||
Order: 2
|
||||
Order: 4
|
||||
---
|
||||
|
||||
The following is a list of the standard 8-bit colors supported in terminals.
|
||||
@@ -1,6 +0,0 @@
|
||||
Title: Console API
|
||||
Order: 2
|
||||
Hidden: True
|
||||
---
|
||||
|
||||
__To be written__
|
||||
@@ -1,6 +0,0 @@
|
||||
Title: Grids
|
||||
Order: 4
|
||||
Hidden: True
|
||||
---
|
||||
|
||||
__To be written__
|
||||
@@ -1,6 +0,0 @@
|
||||
Title: Panels
|
||||
Order: 5
|
||||
Hidden: True
|
||||
---
|
||||
|
||||
__To be written__
|
||||
@@ -1,6 +0,0 @@
|
||||
Title: Tables
|
||||
Order: 3
|
||||
Hidden: True
|
||||
---
|
||||
|
||||
__To be written__
|
||||
@@ -1,84 +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>
|
||||
}
|
||||
|
||||
@* <div class="container py-3">
|
||||
<div class="row">
|
||||
<div class="col-sm py-3">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<i class="fad fa-heartbeat fa-2x icon-md-100 icon-theme"></i>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<h3 class="font-weight-bold font-size-base text-dark mb-2">A beautiful console</h3>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Aenean elementum est lorem, at auctor nibh rhoncus eget.
|
||||
Ut lorem leo, aliquet sit amet tortor vitae, aliquet eleifend dui.
|
||||
Etiam lectus diam, maximus a pretium a, lacinia in augue.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm py-3">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<i class="fad fa-code fa-2x icon-md-100 icon-theme"></i>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<h3 class="font-weight-bold font-size-base text-dark mb-2">Rich formatting language</h3>
|
||||
<p>
|
||||
Donec at rutrum turpis. Etiam tempor sed ex quis pharetra.
|
||||
Suspendisse ullamcorper at magna ac efficitur. Nulla ornare,
|
||||
lectus feugiat ornare ultricies, nunc lorem maximus ipsum,
|
||||
nec accumsan eros tellus quis ante
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm py-3">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<i class="fad fa-cogs fa-2x icon-md-100 icon-theme"></i>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<h3 class="font-weight-bold font-size-base text-dark mb-2">Configurable</h3>
|
||||
<p>
|
||||
Suspendisse vel condimentum tortor. Fusce tempus ligula ut eros finibus,
|
||||
nec fermentum ipsum hendrerit. Proin eu diam in tortor vestibulum bibendum.
|
||||
Integer tincidunt felis eu urna pulvinar vehicula.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm py-3">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<i class="fad fa-search fa-2x icon-md-100 icon-theme"></i>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<h3 class="font-weight-bold font-size-base text-dark mb-2">Find problems quickly</h3>
|
||||
<p>
|
||||
Aliquam nec nisl ullamcorper, aliquam mauris sit amet, sagittis orci.
|
||||
Aenean sapien dui, eleifend eget sapien nec, tristique accumsan tortor.
|
||||
Quisque ex quam, rhoncus sagittis consequat id, euismod sit amet dolor.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> *@
|
||||
@@ -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.
|
||||
104
docs/input/markup.md
Normal file
104
docs/input/markup.md
Normal file
@@ -0,0 +1,104 @@
|
||||
Title: Markup
|
||||
Order: 3
|
||||
Hidden: False
|
||||
---
|
||||
|
||||
In `Spectre.Console` there's a class called `Markup` that
|
||||
allows you to output rich text to the console.
|
||||
|
||||
```csharp
|
||||
AnsiConsole.Render(new Markup("[bold yellow]Hello[/] [red]World![/]"));
|
||||
```
|
||||
|
||||
Which should output something similar to the image below. Note that the
|
||||
actual appearance might vary depending on your terminal.
|
||||
|
||||

|
||||
|
||||
|
||||
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[/]
|
||||
```
|
||||
|
||||
# Colors
|
||||
|
||||
For a list of colors, see the [Colors](xref:colors) section.
|
||||
|
||||
# Styles
|
||||
|
||||
Note that what styles that can be used is defined by the system or your terminal software, and may not appear as they should.
|
||||
|
||||
<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>
|
||||
@@ -11,15 +11,6 @@ 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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -26,6 +25,7 @@ namespace Docs.Shortcodes
|
||||
var table = new XElement("table", new XAttribute("class", "table"));
|
||||
var header = new XElement("tr", new XAttribute("class", "color-row"));
|
||||
header.Add(new XElement("th", ""));
|
||||
header.Add(new XElement("th", "#"));
|
||||
header.Add(new XElement("th", "Name"));
|
||||
header.Add(new XElement("th", "RGB"));
|
||||
header.Add(new XElement("th", "Hex"));
|
||||
@@ -38,7 +38,8 @@ namespace Docs.Shortcodes
|
||||
new XElement("span",
|
||||
new XAttribute("class", "color-representation"),
|
||||
new XAttribute("style", $"background-color:{color.Hex};")));
|
||||
var name = new XElement("td", new XElement("code", color.Name.ToLower()));
|
||||
var name = new XElement("td", new XElement("code", color.Number.ToString()));
|
||||
var number = new XElement("td", new XElement("code", color.Name.ToLower()));
|
||||
var rgb = new XElement("td", new XElement("code", $"{color.R},{color.G},{color.B}"));
|
||||
var hex = new XElement("td", new XElement("code", color.Hex));
|
||||
var clr = new XElement("td", new XElement("code", color.ClrName));
|
||||
@@ -47,6 +48,7 @@ namespace Docs.Shortcodes
|
||||
var row = new XElement("tr");
|
||||
row.Add(rep);
|
||||
row.Add(name);
|
||||
row.Add(number);
|
||||
row.Add(rgb);
|
||||
row.Add(hex);
|
||||
row.Add(clr);
|
||||
|
||||
34
docs/src/Utilities/VersionUtilities.cs
Normal file
34
docs/src/Utilities/VersionUtilities.cs
Normal 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 "?";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,12 @@
|
||||
"commands": [
|
||||
"gpr"
|
||||
]
|
||||
},
|
||||
"dotnet-example": {
|
||||
"version": "0.8.0",
|
||||
"commands": [
|
||||
"dotnet-example"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,75 +2,117 @@ using Spectre.Console;
|
||||
|
||||
namespace ColorExample
|
||||
{
|
||||
class Program
|
||||
public static class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
public static void Main()
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// 4-BIT
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
AnsiConsole.ResetColors();
|
||||
AnsiConsole.WriteLine();
|
||||
AnsiConsole.MarkupLine("[bold underline]4-bit Colors[/]");
|
||||
AnsiConsole.WriteLine();
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
if (AnsiConsole.Capabilities.ColorSystem == ColorSystem.NoColors)
|
||||
{
|
||||
AnsiConsole.Background = Color.FromInt32(i);
|
||||
AnsiConsole.Write(string.Format(" {0,-9}", AnsiConsole.Background.ToString()));
|
||||
AnsiConsole.ResetColors();
|
||||
if ((i + 1) % 8 == 0)
|
||||
{
|
||||
AnsiConsole.WriteLine();
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// No colors
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
AnsiConsole.WriteLine("No colors are supported.");
|
||||
return;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// 8-BIT
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
AnsiConsole.ResetColors();
|
||||
AnsiConsole.WriteLine();
|
||||
AnsiConsole.MarkupLine("[bold underline]8-bit Colors[/]");
|
||||
AnsiConsole.WriteLine();
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
if (AnsiConsole.Capabilities.Supports(ColorSystem.Legacy))
|
||||
{
|
||||
for (var j = 0; j < 16; j++)
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// 3-BIT
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
AnsiConsole.ResetColors();
|
||||
AnsiConsole.WriteLine();
|
||||
AnsiConsole.MarkupLine("[bold underline]3-bit Colors[/]");
|
||||
AnsiConsole.WriteLine();
|
||||
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
var number = i * 16 + j;
|
||||
AnsiConsole.Background = Color.FromInt32(number);
|
||||
AnsiConsole.Write(string.Format(" {0,-4}", number));
|
||||
AnsiConsole.Background = Color.FromInt32(i);
|
||||
AnsiConsole.Write(string.Format(" {0,-9}", AnsiConsole.Background.ToString()));
|
||||
AnsiConsole.ResetColors();
|
||||
if ((number + 1) % 16 == 0)
|
||||
if ((i + 1) % 8 == 0)
|
||||
{
|
||||
AnsiConsole.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// 24-BIT
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
AnsiConsole.ResetColors();
|
||||
AnsiConsole.WriteLine();
|
||||
AnsiConsole.MarkupLine("[bold underline]24-bit Colors[/]");
|
||||
AnsiConsole.WriteLine();
|
||||
|
||||
var index = 0;
|
||||
for (var i = 0.0005; i < 1; i += 0.0025)
|
||||
if (AnsiConsole.Capabilities.Supports(ColorSystem.Standard))
|
||||
{
|
||||
index++;
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// 4-BIT
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
var color = Utilities.HSL2RGB(i, 0.5, 0.5);
|
||||
AnsiConsole.Background = new Color(color.R, color.G, color.B);
|
||||
AnsiConsole.Write(" ");
|
||||
AnsiConsole.ResetColors();
|
||||
AnsiConsole.WriteLine();
|
||||
AnsiConsole.MarkupLine("[bold underline]4-bit Colors[/]");
|
||||
AnsiConsole.WriteLine();
|
||||
|
||||
if (index % 50 == 0)
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
AnsiConsole.WriteLine();
|
||||
AnsiConsole.Background = Color.FromInt32(i);
|
||||
AnsiConsole.Write(string.Format(" {0,-9}", AnsiConsole.Background.ToString()));
|
||||
AnsiConsole.ResetColors();
|
||||
if ((i + 1) % 8 == 0)
|
||||
{
|
||||
AnsiConsole.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (AnsiConsole.Capabilities.Supports(ColorSystem.EightBit))
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// 8-BIT
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
AnsiConsole.ResetColors();
|
||||
AnsiConsole.WriteLine();
|
||||
AnsiConsole.MarkupLine("[bold underline]8-bit Colors[/]");
|
||||
AnsiConsole.WriteLine();
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
for (var j = 0; j < 16; j++)
|
||||
{
|
||||
var number = i * 16 + j;
|
||||
AnsiConsole.Background = Color.FromInt32(number);
|
||||
AnsiConsole.Write(string.Format(" {0,-4}", number));
|
||||
AnsiConsole.ResetColors();
|
||||
if ((number + 1) % 16 == 0)
|
||||
{
|
||||
AnsiConsole.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (AnsiConsole.Capabilities.Supports(ColorSystem.TrueColor))
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// 24-BIT
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
AnsiConsole.ResetColors();
|
||||
AnsiConsole.WriteLine();
|
||||
AnsiConsole.MarkupLine("[bold underline]24-bit Colors[/]");
|
||||
AnsiConsole.WriteLine();
|
||||
|
||||
var index = 0;
|
||||
for (var i = 0.0005; i < 1; i += 0.0025)
|
||||
{
|
||||
index++;
|
||||
|
||||
var color = Utilities.HSL2RGB(i, 0.5, 0.5);
|
||||
AnsiConsole.Background = new Color(color.R, color.G, color.B);
|
||||
AnsiConsole.Write(" ");
|
||||
|
||||
if (index % 50 == 0)
|
||||
{
|
||||
AnsiConsole.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
17
examples/Columns/Columns.csproj
Normal file
17
examples/Columns/Columns.csproj
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
42
examples/Columns/Program.cs
Normal file
42
examples/Columns/Program.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Spectre.Console;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
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}[/]";
|
||||
}
|
||||
}
|
||||
}
|
||||
14
examples/Diagnostic/Diagnostic.csproj
Normal file
14
examples/Diagnostic/Diagnostic.csproj
Normal file
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Description>Displays the capabilities of the current console.</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
17
examples/Diagnostic/Program.cs
Normal file
17
examples/Diagnostic/Program.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Spectre.Console;
|
||||
|
||||
namespace Diagnostic
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,12 @@ using Spectre.Console;
|
||||
|
||||
namespace GridExample
|
||||
{
|
||||
public sealed class Program
|
||||
public static class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
public static void Main()
|
||||
{
|
||||
AnsiConsole.WriteLine();
|
||||
AnsiConsole.MarkupLine("Usage: [grey]dotnet [blue]run[/] [[options] [[[[--] <additional arguments>...]][/]");
|
||||
AnsiConsole.MarkupLine("Usage: [grey]dotnet [blue]run[/] [[options]] [[[[--]] <additional arguments>...]]]][/]");
|
||||
AnsiConsole.WriteLine();
|
||||
|
||||
var grid = new Grid();
|
||||
|
||||
@@ -1,45 +1,41 @@
|
||||
using Spectre.Console;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace PanelExample
|
||||
{
|
||||
class Program
|
||||
public static class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
public static void Main()
|
||||
{
|
||||
var content = new Markup(
|
||||
"[underline]I[/] heard [underline on blue]you[/] like 📦\n\n\n\n" +
|
||||
"So I put a 📦 in a 📦\n\n" +
|
||||
"😅").Centered();
|
||||
"[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
|
||||
}));
|
||||
.SetBorderKind(BorderKind.Rounded)));
|
||||
|
||||
// Left adjusted panel with text
|
||||
AnsiConsole.Render(new Panel(
|
||||
new Text("Left adjusted\nLeft").LeftAligned())
|
||||
{
|
||||
Expand = true,
|
||||
});
|
||||
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 = true,
|
||||
Border = BorderKind.Ascii,
|
||||
});
|
||||
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 = true,
|
||||
Border = BorderKind.Rounded,
|
||||
});
|
||||
AnsiConsole.Render(
|
||||
new Panel(new Text("Right adjusted\nRight").RightAligned())
|
||||
.Expand()
|
||||
.RoundedBorder()
|
||||
.SetHeader("Right", Style.WithForeground(Color.Blue), Justify.Right));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,21 +35,21 @@ namespace TableExample
|
||||
private static void RenderBigTable()
|
||||
{
|
||||
// Create the table.
|
||||
var table = new Table().SetBorder(BorderKind.Rounded);
|
||||
var table = new Table().SetBorderKind(BorderKind.Rounded);
|
||||
table.AddColumn("[red underline]Foo[/]");
|
||||
table.AddColumn(new TableColumn("[blue]Bar[/]") { Alignment = Justify.Right, NoWrap = true });
|
||||
|
||||
// Add some rows
|
||||
table.AddRow("[blue][underline]Hell[/]o[/]", "World 🌍");
|
||||
table.AddRow("[blue][underline]Hell[/]o[/]", "World");
|
||||
table.AddRow("[yellow]Patrik [green]\"Hello World\"[/] Svensson[/]", "Was [underline]here[/]!");
|
||||
table.AddEmptyRow();
|
||||
table.AddRow(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit,sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
|
||||
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure " +
|
||||
"dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat " +
|
||||
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum", "◀ Strange language");
|
||||
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum", "<- Strange language");
|
||||
table.AddEmptyRow();
|
||||
table.AddRow("Hej 👋", "[green]Världen[/]");
|
||||
table.AddRow("Hej", "[green]Världen[/]");
|
||||
|
||||
AnsiConsole.Render(table);
|
||||
}
|
||||
@@ -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().SetBorderKind(BorderKind.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().SetBorderKind(BorderKind.Square).SetBorderColor(Color.Green);
|
||||
second.AddColumn(new TableColumn("[u]Foo[/]"));
|
||||
second.AddColumn(new TableColumn("[u]Bar[/]"));
|
||||
second.AddColumn(new TableColumn("[u]Baz[/]"));
|
||||
@@ -75,13 +74,13 @@ 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().SetBorderKind(BorderKind.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)));
|
||||
|
||||
// Add some rows
|
||||
table.AddRow(new Text("Hello").Centered(), new Markup("[red]World![/] 🌍"), Text.Empty);
|
||||
table.AddRow(new Text("Hello").Centered(), new Markup("[red]World![/]"), Text.Empty);
|
||||
table.AddRow(second, new Text("Whaaat"), new Text("Lol"));
|
||||
table.AddRow(new Markup("[blue]Hej[/]").Centered(), new Markup("[yellow]Världen![/]"), Text.Empty);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -12,7 +12,7 @@ namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("[yellow]Hello[/]", "[93mHello[0m")]
|
||||
[InlineData("[yellow]Hello [italic]World[/]![/]", "[93mHello[0m[93m [0m[3;93mWorld[0m[93m![0m")]
|
||||
[InlineData("[yellow]Hello [italic]World[/]![/]", "[93mHello [0m[3;93mWorld[0m[93m![0m")]
|
||||
public void Should_Output_Expected_Ansi_For_Markup(string markup, string expected)
|
||||
{
|
||||
// Given
|
||||
@@ -26,7 +26,7 @@ namespace Spectre.Console.Tests.Unit
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("[yellow]Hello [[ World[/]", "[93mHello[0m[93m [0m[93m[[0m[93m [0m[93mWorld[0m")]
|
||||
[InlineData("[yellow]Hello [[ World[/]", "[93mHello [ World[0m")]
|
||||
public void Should_Be_Able_To_Escape_Tags(string markup, string expected)
|
||||
{
|
||||
// Given
|
||||
|
||||
46
src/Spectre.Console.Tests/Unit/ColumnsTests.cs
Normal file
46
src/Spectre.Console.Tests/Unit/ColumnsTests.cs
Normal 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("╰────────────────────╯ ╰────────────────╯ ╰─────────────────╯");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]
|
||||
|
||||
@@ -40,6 +40,108 @@ namespace Spectre.Console.Tests.Unit
|
||||
console.Lines[2].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 Header("Greeting"),
|
||||
Expand = true,
|
||||
Padding = new Padding(2, 2),
|
||||
});
|
||||
|
||||
// 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_Left_Aligned_Header()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
|
||||
// When
|
||||
console.Render(new Panel("Hello World")
|
||||
{
|
||||
Header = new Header("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 Header("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 Header("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 Header("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]
|
||||
public void Should_Render_Panel_With_Unicode_Correctly()
|
||||
{
|
||||
|
||||
@@ -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() { BorderKind = BorderKind.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,
|
||||
BorderKind = BorderKind.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 { BorderKind = BorderKind.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 { BorderKind = BorderKind.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 { BorderKind = BorderKind.None };
|
||||
table.AddColumns("Foo", "Bar", "Baz");
|
||||
table.AddRow("Qux", "Corgi", "Waldo");
|
||||
table.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
@@ -65,6 +65,21 @@ namespace Spectre.Console.Tests.Unit
|
||||
fixture.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]
|
||||
[InlineData(5, "Hello World", "Hello\nWorld")]
|
||||
[InlineData(10, "Hello Sweet Nice World", "Hello \nSweet Nice\nWorld")]
|
||||
@@ -83,5 +98,25 @@ namespace Spectre.Console.Tests.Unit
|
||||
.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 fixture = new PlainConsole(14);
|
||||
var text = new Text("foo pneumonoultramicroscopicsilicovolcanoconiosis bar qux")
|
||||
.SetOverflow(overflow);
|
||||
|
||||
// When
|
||||
fixture.Render(text);
|
||||
|
||||
// Then
|
||||
fixture.Output
|
||||
.NormalizeLineEndings()
|
||||
.ShouldBe(expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grid", "..\examples\Grid\Gr
|
||||
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}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Columns", "..\examples\Columns\Columns.csproj", "{33357599-C79D-4299-888F-634E2C3EACEF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -107,6 +111,30 @@ 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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -116,6 +144,8 @@ 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}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5729B071-67A0-48FB-8B1B-275E6822086C}
|
||||
|
||||
@@ -38,6 +38,17 @@ namespace Spectre.Console
|
||||
LegacyConsole = legacyConsole;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the current capabilities supports
|
||||
/// the specified color system.
|
||||
/// </summary>
|
||||
/// <param name="colorSystem">The color system to check.</param>
|
||||
/// <returns><c>true</c> if the color system is supported, otherwise <c>false</c>.</returns>
|
||||
public bool Supports(ColorSystem colorSystem)
|
||||
{
|
||||
return (int)colorSystem <= (int)ColorSystem;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
@@ -30,8 +31,11 @@ namespace Spectre.Console
|
||||
|
||||
using (console.PushStyle(Style.Plain))
|
||||
{
|
||||
var segments = renderable.Render(options, console.Width).Where(x => !(x.Text.Length == 0 && !x.IsLineBreak)).ToArray();
|
||||
segments = Segment.Merge(segments).ToArray();
|
||||
|
||||
var current = Style.Plain;
|
||||
foreach (var segment in renderable.Render(options, console.Width))
|
||||
foreach (var segment in segments)
|
||||
{
|
||||
if (string.IsNullOrEmpty(segment.Text))
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Spectre.Console.Internal
|
||||
{
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
return System.Console.BufferWidth;
|
||||
return ConsoleHelper.GetSafeBufferWidth(Constants.DefaultBufferWidth);
|
||||
}
|
||||
|
||||
return Constants.DefaultBufferWidth;
|
||||
@@ -34,7 +34,7 @@ namespace Spectre.Console.Internal
|
||||
{
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
return System.Console.BufferHeight;
|
||||
return ConsoleHelper.GetSafeBufferHeight(Constants.DefaultBufferHeight);
|
||||
}
|
||||
|
||||
return Constants.DefaultBufferHeight;
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class ConsoleExtensions
|
||||
internal static class AnsiConsoleExtensions
|
||||
{
|
||||
public static IDisposable PushStyle(this IAnsiConsole console, Style style)
|
||||
{
|
||||
@@ -24,7 +24,7 @@ namespace Spectre.Console.Internal
|
||||
{
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
return System.Console.BufferWidth;
|
||||
return ConsoleHelper.GetSafeBufferWidth(Constants.DefaultBufferWidth);
|
||||
}
|
||||
|
||||
return Constants.DefaultBufferWidth;
|
||||
@@ -37,7 +37,7 @@ namespace Spectre.Console.Internal
|
||||
{
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
return System.Console.BufferHeight;
|
||||
return ConsoleHelper.GetSafeBufferHeight(Constants.DefaultBufferHeight);
|
||||
}
|
||||
|
||||
return Constants.DefaultBufferHeight;
|
||||
|
||||
43
src/Spectre.Console/Internal/Utilities/ConsoleHelper.cs
Normal file
43
src/Spectre.Console/Internal/Utilities/ConsoleHelper.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class ConsoleHelper
|
||||
{
|
||||
public static int GetSafeBufferWidth(int defaultValue = Constants.DefaultBufferWidth)
|
||||
{
|
||||
try
|
||||
{
|
||||
var width = System.Console.BufferWidth;
|
||||
if (width == 0)
|
||||
{
|
||||
width = defaultValue;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetSafeBufferHeight(int defaultValue = Constants.DefaultBufferWidth)
|
||||
{
|
||||
try
|
||||
{
|
||||
var height = System.Console.BufferHeight;
|
||||
if (height == 0)
|
||||
{
|
||||
height = defaultValue;
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
141
src/Spectre.Console/Rendering/Columns.cs
Normal file
141
src/Spectre.Console/Rendering/Columns.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders things in columns.
|
||||
/// </summary>
|
||||
public sealed class Columns : Renderable, IPaddable, IExpandable
|
||||
{
|
||||
private readonly List<IRenderable> _items;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Padding Padding { get; set; } = new Padding(0, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not the columns should
|
||||
/// expand to the available space. If <c>false</c>, the column
|
||||
/// width will be auto calculated. Defaults to <c>true</c>.
|
||||
/// </summary>
|
||||
public bool Expand { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Columns"/> class.
|
||||
/// </summary>
|
||||
/// <param name="items">The items to render.</param>
|
||||
public Columns(IEnumerable<IRenderable> items)
|
||||
{
|
||||
if (items is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(items));
|
||||
}
|
||||
|
||||
_items = new List<IRenderable>(items);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Columns"/> class.
|
||||
/// </summary>
|
||||
/// <param name="items">The items to render.</param>
|
||||
public Columns(IEnumerable<string> items)
|
||||
{
|
||||
if (items is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(items));
|
||||
}
|
||||
|
||||
_items = new List<IRenderable>(items.Select(item => new Markup(item)));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||
{
|
||||
var maxPadding = Math.Max(Padding.Left, Padding.Right);
|
||||
|
||||
var itemWidths = _items.Select(item => item.Measure(context, maxWidth).Max).ToArray();
|
||||
var columnCount = CalculateColumnCount(maxWidth, itemWidths, _items.Count, maxPadding);
|
||||
|
||||
var table = new Table();
|
||||
table.NoBorder();
|
||||
table.HideHeaders();
|
||||
table.PadRightCell = false;
|
||||
|
||||
if (Expand)
|
||||
{
|
||||
table.Expand();
|
||||
}
|
||||
|
||||
// Add columns
|
||||
for (var index = 0; index < columnCount; index++)
|
||||
{
|
||||
table.AddColumn(new TableColumn(string.Empty)
|
||||
{
|
||||
Padding = Padding,
|
||||
NoWrap = true,
|
||||
});
|
||||
}
|
||||
|
||||
// Add rows
|
||||
for (var start = 0; start < _items.Count; start += columnCount)
|
||||
{
|
||||
table.AddRow(_items.Skip(start).Take(columnCount).ToArray());
|
||||
}
|
||||
|
||||
return ((IRenderable)table).Render(context, maxWidth);
|
||||
}
|
||||
|
||||
// Algorithm borrowed from https://github.com/willmcgugan/rich/blob/master/rich/columns.py
|
||||
private int CalculateColumnCount(int maxWidth, int[] itemWidths, int columnCount, int padding)
|
||||
{
|
||||
var widths = new Dictionary<int, int>();
|
||||
while (columnCount > 1)
|
||||
{
|
||||
var columnIndex = 0;
|
||||
widths.Clear();
|
||||
|
||||
var exceededTotalWidth = false;
|
||||
foreach (var renderableWidth in IterateWidths(itemWidths, columnCount))
|
||||
{
|
||||
widths[columnIndex] = Math.Max(widths.ContainsKey(columnIndex) ? widths[columnIndex] : 0, renderableWidth);
|
||||
var totalWidth = widths.Values.Sum() + (padding * (widths.Count - 1));
|
||||
if (totalWidth > maxWidth)
|
||||
{
|
||||
columnCount = widths.Count - 1;
|
||||
exceededTotalWidth = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
columnIndex = (columnIndex + 1) % columnCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exceededTotalWidth)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return columnCount;
|
||||
}
|
||||
|
||||
private IEnumerable<int> IterateWidths(int[] itemWidths, int columnCount)
|
||||
{
|
||||
foreach (var width in itemWidths)
|
||||
{
|
||||
yield return width;
|
||||
}
|
||||
|
||||
if (_items.Count % columnCount != 0)
|
||||
{
|
||||
for (var i = 0; i < columnCount - (_items.Count % columnCount) - 1; i++)
|
||||
{
|
||||
yield return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
@@ -9,10 +7,27 @@ namespace Spectre.Console
|
||||
/// <summary>
|
||||
/// A renderable grid.
|
||||
/// </summary>
|
||||
public sealed class Grid : Renderable
|
||||
public sealed class Grid : Renderable, IExpandable
|
||||
{
|
||||
private readonly Table _table;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of columns in the table.
|
||||
/// </summary>
|
||||
public int ColumnCount => _table.ColumnCount;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of rows in the table.
|
||||
/// </summary>
|
||||
public int RowCount => _table.RowCount;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Expand
|
||||
{
|
||||
get => _table.Expand;
|
||||
set => _table.Expand = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Grid"/> class.
|
||||
/// </summary>
|
||||
@@ -20,7 +35,7 @@ namespace Spectre.Console
|
||||
{
|
||||
_table = new Table
|
||||
{
|
||||
Border = BorderKind.None,
|
||||
BorderKind = BorderKind.None,
|
||||
ShowHeaders = false,
|
||||
IsGrid = true,
|
||||
PadRightCell = false,
|
||||
@@ -75,45 +90,6 @@ namespace Spectre.Console
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a column to the grid.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of columns to add.</param>
|
||||
public void AddColumns(int count)
|
||||
{
|
||||
for (var index = 0; index < count; index++)
|
||||
{
|
||||
AddColumn(new GridColumn());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a column to the grid.
|
||||
/// </summary>
|
||||
/// <param name="columns">The columns to add.</param>
|
||||
public void AddColumns(params GridColumn[] columns)
|
||||
{
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
foreach (var column in columns)
|
||||
{
|
||||
AddColumn(column);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an empty row to the grid.
|
||||
/// </summary>
|
||||
public void AddEmptyRow()
|
||||
{
|
||||
var columns = new IRenderable[_table.ColumnCount];
|
||||
Enumerable.Range(0, _table.ColumnCount).ForEach(index => columns[index] = Text.Empty);
|
||||
AddRow(columns);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new row to the grid.
|
||||
/// </summary>
|
||||
@@ -125,11 +101,6 @@ namespace Spectre.Console
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
if (columns.Length < _table.ColumnCount)
|
||||
{
|
||||
throw new InvalidOperationException("The number of row columns are less than the number of grid columns.");
|
||||
}
|
||||
|
||||
if (columns.Length > _table.ColumnCount)
|
||||
{
|
||||
throw new InvalidOperationException("The number of row columns are greater than the number of grid columns.");
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
@@ -8,6 +10,63 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
public static class GridExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a column to the grid.
|
||||
/// </summary>
|
||||
/// <param name="grid">The grid to add the column to.</param>
|
||||
/// <param name="count">The number of columns to add.</param>
|
||||
public static void AddColumns(this Grid grid, int count)
|
||||
{
|
||||
if (grid is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(grid));
|
||||
}
|
||||
|
||||
for (var index = 0; index < count; index++)
|
||||
{
|
||||
grid.AddColumn(new GridColumn());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a column to the grid.
|
||||
/// </summary>
|
||||
/// <param name="grid">The grid to add the column to.</param>
|
||||
/// <param name="columns">The columns to add.</param>
|
||||
public static void AddColumns(this Grid grid, params GridColumn[] columns)
|
||||
{
|
||||
if (grid is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(grid));
|
||||
}
|
||||
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
foreach (var column in columns)
|
||||
{
|
||||
grid.AddColumn(column);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an empty row to the grid.
|
||||
/// </summary>
|
||||
/// <param name="grid">The grid to add the row to.</param>
|
||||
public static void AddEmptyRow(this Grid grid)
|
||||
{
|
||||
if (grid is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(grid));
|
||||
}
|
||||
|
||||
var columns = new IRenderable[grid.ColumnCount];
|
||||
Enumerable.Range(0, grid.ColumnCount).ForEach(index => columns[index] = Text.Empty);
|
||||
grid.AddRow(columns);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new row to the grid.
|
||||
/// </summary>
|
||||
|
||||
60
src/Spectre.Console/Rendering/Header.cs
Normal file
60
src/Spectre.Console/Rendering/Header.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a header.
|
||||
/// </summary>
|
||||
public sealed class Header : IAlignable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the header text.
|
||||
/// </summary>
|
||||
public string Text { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the header style.
|
||||
/// </summary>
|
||||
public Style? Style { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the header alignment.
|
||||
/// </summary>
|
||||
public Justify? Alignment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Header"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The header text.</param>
|
||||
/// <param name="style">The header style.</param>
|
||||
/// <param name="alignment">The header alignment.</param>
|
||||
public Header(string text, Style? style = null, Justify? alignment = null)
|
||||
{
|
||||
Text = text ?? throw new ArgumentNullException(nameof(text));
|
||||
Style = style;
|
||||
Alignment = alignment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the header style.
|
||||
/// </summary>
|
||||
/// <param name="style">The header style.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public Header SetStyle(Style? style)
|
||||
{
|
||||
Style = style ?? Style.Plain;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the header alignment.
|
||||
/// </summary>
|
||||
/// <param name="alignment">The header alignment.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public Header SetAlignment(Justify alignment)
|
||||
{
|
||||
Alignment = alignment;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace Spectre.Console
|
||||
/// <summary>
|
||||
/// A renderable piece of markup text.
|
||||
/// </summary>
|
||||
public sealed class Markup : Renderable, IAlignable
|
||||
public sealed class Markup : Renderable, IAlignable, IOverflowable
|
||||
{
|
||||
private readonly Paragraph _paragraph;
|
||||
|
||||
@@ -18,6 +18,13 @@ namespace Spectre.Console
|
||||
set => _paragraph.Alignment = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Overflow? Overflow
|
||||
{
|
||||
get => _paragraph.Overflow;
|
||||
set => _paragraph.Overflow = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Markup"/> class.
|
||||
/// </summary>
|
||||
|
||||
24
src/Spectre.Console/Rendering/Overflow.cs
Normal file
24
src/Spectre.Console/Rendering/Overflow.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents text overflow.
|
||||
/// </summary>
|
||||
public enum Overflow
|
||||
{
|
||||
/// <summary>
|
||||
/// Put any excess characters on the next line.
|
||||
/// </summary>
|
||||
Fold = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Truncates the text at the end of the line.
|
||||
/// </summary>
|
||||
Crop = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Truncates the text at the end of the line and
|
||||
/// also inserts an ellipsis character.
|
||||
/// </summary>
|
||||
Ellipsis = 2,
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Rendering;
|
||||
@@ -15,13 +16,13 @@ namespace Spectre.Console
|
||||
private readonly IRenderable _child;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public BorderKind Border { get; set; } = BorderKind.Square;
|
||||
public BorderKind BorderKind { get; set; } = BorderKind.Square;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool SafeBorder { get; set; } = true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Color? BorderColor { get; set; }
|
||||
public Style? BorderStyle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not the panel should
|
||||
@@ -35,6 +36,11 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
public Padding Padding { get; set; } = new Padding(1, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the header.
|
||||
/// </summary>
|
||||
public Header? Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Panel"/> class.
|
||||
/// </summary>
|
||||
@@ -58,15 +64,15 @@ namespace Spectre.Console
|
||||
{
|
||||
var childWidth = _child.Measure(context, maxWidth);
|
||||
return new Measurement(
|
||||
childWidth.Min + 2 + Padding.GetHorizontalPadding(),
|
||||
childWidth.Max + 2 + Padding.GetHorizontalPadding());
|
||||
childWidth.Min + EdgeWidth + Padding.GetHorizontalPadding(),
|
||||
childWidth.Max + EdgeWidth + Padding.GetHorizontalPadding());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||
{
|
||||
var border = SpectreBorder.GetBorder(Border, (context.LegacyConsole || !context.Unicode) && SafeBorder);
|
||||
var borderStyle = new Style(BorderColor, null, null);
|
||||
var border = SpectreBorder.GetBorder(BorderKind, (context.LegacyConsole || !context.Unicode) && SafeBorder);
|
||||
var borderStyle = BorderStyle ?? Style.Plain;
|
||||
|
||||
var paddingWidth = Padding.GetHorizontalPadding();
|
||||
var childWidth = maxWidth - EdgeWidth - paddingWidth;
|
||||
@@ -77,21 +83,16 @@ namespace Spectre.Console
|
||||
childWidth = measurement.Max;
|
||||
}
|
||||
|
||||
var panelWidth = childWidth + paddingWidth;
|
||||
var panelWidth = childWidth + EdgeWidth + paddingWidth;
|
||||
panelWidth = Math.Min(panelWidth, maxWidth);
|
||||
|
||||
var result = new List<Segment>();
|
||||
|
||||
// Panel top
|
||||
var result = new List<Segment>
|
||||
{
|
||||
new Segment(border.GetPart(BorderPart.HeaderTopLeft), borderStyle),
|
||||
new Segment(border.GetPart(BorderPart.HeaderTop, panelWidth), borderStyle),
|
||||
new Segment(border.GetPart(BorderPart.HeaderTopRight), borderStyle),
|
||||
Segment.LineBreak,
|
||||
};
|
||||
|
||||
// Render the child.
|
||||
var childSegments = _child.Render(context, childWidth);
|
||||
AddTopBorder(result, context, border, borderStyle, panelWidth);
|
||||
|
||||
// Split the child segments into lines.
|
||||
var childSegments = _child.Render(context, childWidth);
|
||||
foreach (var line in Segment.SplitLines(childSegments, panelWidth))
|
||||
{
|
||||
result.Add(new Segment(border.GetPart(BorderPart.CellLeft), borderStyle));
|
||||
@@ -126,12 +127,62 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
// Panel bottom
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottomLeft), borderStyle));
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottom, panelWidth), borderStyle));
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottomRight), borderStyle));
|
||||
result.Add(Segment.LineBreak);
|
||||
AddBottomBorder(result, border, borderStyle, panelWidth);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void AddBottomBorder(List<Segment> result, SpectreBorder border, Style borderStyle, int panelWidth)
|
||||
{
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottomLeft), borderStyle));
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottom, panelWidth - EdgeWidth), borderStyle));
|
||||
result.Add(new Segment(border.GetPart(BorderPart.FooterBottomRight), borderStyle));
|
||||
result.Add(Segment.LineBreak);
|
||||
}
|
||||
|
||||
private void AddTopBorder(List<Segment> segments, RenderContext context, SpectreBorder border, Style borderStyle, int panelWidth)
|
||||
{
|
||||
segments.Add(new Segment(border.GetPart(BorderPart.HeaderTopLeft), borderStyle));
|
||||
|
||||
if (Header != null)
|
||||
{
|
||||
var leftSpacing = 0;
|
||||
var rightSpacing = 0;
|
||||
|
||||
var headerWidth = panelWidth - (EdgeWidth * 2);
|
||||
var header = Segment.TruncateWithEllipsis(Header.Text, Header.Style ?? borderStyle, context.Encoding, headerWidth);
|
||||
|
||||
var excessWidth = headerWidth - header.CellLength(context.Encoding);
|
||||
if (excessWidth > 0)
|
||||
{
|
||||
switch (Header.Alignment ?? Justify.Left)
|
||||
{
|
||||
case Justify.Left:
|
||||
leftSpacing = 0;
|
||||
rightSpacing = excessWidth;
|
||||
break;
|
||||
case Justify.Right:
|
||||
leftSpacing = excessWidth;
|
||||
rightSpacing = 0;
|
||||
break;
|
||||
case Justify.Center:
|
||||
leftSpacing = excessWidth / 2;
|
||||
rightSpacing = (excessWidth / 2) + (excessWidth % 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
segments.Add(new Segment(border.GetPart(BorderPart.HeaderTop, leftSpacing + 1), borderStyle));
|
||||
segments.Add(header);
|
||||
segments.Add(new Segment(border.GetPart(BorderPart.HeaderTop, rightSpacing + 1), borderStyle));
|
||||
}
|
||||
else
|
||||
{
|
||||
segments.Add(new Segment(border.GetPart(BorderPart.HeaderTop, panelWidth - EdgeWidth), borderStyle));
|
||||
}
|
||||
|
||||
segments.Add(new Segment(border.GetPart(BorderPart.HeaderTopRight), borderStyle));
|
||||
segments.Add(Segment.LineBreak);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
50
src/Spectre.Console/Rendering/PanelExtensions.cs
Normal file
50
src/Spectre.Console/Rendering/PanelExtensions.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="Panel"/>.
|
||||
/// </summary>
|
||||
public static class PanelExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the panel header.
|
||||
/// </summary>
|
||||
/// <param name="panel">The panel.</param>
|
||||
/// <param name="text">The header text.</param>
|
||||
/// <param name="style">The header style.</param>
|
||||
/// <param name="alignment">The header alignment.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Panel SetHeader(this Panel panel, string text, Style? style = null, Justify? alignment = null)
|
||||
{
|
||||
if (panel is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(panel));
|
||||
}
|
||||
|
||||
if (text is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(text));
|
||||
}
|
||||
|
||||
return SetHeader(panel, new Header(text, style, alignment));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the panel header.
|
||||
/// </summary>
|
||||
/// <param name="panel">The panel.</param>
|
||||
/// <param name="header">The header to use.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Panel SetHeader(this Panel panel, Header header)
|
||||
{
|
||||
if (panel is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(panel));
|
||||
}
|
||||
|
||||
panel.Header = header;
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
@@ -12,7 +12,7 @@ namespace Spectre.Console
|
||||
/// of the paragraph can have individual styling.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{_text,nq}")]
|
||||
public sealed class Paragraph : Renderable, IAlignable
|
||||
public sealed class Paragraph : Renderable, IAlignable, IOverflowable
|
||||
{
|
||||
private readonly List<SegmentLine> _lines;
|
||||
|
||||
@@ -21,6 +21,11 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
public Justify? Alignment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text overflow strategy.
|
||||
/// </summary>
|
||||
public Overflow? Overflow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Paragraph"/> class.
|
||||
/// </summary>
|
||||
@@ -117,7 +122,7 @@ namespace Spectre.Console
|
||||
var min = _lines.Max(line => line.Max(segment => segment.CellLength(context.Encoding)));
|
||||
var max = _lines.Max(x => x.CellWidth(context.Encoding));
|
||||
|
||||
return new Measurement(min, max);
|
||||
return new Measurement(min, Math.Min(max, maxWidth));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -197,34 +202,76 @@ namespace Spectre.Console
|
||||
var line = new SegmentLine();
|
||||
|
||||
var newLine = true;
|
||||
using (var iterator = new SegmentLineIterator(_lines))
|
||||
|
||||
using var iterator = new SegmentLineIterator(_lines);
|
||||
var queue = new Queue<Segment>();
|
||||
while (true)
|
||||
{
|
||||
while (iterator.MoveNext())
|
||||
var current = (Segment?)null;
|
||||
if (queue.Count == 0)
|
||||
{
|
||||
var current = iterator.Current;
|
||||
if (current == null)
|
||||
if (!iterator.MoveNext())
|
||||
{
|
||||
throw new InvalidOperationException("Iterator returned empty segment.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (newLine && current.IsWhiteSpace && !current.IsLineBreak)
|
||||
{
|
||||
newLine = false;
|
||||
continue;
|
||||
}
|
||||
current = iterator.Current;
|
||||
}
|
||||
else
|
||||
{
|
||||
current = queue.Dequeue();
|
||||
}
|
||||
|
||||
if (current == null)
|
||||
{
|
||||
throw new InvalidOperationException("Iterator returned empty segment.");
|
||||
}
|
||||
|
||||
if (newLine && current.IsWhiteSpace && !current.IsLineBreak)
|
||||
{
|
||||
newLine = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current.IsLineBreak)
|
||||
newLine = false;
|
||||
|
||||
if (current.IsLineBreak)
|
||||
{
|
||||
line.Add(current);
|
||||
lines.Add(line);
|
||||
line = new SegmentLine();
|
||||
newLine = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
var length = current.CellLength(context.Encoding);
|
||||
if (length > maxWidth)
|
||||
{
|
||||
// The current segment is longer than the width of the console,
|
||||
// so we will need to crop it up, into new segments.
|
||||
var segments = Segment.SplitOverflow(current, Overflow, context.Encoding, maxWidth);
|
||||
if (segments.Count > 0)
|
||||
{
|
||||
line.Add(current);
|
||||
lines.Add(line);
|
||||
line = new SegmentLine();
|
||||
newLine = true;
|
||||
continue;
|
||||
}
|
||||
if (line.CellWidth(context.Encoding) + segments[0].CellLength(context.Encoding) > maxWidth)
|
||||
{
|
||||
lines.Add(line);
|
||||
line = new SegmentLine();
|
||||
newLine = true;
|
||||
|
||||
var length = current.CellLength(context.Encoding);
|
||||
segments.ForEach(s => queue.Enqueue(s));
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the segment and push the rest of them to the queue.
|
||||
line.Add(segments[0]);
|
||||
segments.Skip(1).ForEach(s => queue.Enqueue(s));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (line.CellWidth(context.Encoding) + length > maxWidth)
|
||||
{
|
||||
line.Add(Segment.Empty);
|
||||
@@ -232,16 +279,16 @@ namespace Spectre.Console
|
||||
line = new SegmentLine();
|
||||
newLine = true;
|
||||
}
|
||||
|
||||
if (newLine && current.IsWhiteSpace)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
newLine = false;
|
||||
|
||||
line.Add(current);
|
||||
}
|
||||
|
||||
if (newLine && current.IsWhiteSpace)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
newLine = false;
|
||||
|
||||
line.Add(current);
|
||||
}
|
||||
|
||||
// Flush remaining.
|
||||
|
||||
@@ -13,10 +13,25 @@ namespace Spectre.Console.Rendering
|
||||
[DebuggerDisplay("{Text,nq}")]
|
||||
public class Segment
|
||||
{
|
||||
private readonly bool _mutable;
|
||||
private string _text;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the segment text.
|
||||
/// </summary>
|
||||
public string Text { get; }
|
||||
public string Text
|
||||
{
|
||||
get => _text;
|
||||
private set
|
||||
{
|
||||
if (!_mutable)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
_text = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not this is an expicit line break
|
||||
@@ -39,12 +54,12 @@ namespace Spectre.Console.Rendering
|
||||
/// <summary>
|
||||
/// Gets a segment representing a line break.
|
||||
/// </summary>
|
||||
public static Segment LineBreak { get; } = new Segment(Environment.NewLine, Style.Plain, true);
|
||||
public static Segment LineBreak { get; } = new Segment(Environment.NewLine, Style.Plain, true, false);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an empty segment.
|
||||
/// </summary>
|
||||
public static Segment Empty { get; } = new Segment(string.Empty, Style.Plain);
|
||||
public static Segment Empty { get; } = new Segment(string.Empty, Style.Plain, false, false);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Segment"/> class.
|
||||
@@ -65,14 +80,16 @@ namespace Spectre.Console.Rendering
|
||||
{
|
||||
}
|
||||
|
||||
private Segment(string text, Style style, bool lineBreak)
|
||||
private Segment(string text, Style style, bool lineBreak, bool mutable = true)
|
||||
{
|
||||
if (text is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(text));
|
||||
}
|
||||
|
||||
Text = text.NormalizeLineEndings();
|
||||
_mutable = mutable;
|
||||
_text = text.NormalizeLineEndings();
|
||||
|
||||
Style = style;
|
||||
IsLineBreak = lineBreak;
|
||||
IsWhiteSpace = string.IsNullOrWhiteSpace(text);
|
||||
@@ -226,6 +243,100 @@ namespace Spectre.Console.Rendering
|
||||
return lines;
|
||||
}
|
||||
|
||||
internal static IEnumerable<Segment> Merge(IEnumerable<Segment> segments)
|
||||
{
|
||||
var result = new List<Segment>();
|
||||
|
||||
var previous = (Segment?)null;
|
||||
foreach (var segment in segments)
|
||||
{
|
||||
if (previous == null)
|
||||
{
|
||||
previous = segment;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Same style?
|
||||
if (previous.Style.Equals(segment.Style))
|
||||
{
|
||||
// Modify the content of the previous segment
|
||||
previous.Text += segment.Text;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Push the current one to the results.
|
||||
result.Add(previous);
|
||||
previous = segment;
|
||||
}
|
||||
}
|
||||
|
||||
if (previous != null)
|
||||
{
|
||||
result.Add(previous);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits an overflowing segment into several new segments.
|
||||
/// </summary>
|
||||
/// <param name="segment">The segment to split.</param>
|
||||
/// <param name="overflow">The overflow strategy to use.</param>
|
||||
/// <param name="encoding">The encodign to use.</param>
|
||||
/// <param name="width">The maxiumum width.</param>
|
||||
/// <returns>A list of segments that has been split.</returns>
|
||||
public static List<Segment> SplitOverflow(Segment segment, Overflow? overflow, Encoding encoding, int width)
|
||||
{
|
||||
if (segment is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(segment));
|
||||
}
|
||||
|
||||
if (segment.CellLength(encoding) <= width)
|
||||
{
|
||||
return new List<Segment>(1) { segment };
|
||||
}
|
||||
|
||||
// Default to folding
|
||||
overflow ??= Overflow.Fold;
|
||||
|
||||
var result = new List<Segment>();
|
||||
|
||||
if (overflow == Overflow.Fold)
|
||||
{
|
||||
var totalLength = segment.Text.CellLength(encoding);
|
||||
var lengthLeft = totalLength;
|
||||
while (lengthLeft > 0)
|
||||
{
|
||||
var index = totalLength - lengthLeft;
|
||||
var take = Math.Min(width, totalLength - index);
|
||||
|
||||
result.Add(new Segment(segment.Text.Substring(index, take), segment.Style));
|
||||
lengthLeft -= take;
|
||||
}
|
||||
}
|
||||
else if (overflow == Overflow.Crop)
|
||||
{
|
||||
result.Add(new Segment(segment.Text.Substring(0, width), segment.Style));
|
||||
}
|
||||
else if (overflow == Overflow.Ellipsis)
|
||||
{
|
||||
result.Add(new Segment(segment.Text.Substring(0, width - 1) + "…", segment.Style));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static Segment TruncateWithEllipsis(string text, Style style, Encoding encoding, int maxWidth)
|
||||
{
|
||||
return SplitOverflow(
|
||||
new Segment(text, style),
|
||||
Overflow.Ellipsis,
|
||||
encoding,
|
||||
maxWidth).First();
|
||||
}
|
||||
|
||||
internal static List<List<SegmentLine>> MakeSameHeight(int cellHeight, List<List<SegmentLine>> cells)
|
||||
{
|
||||
foreach (var cell in cells)
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Spectre.Console
|
||||
// https://github.com/willmcgugan/rich/blob/527475837ebbfc427530b3ee0d4d0741d2d0fc6d/rich/table.py#L394
|
||||
private List<int> CalculateColumnWidths(RenderContext options, int maxWidth)
|
||||
{
|
||||
var width_ranges = _columns.Select(column => MeasureColumn(column, options, maxWidth));
|
||||
var width_ranges = _columns.Select(column => MeasureColumn(column, options, maxWidth)).ToArray();
|
||||
var widths = width_ranges.Select(range => range.Max).ToList();
|
||||
|
||||
var tableWidth = widths.Sum();
|
||||
@@ -117,9 +117,17 @@ namespace Spectre.Console
|
||||
|
||||
private int GetExtraWidth(bool includePadding)
|
||||
{
|
||||
var separators = _columns.Count - 1;
|
||||
var hideBorder = BorderKind == BorderKind.None;
|
||||
var separators = hideBorder ? 0 : _columns.Count - 1;
|
||||
var edges = hideBorder ? 0 : EdgeCount;
|
||||
var padding = includePadding ? _columns.Select(x => x.Padding.GetHorizontalPadding()).Sum() : 0;
|
||||
return separators + EdgeCount + padding;
|
||||
|
||||
if (!PadRightCell)
|
||||
{
|
||||
padding -= _columns.Last().Padding.Right;
|
||||
}
|
||||
|
||||
return separators + edges + padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ namespace Spectre.Console
|
||||
public int RowCount => _rows.Count;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public BorderKind Border { get; set; } = BorderKind.Square;
|
||||
public BorderKind BorderKind { get; set; } = BorderKind.Square;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Color? BorderColor { get; set; }
|
||||
public Style? BorderStyle { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool SafeBorder { get; set; } = true;
|
||||
@@ -125,17 +125,19 @@ namespace Spectre.Console
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
if (columns.Length < _columns.Count)
|
||||
{
|
||||
throw new InvalidOperationException("The number of row columns are less than the number of table columns.");
|
||||
}
|
||||
|
||||
if (columns.Length > _columns.Count)
|
||||
{
|
||||
throw new InvalidOperationException("The number of row columns are greater than the number of table columns.");
|
||||
}
|
||||
|
||||
_rows.Add(columns.ToList());
|
||||
|
||||
// Need to add missing columns?
|
||||
if (columns.Length < _columns.Count)
|
||||
{
|
||||
var diff = _columns.Count - columns.Length;
|
||||
Enumerable.Range(0, diff).ForEach(_ => _rows.Last().Add(Text.Empty));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -168,13 +170,13 @@ namespace Spectre.Console
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var border = SpectreBorder.GetBorder(Border, (context.LegacyConsole || !context.Unicode) && SafeBorder);
|
||||
var borderStyle = new Style(BorderColor, null, null);
|
||||
var border = SpectreBorder.GetBorder(BorderKind, (context.LegacyConsole || !context.Unicode) && SafeBorder);
|
||||
var borderStyle = BorderStyle ?? Style.Plain;
|
||||
|
||||
var tableWidth = maxWidth;
|
||||
|
||||
var showBorder = Border != BorderKind.None;
|
||||
var hideBorder = Border == BorderKind.None;
|
||||
var showBorder = BorderKind != BorderKind.None;
|
||||
var hideBorder = BorderKind == BorderKind.None;
|
||||
var hasRows = _rows.Count > 0;
|
||||
|
||||
if (Width != null)
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{_text,nq}")]
|
||||
[SuppressMessage("Naming", "CA1724:Type names should not match namespaces")]
|
||||
public sealed class Text : Renderable, IAlignable
|
||||
public sealed class Text : Renderable, IAlignable, IOverflowable
|
||||
{
|
||||
private readonly Paragraph _paragraph;
|
||||
|
||||
@@ -38,6 +38,15 @@ namespace Spectre.Console
|
||||
set => _paragraph.Alignment = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text overflow strategy.
|
||||
/// </summary>
|
||||
public Overflow? Overflow
|
||||
{
|
||||
get => _paragraph.Overflow;
|
||||
set => _paragraph.Overflow = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Rendering
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IHasBorder"/>.
|
||||
@@ -8,13 +8,61 @@ namespace Spectre.Console.Rendering
|
||||
public static class BorderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the border.
|
||||
/// Do not display a border.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The object that has a border.</typeparam>
|
||||
/// <typeparam name="T">An object type with a border.</typeparam>
|
||||
/// <param name="obj">The object to set the border for.</param>
|
||||
/// <param name="border">The border to use.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T SetBorder<T>(this T obj, BorderKind border)
|
||||
public static T NoBorder<T>(this T obj)
|
||||
where T : class, IHasBorder
|
||||
{
|
||||
return SetBorderKind(obj, BorderKind.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display a square border.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object type with a border.</typeparam>
|
||||
/// <param name="obj">The object to set the border for.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T SquareBorder<T>(this T obj)
|
||||
where T : class, IHasBorder
|
||||
{
|
||||
return SetBorderKind(obj, BorderKind.Square);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display an ASCII border.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object type with a border.</typeparam>
|
||||
/// <param name="obj">The object to set the border for.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T AsciiBorder<T>(this T obj)
|
||||
where T : class, IHasBorder
|
||||
{
|
||||
return SetBorderKind(obj, BorderKind.Ascii);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display a rounded border.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object type with a border.</typeparam>
|
||||
/// <param name="obj">The object to set the border for.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T RoundedBorder<T>(this T obj)
|
||||
where T : class, IHasBorder
|
||||
{
|
||||
return SetBorderKind(obj, BorderKind.Rounded);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the border kind.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object type with a border.</typeparam>
|
||||
/// <param name="obj">The object to set the border for.</param>
|
||||
/// <param name="border">The border kind to use.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T SetBorderKind<T>(this T obj, BorderKind border)
|
||||
where T : class, IHasBorder
|
||||
{
|
||||
if (obj is null)
|
||||
@@ -22,14 +70,14 @@ namespace Spectre.Console.Rendering
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
obj.Border = border;
|
||||
obj.BorderKind = border;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables the safe border.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The object that has a border.</typeparam>
|
||||
/// <typeparam name="T">An object type with a border.</typeparam>
|
||||
/// <param name="obj">The object to set the border for.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T NoSafeBorder<T>(this T obj)
|
||||
@@ -44,12 +92,31 @@ namespace Spectre.Console.Rendering
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the border style.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object type with a border.</typeparam>
|
||||
/// <param name="obj">The object to set the border color for.</param>
|
||||
/// <param name="style">The border style to set.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T SetBorderStyle<T>(this T obj, Style style)
|
||||
where T : class, IHasBorder
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
obj.BorderStyle = style;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the border color.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The object that has a border.</typeparam>
|
||||
/// <typeparam name="T">An object type with a border.</typeparam>
|
||||
/// <param name="obj">The object to set the border color for.</param>
|
||||
/// <param name="color">The color to set.</param>
|
||||
/// <param name="color">The border color to set.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T SetBorderColor<T>(this T obj, Color color)
|
||||
where T : class, IHasBorder
|
||||
@@ -59,7 +126,7 @@ namespace Spectre.Console.Rendering
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
obj.BorderColor = color;
|
||||
obj.BorderStyle = (obj.BorderStyle ?? Style.Plain).WithForeground(color);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Rendering
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IExpandable"/>.
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IOverflowable"/>.
|
||||
/// </summary>
|
||||
public static class OverflowableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Folds any overflowing text.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object implementing <see cref="IOverflowable"/>.</typeparam>
|
||||
/// <param name="obj">The overflowable object instance.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T Fold<T>(this T obj)
|
||||
where T : class, IOverflowable
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
return SetOverflow(obj, Overflow.Fold);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Crops any overflowing text.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object implementing <see cref="IOverflowable"/>.</typeparam>
|
||||
/// <param name="obj">The overflowable object instance.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T Crop<T>(this T obj)
|
||||
where T : class, IOverflowable
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
return SetOverflow(obj, Overflow.Crop);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Crops any overflowing text and adds an ellipsis to the end.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object implementing <see cref="IOverflowable"/>.</typeparam>
|
||||
/// <param name="obj">The overflowable object instance.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T Ellipsis<T>(this T obj)
|
||||
where T : class, IOverflowable
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
return SetOverflow(obj, Overflow.Ellipsis);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the overflow strategy.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">An object implementing <see cref="IOverflowable"/>.</typeparam>
|
||||
/// <param name="obj">The overflowable object instance.</param>
|
||||
/// <param name="overflow">The overflow strategy to use.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static T SetOverflow<T>(this T obj, Overflow overflow)
|
||||
where T : class, IOverflowable
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
}
|
||||
|
||||
obj.Overflow = overflow;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,11 @@ namespace Spectre.Console
|
||||
/// <summary>
|
||||
/// Gets or sets the kind of border to use.
|
||||
/// </summary>
|
||||
public BorderKind Border { get; set; }
|
||||
public BorderKind BorderKind { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the border color.
|
||||
/// Gets or sets the border style.
|
||||
/// </summary>
|
||||
public Color? BorderColor { get; set; }
|
||||
public Style? BorderStyle { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
13
src/Spectre.Console/Rendering/Traits/IOverflowable.cs
Normal file
13
src/Spectre.Console/Rendering/Traits/IOverflowable.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents something that can overflow.
|
||||
/// </summary>
|
||||
public interface IOverflowable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the text overflow strategy.
|
||||
/// </summary>
|
||||
Overflow? Overflow { get; set; }
|
||||
}
|
||||
}
|
||||
40
src/Spectre.Console/Style.Factory.cs
Normal file
40
src/Spectre.Console/Style.Factory.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents color and text decoration.
|
||||
/// </summary>
|
||||
public sealed partial class Style : IEquatable<Style>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new style from the specified foreground color.
|
||||
/// </summary>
|
||||
/// <param name="color">The foreground color.</param>
|
||||
/// <returns>A new <see cref="Style"/> with the specified foreground color.</returns>
|
||||
public static Style WithForeground(Color color)
|
||||
{
|
||||
return new Style(foreground: color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new style from the specified background color.
|
||||
/// </summary>
|
||||
/// <param name="color">The background color.</param>
|
||||
/// <returns>A new <see cref="Style"/> with the specified background color.</returns>
|
||||
public static Style WithBackground(Color color)
|
||||
{
|
||||
return new Style(background: color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new style from the specified text decoration.
|
||||
/// </summary>
|
||||
/// <param name="decoration">The text decoration.</param>
|
||||
/// <returns>A new <see cref="Style"/> with the specified text decoration.</returns>
|
||||
public static Style WithDecoration(Decoration decoration)
|
||||
{
|
||||
return new Style(decoration: decoration);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Spectre.Console
|
||||
/// <summary>
|
||||
/// Represents color and text decoration.
|
||||
/// </summary>
|
||||
public sealed class Style : IEquatable<Style>
|
||||
public sealed partial class Style : IEquatable<Style>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the foreground color.
|
||||
|
||||
70
src/Spectre.Console/StyleExtensions.cs
Normal file
70
src/Spectre.Console/StyleExtensions.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="Style"/>.
|
||||
/// </summary>
|
||||
public static class StyleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new style from the specified one with
|
||||
/// the specified foreground color.
|
||||
/// </summary>
|
||||
/// <param name="style">The style.</param>
|
||||
/// <param name="color">The foreground color.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Style WithForeground(this Style style, Color color)
|
||||
{
|
||||
if (style is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(style));
|
||||
}
|
||||
|
||||
return new Style(
|
||||
foreground: color,
|
||||
background: style.Background,
|
||||
decoration: style.Decoration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new style from the specified one with
|
||||
/// the specified background color.
|
||||
/// </summary>
|
||||
/// <param name="style">The style.</param>
|
||||
/// <param name="color">The background color.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Style WithBackground(this Style style, Color color)
|
||||
{
|
||||
if (style is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(style));
|
||||
}
|
||||
|
||||
return new Style(
|
||||
foreground: style.Foreground,
|
||||
background: color,
|
||||
decoration: style.Decoration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new style from the specified one with
|
||||
/// the specified text decoration.
|
||||
/// </summary>
|
||||
/// <param name="style">The style.</param>
|
||||
/// <param name="decoration">The text decoration.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Style WithDecoration(this Style style, Decoration decoration)
|
||||
{
|
||||
if (style is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(style));
|
||||
}
|
||||
|
||||
return new Style(
|
||||
foreground: style.Foreground,
|
||||
background: style.Background,
|
||||
decoration: decoration);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user