Compare commits

...

32 Commits

Author SHA1 Message Date
Patrik Svensson
03334f693d Add support for table footers 2020-10-26 00:01:13 +01:00
Patrik Svensson
c9c0ad733f Fix rendering bug when splitting lines
The bug might occur if there are wide characters such as emojis
at the end of a line. The SplitLines method mixed cell width
and text length, which might give incorrect results. This commit
makes sure that comparison and calculation is done using cell width
where it's appropriate.
2020-10-24 01:45:41 +02:00
Patrik Svensson
041bd016a2 Remove verbs from extension methods
Removed the verbs from all extension methods that manipulate
properties which makes the API more succinct and easier to read.

Also added implicit conversion from string to Style.

As a good OSS citizen, I've obsoleted the old methods with
a warning for now, so this shouldn't break anyone using
the old methods.
2020-10-23 15:08:18 +02:00
Takahito Yamatoya
037a215a78 Add documentation for rule 2020-10-22 08:53:20 +02:00
Patrik Svensson
9afc1ea721 Add support for aligning tables 2020-10-21 18:15:51 +02:00
Takahito Yamatoya
b52056ee49 Update documentation for calendar 2020-10-20 21:55:29 +02:00
Patrik Svensson
3941fd81ab Move table and calendar docs 2020-10-20 02:32:04 +02:00
Patrik Svensson
5a1b8a1710 Add rule widget
Adds a new rule widget.
Also fixes some bugs I encountered while testing
some unrelated things in an extremely small console.
2020-10-20 01:45:53 +02:00
Patrik Svensson
1410cba6c5 Add Markdown.Escape method 2020-10-20 01:09:26 +02:00
Patrik Svensson
70fc14e9cd Add new ctors for Rows and Columns widgets 2020-10-19 21:25:28 +02:00
Takahito Yamatoya
0b4359a52a Add installation instructions
* to add how to install

* fix

* remove empty line
2020-10-19 16:50:54 +02:00
Patrik Svensson
cb2924a609 Add table heading and footnote support
Closes #116
2020-10-19 15:46:57 +02:00
Takahito Yamatoya
5c119ee0c3 Add documentation for calendar 2020-10-19 15:44:16 +02:00
Takahito Yamatoya
b9d182b6e3 Add README.jp.md 2020-10-19 15:42:33 +02:00
Patrik Svensson
bfffef630f Do not draw tables that can't be drawn
This is a temporary fix for undrawable tables until we've
implemented a proper strategy. What this does is that it replaces
an undrawable table with an ellipsis (...). This should only
occur in either super big tables or deeply nested tables in a
console with a small buffer width.
2020-10-18 08:03:40 +02:00
Takahito Yamatoya
a2f507e58f update sample output 2020-10-18 06:56:47 +02:00
Takahito Yamatoya
d1d06d6a6b fix incorrect command 2020-10-18 06:56:47 +02:00
Patrik Svensson
52718c499c Fix minor typo in example 2020-10-17 13:22:01 +02:00
Patrik Svensson
7ef1ac483a Fix overflow splitting bug
Closes #93
2020-10-17 12:37:20 +02:00
Takahito Yamatoya
c0875c912a fix incorrect link 2020-10-17 12:16:18 +02:00
Patrik Svensson
3f2ca49071 Add calendar control
Closes #101
2020-10-16 23:02:53 +02:00
Khalid Abuhakmeh
0a0380ae0a Don't throw when console is small
this just returns an empty collection when
take is 0. It leads to some strange output, but
it doesn't blow up.

 #93
2020-10-08 22:17:12 +02:00
Patrik Svensson
ae92c606bb Add support for remapping emojis
Closes #94
2020-10-07 17:33:05 +02:00
Patrik Svensson
68e92f3365 Add various exception improvements 2020-10-07 11:57:28 +02:00
Patrik Svensson
39a8588dc3 Rename ExceptionFormats.None 2020-10-07 11:57:28 +02:00
Patrik Svensson
3c3afe7439 Add support for rendering exceptions 2020-10-05 07:03:02 +02:00
Gary Ewan Park
971f9032ba (doc) Dynamically generate sections
Rather than hard-coding them.  Then, as the number of sections increase,
no additional changes will be required here.
2020-10-03 16:30:21 +02:00
Gary Ewan Park
5149557560 (doc) Remove hard-coded link
Rather than specifying spectre.console directly in the layout, figure out
the URL using GetLink method.
2020-10-03 16:30:21 +02:00
Khalid Abuhakmeh
e0947708c9 Generalized Search
Generalized the search to work with any table
with some basic classes and some updated
JavaScript, we can now search colors and emojis.
2020-10-02 19:39:02 +02:00
Patrik Svensson
b1db8a9403 Clean up border code
Removed caching that really didn't do anything anymore.
2020-10-01 23:05:02 +02:00
Khalid Abuhakmeh
a2f8652575 Add Search To Emoji Page
This adds a typeahead search feature
for the very large emoji table. It filters as you type to find if an emoji exists or not.

The JavaScript could be adapted to work on all tables in the future.
2020-10-01 22:00:39 +02:00
Khalid Abuhakmeh
672faa131f Update Docs Readme
Added some more context to the docs readme for
folks looking to contribute. Also added the license
so its clear what the license of the docs site is. As
a small tweak I removed a duplicate string value and
use the Constant.
2020-10-01 20:51:32 +02:00
163 changed files with 5965 additions and 730 deletions

View File

@@ -70,6 +70,8 @@ jobs:
dotnet example panels
dotnet example colors
dotnet example emojis
dotnet example exceptions
dotnet example calendars
- name: Build
shell: bash

1
.gitignore vendored
View File

@@ -5,6 +5,7 @@
[Pp]ackages/
/.artifacts/
/[Tt]ools/
.idea
.DS_Store
# Cakeup

413
README.jp.md Normal file
View File

@@ -0,0 +1,413 @@
# `Spectre.Console`
_[![Spectre.Console NuGet Version](https://img.shields.io/nuget/v/spectre.console.svg?style=flat&label=NuGet%3A%20Spectre.Console)](https://www.nuget.org/packages/spectre.console)_
綺麗なコンソールアプリケーションを簡単に作成するための.NET Standard 2.0ライブラリです。
Python用の素晴らしい[Rich ライブラリ](https://github.com/willmcgugan/rich)に強く影響を受けています。
## 目次
1. [特徴](#特徴)
2. [](#例)
3. [使用方法](#使用方法)
3.1. [Static APIの利用](#static-apiの利用)
3.2. [コンソールの作成](#コンソールの作成)
4. [例の実行](#例の実行)
5. [クイックスタート](#クイックスタート)
6. [マークアップ](#マークアップ)
7. [絵文字](#絵文字)
8. [テーブル](#テーブル)
9. [例外](#例外)
## 特徴
* ユニットテストを意識して書いています。
* table、grid、panel、マークアップ言語に影響を受けた [rich](https://github.com/willmcgugan/rich) に対応しています。
* 太字、薄字、斜字、下線、斜線、点滅などの一般的なSGR parameters に対応しています。
* ターミナルで 3/4/8/24ビットカラーに対応しています。
ライブラリは現在のターミナルの性能を検知し、必要なカラーにダウングレードします
## 例
![Example](resources/gfx/screenshots/example.png)
## 使用方法
`Spectre.Console` APIはステートフルで、スレッドセーフではありません。
異なるスレッドからコンソールに書く必要がある場合、通常の`System.Console` APIを使用するときと同様、適切な注意を払ってください。
現在の端末がANSIエスケープシーケンスに対応していない場合、
`Spectre.Console`は、`System.Console` APIの利用に切り替わります。
_メモ: このライブラリは現在開発中で、APIは1.0のリリースまでの間に変更されたり、
削除されたりする可能性があります。_
### Static APIの利用
`System.Console` APIでするように、テキストを出力したいだけの時にはstatic APIが最適ですが、綺麗です。
```csharp
AnsiConsole.Foreground = Color.CornflowerBlue;
AnsiConsole.Decoration = Decoration.Underline | Decoration.Bold;
AnsiConsole.WriteLine("Hello World!");
AnsiConsole.Reset();
AnsiConsole.MarkupLine("[bold yellow on red]{0}[/] [underline]world[/]!", "Goodbye");
```
もし、デフォルトの`IAnsiConsole`への参照を取得したい場合、
`AnsiConsole.Console`経由でアクセスできます。
### コンソールの作成
単体テスト中にコードの実行環境を制御したい場合など、
特定の機能をもつコンソールを明示的に作成すると便利なことがあります。
単体テストの一部としてコードで `AnsiConsole`を使わないことを推奨します。
```csharp
IAnsiConsole console = AnsiConsole.Create(
new AnsiConsoleSettings()
{
Ansi = AnsiSupport.Yes,
ColorSystem = ColorSystemSupport.TrueColor,
Out = new StringWriter(),
});
```
_メモ: 主導でコンソールを作成しているときに特定のカラーシステムを指定できたとしても、
ユーザーのターミナルでは使えないかもしれないことを覚えておいてください。
テスト用にIAnsiConsoleを作成していない限り、
常に`ColorSystemSupport.Detect``AnsiSupport.Detect`を使用してください。_
## 例の実行
Spectre.Consoleでできることを見るために、
[dotnet-example](https://github.com/patriksvensson/dotnet-example)グローバルツールをインストールします。
```
> dotnet tool install -g dotnet-example
```
このリポジトリで提供している例が一覧表示されます
```
> dotnet example
╭────────────┬───────────────────────────────────────┬──────────────────────────────────────────────────────╮
│ Name │ Path │ Description │
├────────────┼───────────────────────────────────────┼──────────────────────────────────────────────────────┤
│ Borders │ examples/Borders/Borders.csproj │ Demonstrates the different kind of borders. │
│ Calendars │ examples/Calendars/Calendars.csproj │ Demonstrates how to render calendars. │
│ Colors │ examples/Colors/Colors.csproj │ Demonstrates how to use colors in the console. │
│ Columns │ examples/Columns/Columns.csproj │ Demonstrates how to render data into columns. │
│ Emojis │ examples/Emojis/Emojis.csproj │ Demonstrates how to render emojis. │
│ Exceptions │ examples/Exceptions/Exceptions.csproj │ Demonstrates how to render formatted exceptions. │
│ Grids │ examples/Grids/Grids.csproj │ Demonstrates how to render grids in a console. │
│ Info │ examples/Info/Info.csproj │ Displays the capabilities of the current console. │
│ Links │ examples/Links/Links.csproj │ Demonstrates how to render links in a console. │
│ Panels │ examples/Panels/Panels.csproj │ Demonstrates how to render items in panels. │
│ Rules │ examples/Rules/Rules.csproj │ Demonstrates how to render horizontal rules (lines). │
│ Tables │ examples/Tables/Tables.csproj │ Demonstrates how to render tables in a console. │
╰────────────┴───────────────────────────────────────┴──────────────────────────────────────────────────────╯
```
そして、例を実行します
```
> dotnet example tables
┌──────────┬──────────┬────────┐
│ Foo │ Bar │ Baz │
├──────────┼──────────┼────────┤
│ Hello │ World! │ │
│ Bonjour │ le │ monde! │
│ Hej │ Världen! │ │
└──────────┴──────────┴────────┘
```
## クイックスタート
pectre.Consoleの利用を開始する最初の方法は、Nugetパッケージをインストールすることです。
```shell
> dotnet add package Spectre.Console
```
その後、`Spectre.Console`名前空間を参照する必要があります。一度参照したら、提供されている全ての機能を使用できます。
```csharp
using Spectre.Console
public static class Program
{
public static void Main(string[] args)
{
AnsiConsole.Markup("[underline red]Hello[/] World!");
}
}
```
## マークアップ
`Markup`クラスは、コンソールにリッチなテキストを出力することができます。
### 文法
コンソールマークアップはbbcodeに影響を受けた文法を利用します。角括弧でスタイルを書いたらスタイルを参照、例えば、`[bold red]`
は、`[/]`で閉じるまでスタイルが適用されます。
```csharp
AnsiConsole.Render(new Markup("[bold yellow]Hello[/] [red]World![/]"));
```
`Markup` クラスは`IRenderable`を実装しており、table、grid、Panelを使用できることを意味します。
`IRenderable`のレンダリングに対応している多くのクラスは、リッチテキストの描画を上書きます。
```csharp
var table = new Table();
table.AddColumn(new TableColumn(new Markup("[yellow]Foo[/]")));
table.AddColumn(new TableColumn("[blue]Bar[/]"));
```
### 便利なメソッド
`AnsiConsole`には、新しい`Markup`インスタンスをインスタンス化することなく、コンソールにマークアップテキストを書き込める便利なメソッドがあります。
```csharp
AnsiConsole.Markup("[underline green]Hello[/] ");
AnsiConsole.MarkupLine("[bold]World[/]");
```
### エスケープ文字列
`[`を出力するために、 `[[`を利用し、`]`を出力するために`]]`を利用します。
```csharp
AnsiConsole.Markup("[[Hello]] "); // [Hello]
AnsiConsole.Markup("[red][[World]][/]"); // [World]
```
`SafeMarkup`拡張メソッドを使用することもできます。
```csharp
AnsiConsole.Markup("[red]{0}[/]", "Hello [World]".SafeMarkup());
```
### カラー
`new Style(foreground: Color.Maroon)`のようなコード、または、`AnsiConsole.Markup("[maroon on blue]Hello[/]")`のようなマークアップテキストで色を使用できます。
### 背景色の設定
カラー指定の際に、`on`を付けることで、マークアップで背景色を設定できます。
```
[bold yellow on blue]Hello[/]
[default on blue]World[/]
```
### 絵文字の描画
マークアップの一部として絵文字を出力するために、emojiショートコードが使用できます。
```csharp
AnsiConsole.MarkupLine("Hello :globe_showing_europe_africa:!");
```
emojiのスタイルについては、付録の[Emoji](./appendix/emojis) を参照してください。
### カラー
上の例では、全ての色は名前で参照されています。
しかし、16進数やRGB表現をマークダウンで色指定に使用できます。
```csharp
AnsiConsole.Markup("[red]Foo[/] ");
AnsiConsole.Markup("[#ff0000]Bar[/] ");
AnsiConsole.Markup("[rgb(255,0,0)]Baz[/] ");
```
## 絵文字
どのような絵文字が使用できるかは、使用しているOSやターミナルに依存し、どのように表示されるかは保証されません。絵文字の幅計算は正確ではないため、表、パネル、グリッドで使用する場合は表示がずれるかもしれません。
完全な互換性を確保するために、Unicode 13.0 より以前の`Emoji_Presentation`カテゴリにあるものだけを使用することを検討してください。
公式の絵文字一覧
https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
```csharp
// Markup
AnsiConsole.MarkupLine("Hello :globe_showing_europe_africa:!");
// Constant
var hello = "Hello " + Emoji.Known.GlobeShowingEuropeAfrica;
```
テキスト内の絵文字を置き換えることができます。
```csharp
var phrase = "Mmmm :birthday_cake:";
var rendered
```
既存の絵文字を別のものにしたり、完全に新しい物を追加したいことがあります。このために、`Emoji.Remap`メソッドを使用できます。
この方法は、マークアップ文字と`Emoji.Replace`の両方で動作します。
```csharp
// Remap the emoji
Emoji.Remap("globe_showing_europe_africa", "😄");
// Render markup
AnsiConsole.MarkupLine("Hello :globe_showing_europe_africa:!");
// Replace emojis in string
var phrase = "Hello :globe_showing_europe_africa:!";
var rendered = Emoji.Replace(phrase);
```
## テーブル
テーブルはターミナルで表データを表示するのに完璧な方法です。
`Spectre.Console` は、テーブルの描画にとても優れていて、全てのカラムは中に合わせて調整してくれます。
`IRenderable`を実装しているものは、列ヘッダやセル、別のテーブルとして使用できます。
### 使い方
テーブルを描画するために、`Table`インスタンスを作成し、必要な数の列を追加し、行を追加します。
テーブルをコンソールの`Render`メソッドに渡して終わりです。
```csharp
// テーブルの作成
var table = new Table();
// 列の追加
table.AddColumn("Foo");
table.AddColumn(new TableColumn("Bar").Centered());
// 行の追加
table.AddRow("Baz", "[green]Qux[/]");
table.AddRow(new Markup("[blue]Corgi[/]"), new Panel("Waldo"));
// コンソールにテーブルの描画
AnsiConsole.Render(table);
```
これは次のように出力を描画します。
![Table](docs/input/assets/images/table.png)
### 罫線
```csharp
// 罫線を設定します
table.SetBorder(Border.None);
table.SetBorder(Border.Ascii);
table.SetBorder(Border.Square);
table.SetBorder(Border.Rounded);
```
### 拡大 / 縮小
```csharp
// テーブル幅を最大に設定します
table.Expand();
// テーブル幅を最小に設定します
table.Collapse();
```
### ヘッダーを隠す
```csharp
// 全ての列のヘッダーを隠します
table.HideHeaders();
```
### テーブル幅の設定
```csharp
// テーブル幅50セルに設定します
table.SetWidth(50);
```
### 整列(アライメント)
```csharp
// 整列を明示的に設定する
column.SetAlignment(Justify.Right);
```
### パディング
```csharp
// 左と右のパディングを設定する
column.SetPadding(left: 3, right: 5);
// 個別にパディングを設定する
column.PadLeft(3);
column.PadRight(5);
```
### 列改行の無効化
```csharp
// 列改行の無効化
column.NoWrap();
```
### 列幅の設定
```csharp
// 列幅の設定(これはまだ柔軟な拡張メソッドがありません)
column.Width = 15;
```
## 例外
例外はターミナルで見たときに読みやすいとは限りません。
`WriteException`メソッドを使用することで、例外をもう少し読みやすくすることができます。
```csharp
AnsiConsole.WriteException(ex);
```
![exception](docs/input/assets/images/exception.png)
### 例外の省略表示
例外の特定部分を短くして、さらに読みやすくしたり、パスをクリック可能なハイパーリンクにすることもできます。
ハイパーリンクがクリックできるかはターミナル次第です。
```csharp
AnsiConsole.WriteException(ex,
ExceptionFormat.ShortenPaths | ExceptionFormat.ShortenTypes |
ExceptionFormat.ShortenMethods | ExceptionFormat.ShowLinks);
```
![exception](docs/input/assets/images/compact_exception.png)
### 例外出力のカスタマイズ
例外の特定部分を短縮するだけでなく、デフォルトのスタイルを上書きすることもできます。
```csharp
AnsiConsole.WriteException(ex, new ExceptionSettings
{
Format = ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks,
Style = new ExceptionStyle
{
Exception = Style.WithForeground(Color.Grey),
Message = Style.WithForeground(Color.White),
NonEmphasized = Style.WithForeground(Color.Cornsilk1),
Parenthesis = Style.WithForeground(Color.Cornsilk1),
Method = Style.WithForeground(Color.Red),
ParameterName = Style.WithForeground(Color.Cornsilk1),
ParameterType = Style.WithForeground(Color.Red),
Path = Style.WithForeground(Color.Red),
LineNumber = Style.WithForeground(Color.Cornsilk1),
}
});
```
![exception](docs/input/assets/images/custom_exception.png)

View File

@@ -10,10 +10,11 @@ for Python.
1. [Features](#features)
2. [Example](#example)
3. [Usage](#usage)
3.1. [Using the static API](#using-the-static-api)
3.2. [Creating a console](#creating-a-console)
4. [Running examples](#running-examples)
3. [Installing](#installing)
4. [Usage](#usage)
4.1. [Using the static API](#using-the-static-api)
4.2. [Creating a console](#creating-a-console)
5. [Running examples](#running-examples)
## Features
@@ -30,6 +31,14 @@ for Python.
![Example](resources/gfx/screenshots/example.png)
## Installing
The fastest way of getting started using Spectre.Console is to install the NuGet package.
```csharp
dotnet add package Spectre.Console
```
## Usage
The `Spectre.Console` API is stateful and is not thread-safe.
@@ -99,20 +108,28 @@ Now you can list available examples in this repository:
```
> dotnet example
╭───────────────────────────────────────┬─────────────────────────────────────────────────╮
│ Name │ Path │ Description │
├───────────────────────────────────────┼─────────────────────────────────────────────────┤
Colors │ examples/Colors/Colors.csproj │ Demonstrates how to use colors in the console.
Grid │ examples/Grid/Grid.csproj │ Demonstrates how to render grids in a console.
Panel │ examples/Panel/Panel.csproj │ Demonstrates how to render items in panels.
Table │ examples/Table/Table.csproj │ Demonstrates how to render tables in a console.
╰────────┴───────────────────────────────┴─────────────────────────────────────────────────╯
╭────────────┬───────────────────────────────────────┬──────────────────────────────────────────────────────
│ Name │ Path │ Description
├────────────┼───────────────────────────────────────┼──────────────────────────────────────────────────────
Borders │ examples/Borders/Borders.csproj │ Demonstrates the different kind of borders.
Calendars │ examples/Calendars/Calendars.csproj │ Demonstrates how to render calendars.
Colors │ examples/Colors/Colors.csproj │ Demonstrates how to use colors in the console.
Columns │ examples/Columns/Columns.csproj │ Demonstrates how to render data into columns.
│ Emojis │ examples/Emojis/Emojis.csproj │ Demonstrates how to render emojis. │
│ Exceptions │ examples/Exceptions/Exceptions.csproj │ Demonstrates how to render formatted exceptions. │
│ Grids │ examples/Grids/Grids.csproj │ Demonstrates how to render grids in a console. │
│ Info │ examples/Info/Info.csproj │ Displays the capabilities of the current console. │
│ Links │ examples/Links/Links.csproj │ Demonstrates how to render links in a console. │
│ Panels │ examples/Panels/Panels.csproj │ Demonstrates how to render items in panels. │
│ Rules │ examples/Rules/Rules.csproj │ Demonstrates how to render horizontal rules (lines). │
│ Tables │ examples/Tables/Tables.csproj │ Demonstrates how to render tables in a console. │
╰────────────┴───────────────────────────────────────┴──────────────────────────────────────────────────────╯
```
And to run an example:
```
> dotnet example table
> dotnet example tables
┌──────────┬──────────┬────────┐
│ Foo │ Bar │ Baz │
├──────────┼──────────┼────────┤

View File

@@ -1,8 +1,50 @@
# Documentation
Preview the documentation locally by running the following
from your favourite shell:
To start contributing to the [Spectre.Console](https://github.com/spectresystems/spectre.console) documentation, you will need the [.NET Core SDK](https://dot.net) 3.1 or higher.
## Running Preview Site
The documentation site uses [Statiq](https://statiq.dev), a static site generator. To build the documentation site run the following in a command-line terminal.
```
> dotnet run -- preview --virtual-dir "spectre.console"
```
> dotnet run preview --virtual-dir "spectre.console"
```
After the build is complete, you can navigate to [http://localhost:5080/spectre.consle](http://localhost:5080/spectre.console).
**Note that the site runs under a virtual directory.**
## Editing Content
The documentation is written using [Markdown](https://www.markdownguide.org/basic-syntax/).
Markdown files can be found under the following directories:
- [/input](./input)
- [/appendix](./input/appendix)
## Editing Layout
Layout and styling can also be found in the [input](./input) directory. Look for Sass, Css, and Images under the [assets](./input/assets) directory.
## Custom Build Features
The documentation site has custom enhancements to Statiq located under the [./src](./src) directory. Enhancements to the build process include:
- [Extension Methods](./src/Extensions)
- [Models](./src/Models)
- [Pipelines](./src/Pipelines)
- [Shortcodes](./src/Shortcodes)
- [Utilities](./src/Utilities)
## License
MIT License
Copyright (c) 2020 Spectre Systems AB
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -5,8 +5,8 @@
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/spectre.console/assets/bootstrap/bootstrap.css" rel="stylesheet" />
<link href="/spectre.console/assets/css/styles.css" rel="stylesheet" />
<link href="@Context.GetLink("/assets/bootstrap/bootstrap.css")" rel="stylesheet" />
<link href="@Context.GetLink("/assets/css/styles.css")" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;700&family=Roboto+Slab:wght@400;700&family=Roboto:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&display=swap" rel="stylesheet" data-no-mirror>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.19.0/themes/prism.css">
@@ -29,7 +29,7 @@
<nav id="topnav" class="navbar navbar-expand-lg navbar-light">
<div class="container py-3">
<a class="navbar-brand" href="/spectre.console"><img id="logo" src="/spectre.console/assets/logo.svg" alt="Spectre.Console"> Spectre.Console</a>
<a class="navbar-brand" href="@Context.GetLink("/")"><img id="logo" src="@Context.GetLink("/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>
@@ -135,7 +135,7 @@
else
{
@root.GetTitle()
}
}
</div>
@foreach (IDocument document in OutputPages.GetChildrenOf(root).OnlyVisible())
@@ -149,7 +149,7 @@
else
{
@document.GetTitle()
}
}
</div>
@if (documentChildren.OnlyVisible().Any())

View File

@@ -13,4 +13,19 @@ in markup text such as `AnsiConsole.Markup("[maroon on blue]Hello[/]")`.
# Standard colors
<?# ColorTable /?>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</div>
<input
class="form-control w-100 filter"
data-table="color-results"
type="text" placeholder="Search Colors..." autocomplete="off"
aria-label="Search Colors">
</div>
<?# ColorTable /?>
<script type="text/javascript" src="../assets/js/table-search.js"></script>

View File

@@ -30,9 +30,43 @@ var phrase = "Mmmm :birthday_cake:";
var rendered = Emoji.Replace(phrase);
```
# Remapping or adding an emoji
Sometimes you want to remap an existing emoji, or
add a completely new one. For this you can use the
`Emoji.Remap` method. This approach works both with
markup strings and `Emoji.Replace`.
```csharp
// Remap the emoji
Emoji.Remap("globe_showing_europe_africa", "😄");
// Render markup
AnsiConsole.MarkupLine("Hello :globe_showing_europe_africa:!");
// Replace emojis in string
var phrase = "Hello :globe_showing_europe_africa:!";
var rendered = Emoji.Replace(phrase);
```
# Emojis
_The images in the table below might not render correctly in your
browser for the same reasons mentioned in the `Compatibility` section._
<?# EmojiTable /?>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</div>
<input
class="form-control w-100 filter"
data-table="emoji-results"
type="text" placeholder="Search Emojis..." autocomplete="off"
aria-label="Search Emojis">
</div>
<?# EmojiTable /?>
<script type="text/javascript" src="../assets/js/table-search.js"></script>

View File

@@ -0,0 +1,12 @@
Title: Appendix
Order: 10
---
<h1>Sections</h1>
<ul>
@foreach (IDocument child in OutputPages.GetChildrenOf(Document))
{
<li>@Html.DocumentLink(child)</li>
}
</ul>

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@@ -0,0 +1,35 @@
$(document).ready(function () {
$('.filter').each(function () {
let input = this;
let table = document.getElementById(input.dataset.table);
input.onkeyup = function (event) {
if (event.key === "Enter") {
event.preventDefault();
event.stopPropagation();
return false;
}
let value = input.value.toUpperCase();
let rows = table.getElementsByClassName('search-row');
for (let i = 0; i < rows.length; i++) {
let row = rows[i];
let match =
new RegExp(value, "i").test(row.textContent) ||
value === '';
if (match) {
row.style.display = 'table-row';
} else {
row.style.display = 'none';
}
}
}; // keyup
})
}); // ready

52
docs/input/exceptions.md Normal file
View File

@@ -0,0 +1,52 @@
Title: Exceptions
Order: 3
---
Exceptions isn't always readable when viewed in the terminal.
You can make exception a bit more readable by using the `WriteException` method.
```csharp
AnsiConsole.WriteException(ex);
```
<img src="assets/images/exception.png" style="max-width: 100%;">
## Shortening parts
You can also shorten specific parts of the exception to make it even
more readable, and make paths clickable hyperlinks. Whether or not
the hyperlinks are clickable is up to the terminal.
```csharp
AnsiConsole.WriteException(ex,
ExceptionFormat.ShortenPaths | ExceptionFormat.ShortenTypes |
ExceptionFormat.ShortenMethods | ExceptionFormat.ShowLinks);
```
<img src="assets/images/compact_exception.png" style="max-width: 100%;">
## Customizing exception output
In addition to shorten specific part of the exception, you can
also override the default styling.
```csharp
AnsiConsole.WriteException(ex, new ExceptionSettings
{
Format = ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks,
Style = new ExceptionStyle
{
Exception = Style.WithForeground(Color.Grey),
Message = Style.WithForeground(Color.White),
NonEmphasized = Style.WithForeground(Color.Cornsilk1),
Parenthesis = Style.WithForeground(Color.Cornsilk1),
Method = Style.WithForeground(Color.Red),
ParameterName = Style.WithForeground(Color.Cornsilk1),
ParameterType = Style.WithForeground(Color.Red),
Path = Style.WithForeground(Color.Red),
LineNumber = Style.WithForeground(Color.Cornsilk1),
}
});
```
<img src="assets/images/custom_exception.png" style="max-width: 100%;">

View File

@@ -20,7 +20,7 @@ for Python written by Will McGugan.
The library will detect the capabilities of the current terminal
and downgrade colors as needed.
## Example
## Examples
<img width="100%"
src="https://github.com/spectresystems/spectre.console/raw/main/resources/gfx/screenshots/example.png" />
<img src="assets/images/table.gif" style="max-width: 100%; margin-top: 15px; margin-bottom: 25px;" />
<img src="https://github.com/spectresystems/spectre.console/raw/main/resources/gfx/screenshots/example.png" style="max-width: 100%;" />

View File

@@ -43,6 +43,12 @@ AnsiConsole.Markup("[[Hello]] "); // [Hello]
AnsiConsole.Markup("[red][[World]][/]"); // [World]
```
You can also use the `SafeMarkup` extension method.
```csharp
AnsiConsole.Markup("[red]{0}[/]", "Hello [World]".SafeMarkup());
```
# Setting background color
You can set the background color in markup by prefixing the color with
@@ -61,10 +67,19 @@ To output an emoji as part of markup, you can use emoji shortcodes.
AnsiConsole.MarkupLine("Hello :globe_showing_europe_africa:!");
```
For a list of emoji, see the [Emojis](xref:styles) appendix section.
For a list of emoji, see the [Emojis](xref:emojis) appendix section.
# Colors
In the examples above, all colors was referenced by their name,
but you can also use the hex or rgb representation for colors in markdown.
```csharp
AnsiConsole.Markup("[red]Foo[/] ");
AnsiConsole.Markup("[#ff0000]Bar[/] ");
AnsiConsole.Markup("[rgb(255,0,0)]Baz[/] ");
```
For a list of colors, see the [Colors](xref:colors) appendix section.
# Styles

View File

@@ -0,0 +1,114 @@
Title: Calendar
Order: 4
RedirectFrom: calendar
---
The `Calendar` is used to render a calendar to the terminal.
# Usage
To render a calendar, create a `Calendar` instance with a target date.
```csharp
var calendar = new Calendar(2020,10);
AnsiConsole.Render(calendar);
2020 October
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐
Sun Mon Tue Wed Thu Fri Sat
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
└─────┴─────┴─────┴─────┴─────┴─────┴─────┘
```
## Culture
You can set the calendar's culture to show localized weekdays.
```csharp
var calendar = new Calendar(2020,10);
calendar.SetCulture("ja-JP");
AnsiConsole.Render(calendar);
202010
┌────┬────┬────┬────┬────┬────┬────┐
├────┼────┼────┼────┼────┼────┼────┤
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
└────┴────┴────┴────┴────┴────┴────┘
```
## Header
You can hide the calendar header.
```csharp
var calendar = new Calendar(2020,10);
calendar.ShowHeader = false;
AnsiConsole.Render(calendar);
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐
Sun Mon Tue Wed Thu Fri Sat
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
└─────┴─────┴─────┴─────┴─────┴─────┴─────┘
```
You can set the header style of the calendar.
```csharp
var calendar = new Calendar(2020,10);
calendar.SetHeaderStyle(Style.Parse("blue bold"));
AnsiConsole.Render(calendar);
```
## Calendar Event
You can add an event to the calendar.
If a date has an event associated with it, the date gets highlighted in the calendar.
```csharp
var calendar = new Calendar(2020,10);
calendar.AddCalendarEvent(2020, 10, 11);
AnsiConsole.Render(calendar);
2020 October
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐
Sun Mon Tue Wed Thu Fri Sat
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
1 2 3
4 5 6 7 8 9 10
11* 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
└─────┴─────┴─────┴─────┴─────┴─────┴─────┘
```
### Highlight style
You can set the highlight style for a calendar event via `SetHighlightStyle`.
```csharp
var calendar = new Calendar(2020,10);
calendar.AddCalendarEvent(2020, 10, 11);
calendar.SetHighlightStyle(Style.Parse("yellow bold"));
AnsiConsole.Render(calendar);
```

View File

@@ -0,0 +1,3 @@
Title: Widgets
Order: 9
---

View File

@@ -0,0 +1,71 @@
Title: Rule
Order: 5
RedirectFrom: rule
---
The `Rule` class is used to render a horizontal rule (line) to the terminal.
![Rule](../assets/images/rule.png)
# Usage
To render a rule without a title:
```csharp
var rule = new Rule();
AnsiConsole.Render(rule);
```
## Title
You can set the rule title markup text.
```csharp
var rule = new Rule("[red]Hello[/]");
AnsiConsole.Render(rule);
// output
───────────────────────────────── Hello ─────────────────────────────────
```
### Title alignment
You can set the rule's title alignment.
```csharp
var rule = new Rule("[red]Hello[/]");
rule.Alignment = Justify.Left;
AnsiConsole.Render(rule);
//output
── Hello ────────────────────────────────────────────────────────────────
```
You can also specify it with a method
```csharp
var rule = new Rule("[red]Hello[/]");
rule.LeftAligned();
AnsiConsole.Render(rule);
//output
── Hello ────────────────────────────────────────────────────────────────
```
## Style
You can set the rule style.
```csharp
var rule = new Rule("[red]Hello[/]");
rule.Style = Style.Parse("red dim");
AnsiConsole.Render(rule);
```
You can also specify it with a method
```csharp
var rule = new Rule("[red]Hello[/]");
rule.SetStyle("red dim");
AnsiConsole.Render(rule);
```

View File

@@ -1,5 +1,6 @@
Title: Tables
Title: Table
Order: 3
RedirectFrom: tables
---
Tables are a perfect way of displaying tabular data in a terminal.
@@ -36,7 +37,7 @@ AnsiConsole.Render(table);
This will render the following output:
![Table](assets/images/table.png)
![Table](../assets/images/table.png)
# Table appearance

View File

@@ -20,10 +20,7 @@ namespace Docs
public static Bootstrapper ConfigureDeployment(this Bootstrapper bootstrapper, string deployBranch)
{
if (bootstrapper != null)
{
bootstrapper.AddSetting(Constants.Deployment.TargetBranch, deployBranch);
}
bootstrapper?.AddSetting(Constants.Deployment.TargetBranch, deployBranch);
return bootstrapper;
}
}

View File

@@ -9,15 +9,13 @@ namespace Docs.Pipelines
{
public class ColorsPipeline : Pipeline
{
public const string Url = "https://raw.githubusercontent.com/spectresystems/spectre.console/main/resources/scripts/Generator/Data/colors.json";
public ColorsPipeline()
{
InputModules = new ModuleList
{
new ExecuteConfig(
Config.FromContext(ctx => {
return new ReadWeb(Url);
return new ReadWeb(Constants.Colors.Url);
}))
};
@@ -32,4 +30,4 @@ namespace Docs.Pipelines
};
}
}
}
}

View File

@@ -21,7 +21,7 @@ namespace Docs.Shortcodes
.First().Object;
// Headers
var table = new XElement("table", new XAttribute("class", "table"));
var table = new XElement("table", new XAttribute("class", "table"), new XAttribute("id", "color-results"));
var header = new XElement("tr", new XAttribute("class", "color-row"));
header.Add(new XElement("th", ""));
header.Add(new XElement("th", "#"));
@@ -33,8 +33,8 @@ namespace Docs.Shortcodes
foreach (var color in colors)
{
var rep = new XElement("td",
new XElement("span",
var rep = new XElement("td",
new XElement("span",
new XAttribute("class", "color-representation"),
new XAttribute("style", $"background-color:{color.Hex};")));
var name = new XElement("td", new XElement("code", color.Number.ToString()));
@@ -44,7 +44,7 @@ namespace Docs.Shortcodes
var clr = new XElement("td", new XElement("code", color.ClrName));
// Create row
var row = new XElement("tr");
var row = new XElement("tr", new XAttribute("class", "search-row"));
row.Add(rep);
row.Add(name);
row.Add(number);

View File

@@ -18,8 +18,8 @@ namespace Docs.Shortcodes
.First().Object;
// Headers
var table = new XElement("table", new XAttribute("class", "table"));
var header = new XElement("tr", new XAttribute("class", "emoji-row"));
var table = new XElement("table", new XAttribute("class", "table"), new XAttribute("id", "emoji-results"));
var header = new XElement("tr", new XAttribute("class", "emoji-row-header"));
header.Add(new XElement("th", ""));
header.Add(new XElement("th", "Markup"));
header.Add(new XElement("th", "Constant"));
@@ -28,9 +28,9 @@ namespace Docs.Shortcodes
foreach (var emoji in emojis)
{
var code = emoji.Code.Replace("U+0000", "U+").Replace("U+000", "U+");
var icon = string.Format("&#x{0};", emoji.Code.Replace("U+", string.Empty));
var icon = $"&#x{emoji.Code.Replace("U+", string.Empty)};";
var row = new XElement("tr");
var row = new XElement("tr", new XAttribute("class", "search-row"));
row.Add(new XElement("td", icon));
row.Add(new XElement("td", new XElement("code", $":{emoji.Id}:")));
row.Add(new XElement("td", new XElement("code", emoji.Name)));

View File

@@ -1,3 +1,4 @@
using System.Diagnostics;
using Spectre.Console;
using Spectre.Console.Rendering;
@@ -8,26 +9,22 @@ namespace BordersExample
public static void Main()
{
// Render panel borders
AnsiConsole.WriteLine();
AnsiConsole.MarkupLine("[white bold underline]PANEL BORDERS[/]");
AnsiConsole.WriteLine();
RenderPanelBorders();
HorizontalRule("PANEL BORDERS");
PanelBorders();
// Render table borders
AnsiConsole.WriteLine();
AnsiConsole.MarkupLine("[white bold underline]TABLE BORDERS[/]");
AnsiConsole.WriteLine();
RenderTableBorders();
HorizontalRule("TABLE BORDERS");
TableBorders();
}
private static void RenderPanelBorders()
private static void PanelBorders()
{
static IRenderable CreatePanel(string name, BoxBorder border)
{
return new Panel($"This is a panel with\nthe [yellow]{name}[/] border.")
.SetHeader($" {name} ", Style.Parse("blue"), Justify.Center)
.SetBorderStyle(Style.Parse("grey"))
.SetBorder(border);
.Header($" {name} ", Style.Parse("blue"), Justify.Center)
.Border(border)
.BorderStyle(Style.Parse("grey"));
}
var items = new[]
@@ -46,19 +43,18 @@ namespace BordersExample
new Padding(2,0,0,0)));
}
private static void RenderTableBorders()
private static void TableBorders()
{
static IRenderable CreateTable(string name, TableBorder border)
{
var table = new Table().SetBorder(border);
table.AddColumn("[yellow]Header 1[/]");
table.AddColumn("[yellow]Header 2[/]", col => col.RightAligned());
var table = new Table().Border(border);
table.AddColumn("[yellow]Header 1[/]", c => c.Footer("[grey]Footer 1[/]"));
table.AddColumn("[yellow]Header 2[/]", col => col.Footer("[grey]Footer 2[/]").RightAligned());
table.AddRow("Cell", "Cell");
table.AddRow("Cell", "Cell");
return new Panel(table)
.SetHeader($" {name} ", Style.Parse("blue"), Justify.Center)
.SetBorderStyle(Style.Parse("grey"))
.Header($" {name} ", Style.Parse("blue"), Justify.Center)
.NoBorder();
}
@@ -85,5 +81,12 @@ namespace BordersExample
AnsiConsole.Render(new Columns(items).Collapse());
}
private static void HorizontalRule(string title)
{
AnsiConsole.WriteLine();
AnsiConsole.Render(new Rule($"[white bold]{title}[/]").RuleStyle("grey").LeftAligned());
AnsiConsole.WriteLine();
}
}
}

View File

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

View File

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

View File

@@ -24,7 +24,7 @@ namespace ColorExample
AnsiConsole.ResetColors();
AnsiConsole.WriteLine();
AnsiConsole.MarkupLine("[bold underline]3-bit Colors[/]");
AnsiConsole.Render(new Rule("[yellow bold underline]3-bit Colors[/]").RuleStyle("grey").LeftAligned());
AnsiConsole.WriteLine();
for (var i = 0; i < 8; i++)
@@ -47,7 +47,7 @@ namespace ColorExample
AnsiConsole.ResetColors();
AnsiConsole.WriteLine();
AnsiConsole.MarkupLine("[bold underline]4-bit Colors[/]");
AnsiConsole.Render(new Rule("[yellow bold underline]4-bit Colors[/]").RuleStyle("grey").LeftAligned());
AnsiConsole.WriteLine();
for (var i = 0; i < 16; i++)
@@ -70,7 +70,7 @@ namespace ColorExample
AnsiConsole.ResetColors();
AnsiConsole.WriteLine();
AnsiConsole.MarkupLine("[bold underline]8-bit Colors[/]");
AnsiConsole.Render(new Rule("[yellow bold underline]8-bit Colors[/]").RuleStyle("grey").LeftAligned());
AnsiConsole.WriteLine();
for (var i = 0; i < 16; i++)
@@ -97,7 +97,7 @@ namespace ColorExample
AnsiConsole.ResetColors();
AnsiConsole.WriteLine();
AnsiConsole.MarkupLine("[bold underline]24-bit Colors[/]");
AnsiConsole.Render(new Rule("[yellow bold underline]24-bit Colors[/]").RuleStyle("grey").LeftAligned());
AnsiConsole.WriteLine();
var index = 0;

View File

@@ -19,8 +19,8 @@ namespace ColumnsExample
var cards = new List<Panel>();
foreach(var user in users.results)
{
cards.Add(new Panel(GetCard(user))
.SetHeader($"{user.location.country}")
cards.Add(new Panel(GetCardContent(user))
.Header($"{user.location.country}")
.RoundedBorder().Expand());
}
@@ -28,7 +28,7 @@ namespace ColumnsExample
AnsiConsole.Render(new Columns(cards));
}
private static string GetCard(dynamic user)
private static string GetCardContent(dynamic user)
{
var name = $"{user.name.first} {user.name.last}";
var country = $"{user.location.city}";

View File

@@ -6,11 +6,19 @@ namespace EmojiExample
{
public static void Main(string[] args)
{
// Markup
// Show a known emoji
RenderEmoji();
// Show a remapped emoji
Emoji.Remap("globe_showing_europe_africa", Emoji.Known.GrinningFaceWithSmilingEyes);
RenderEmoji();
}
private static void RenderEmoji()
{
AnsiConsole.Render(
new Panel("[yellow]Hello :globe_showing_europe_africa:![/]")
.RoundedBorder()
.SetHeader("Markup"));
.RoundedBorder());
}
}
}

View File

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

View File

@@ -0,0 +1,66 @@
using System;
using System.Security.Authentication;
using Spectre.Console;
namespace Exceptions
{
public static class Program
{
public static void Main(string[] args)
{
try
{
DoMagic(42, null);
}
catch (Exception ex)
{
AnsiConsole.WriteLine();
AnsiConsole.Render(new Rule("Default").LeftAligned());
AnsiConsole.WriteLine();
AnsiConsole.WriteException(ex);
AnsiConsole.WriteLine();
AnsiConsole.Render(new Rule("Compact").LeftAligned());
AnsiConsole.WriteLine();
AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks);
AnsiConsole.WriteLine();
AnsiConsole.Render(new Rule("Compact + Custom colors").LeftAligned());
AnsiConsole.WriteLine();
AnsiConsole.WriteException(ex, new ExceptionSettings
{
Format = ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks,
Style = new ExceptionStyle
{
Exception = new Style().Foreground(Color.Grey),
Message = new Style().Foreground(Color.White),
NonEmphasized = new Style().Foreground(Color.Cornsilk1),
Parenthesis = new Style().Foreground(Color.Cornsilk1),
Method = new Style().Foreground(Color.Red),
ParameterName = new Style().Foreground(Color.Cornsilk1),
ParameterType = new Style().Foreground(Color.Red),
Path = new Style().Foreground(Color.Red),
LineNumber = new Style().Foreground(Color.Cornsilk1),
}
});
}
}
private static void DoMagic(int foo, string[,] bar)
{
try
{
CheckCredentials(foo, bar);
}
catch(Exception ex)
{
throw new InvalidOperationException("Whaaat?", ex);
}
}
private static void CheckCredentials(int qux, string[,] corgi)
{
throw new InvalidCredentialException("The credentials are invalid.");
}
}
}

View File

@@ -11,13 +11,12 @@ namespace GridExample
AnsiConsole.WriteLine();
var grid = new Grid();
grid.AddColumn(new GridColumn { NoWrap = true });
grid.AddColumn(new GridColumn { NoWrap = true, Width = 2 });
grid.AddColumn();
grid.AddRow("Options:", "", "");
grid.AddRow(" [blue]-h[/], [blue]--help[/]", "", "Show command line help.");
grid.AddRow(" [blue]-c[/], [blue]--configuration[/] <CONFIGURATION>", "", "The configuration to run for.");
grid.AddRow(" [blue]-v[/], [blue]--verbosity[/] <LEVEL>", "", "Set the [grey]MSBuild[/] verbosity level.");
grid.AddColumn(new GridColumn().NoWrap());
grid.AddColumn(new GridColumn().PadLeft(2));
grid.AddRow("Options:");
grid.AddRow(" [blue]-h[/], [blue]--help[/]", "Show command line help.");
grid.AddRow(" [blue]-c[/], [blue]--configuration[/] <CONFIGURATION>", "The configuration to run for.");
grid.AddRow(" [blue]-v[/], [blue]--verbosity[/] <LEVEL>", "Set the [grey]MSBuild[/] verbosity level.");
AnsiConsole.Render(grid);
}

View File

@@ -17,7 +17,7 @@ namespace InfoExample
AnsiConsole.Render(
new Panel(grid)
.SetHeader("Information"));
.Header("Information"));
}
private static string YesNo(bool value)

View File

@@ -13,28 +13,33 @@ namespace PanelExample
AnsiConsole.Render(
new Panel(
new Panel(content)
.SetBorder(BoxBorder.Rounded)));
.Border(BoxBorder.Rounded)));
// Left adjusted panel with text
AnsiConsole.Render(
new Panel(new Text("Left adjusted\nLeft").LeftAligned())
.Expand()
.SquareBorder()
.SetHeader("Left", Style.WithForeground(Color.Red)));
.Header("Left")
.HeaderStyle("red"));
// Centered ASCII panel with text
AnsiConsole.Render(
new Panel(new Text("Centered\nCenter").Centered())
.Expand()
.AsciiBorder()
.SetHeader("Center", Style.WithForeground(Color.Green), Justify.Center));
.Header("Center")
.HeaderStyle("green")
.HeaderAlignment(Justify.Center));
// Right adjusted, rounded panel with text
AnsiConsole.Render(
new Panel(new Text("Right adjusted\nRight").RightAligned())
.Expand()
.RoundedBorder()
.SetHeader("Right", Style.WithForeground(Color.Blue), Justify.Right));
.Header("Right")
.HeaderStyle("blue")
.HeaderAlignment(Justify.Right));
}
}
}

40
examples/Rules/Program.cs Normal file
View File

@@ -0,0 +1,40 @@
using Spectre.Console;
namespace EmojiExample
{
public static class Program
{
public static void Main(string[] args)
{
// No title
WrapInPanel(
new Rule()
.RuleStyle(Style.Parse("yellow"))
.LeftAligned());
// Left aligned title
WrapInPanel(
new Rule("[white]Left aligned[/]")
.RuleStyle(Style.Parse("red"))
.LeftAligned());
// Centered title
WrapInPanel(
new Rule("[silver]Centered[/]")
.RuleStyle(Style.Parse("green"))
.Centered());
// Right aligned title
WrapInPanel(
new Rule("[grey]Right aligned[/]")
.RuleStyle(Style.Parse("blue"))
.RightAligned());
}
private static void WrapInPanel(Rule rule)
{
AnsiConsole.Render(new Panel(rule).Expand().BorderStyle(Style.Parse("grey")));
AnsiConsole.WriteLine();
}
}
}

View File

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

View File

@@ -5,86 +5,47 @@ namespace TableExample
public static class Program
{
public static void Main()
{
// A simple table
RenderSimpleTable();
// A big table
RenderBigTable();
// A nested table
RenderNestedTable();
}
private static void RenderSimpleTable()
{
// Create the table.
var table = new Table();
table.AddColumn(new TableColumn("[u]Foo[/]"));
table.AddColumn(new TableColumn("[u]Bar[/]"));
table.AddColumn(new TableColumn("[u]Baz[/]"));
// Add some rows
table.AddRow("Hello", "[red]World![/]", "");
table.AddRow("[blue]Bonjour[/]", "[white]le[/]", "[red]monde![/]");
table.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
var table = CreateTable();
// Render the table.
AnsiConsole.Render(table);
}
private static void RenderBigTable()
private static Table CreateTable()
{
// Create the table.
var table = new Table().SetBorder(TableBorder.Rounded);
table.AddColumn("[red underline]Foo[/]");
table.AddColumn(new TableColumn("[blue]Bar[/]") { Alignment = Justify.Right, NoWrap = true });
var simple = new Table()
.Border(TableBorder.Square)
.BorderColor(Color.Red)
.AddColumn(new TableColumn("[u]CDE[/]").Footer("EDC").Centered())
.AddColumn(new TableColumn("[u]FED[/]").Footer("DEF"))
.AddColumn(new TableColumn("[u]IHG[/]").Footer("GHI"))
.AddRow("Hello", "[red]World![/]", "")
.AddRow("[blue]Bonjour[/]", "[white]le[/]", "[red]monde![/]")
.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
// Add some rows
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");
table.AddEmptyRow();
table.AddRow("Hej", "[green]Världen[/]");
var second = new Table()
.Border(TableBorder.Rounded)
.BorderColor(Color.Green)
.AddColumn(new TableColumn("[u]Foo[/]"))
.AddColumn(new TableColumn("[u]Bar[/]"))
.AddColumn(new TableColumn("[u]Baz[/]"))
.AddRow("Hello", "[red]World![/]", "")
.AddRow(simple, new Text("Whaaat"), new Text("Lolz"))
.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
AnsiConsole.Render(table);
}
private static void RenderNestedTable()
{
// Create simple table.
var simple = new Table().SetBorder(TableBorder.Rounded).SetBorderColor(Color.Red);
simple.AddColumn(new TableColumn("[u]Foo[/]").Centered());
simple.AddColumn(new TableColumn("[u]Bar[/]"));
simple.AddColumn(new TableColumn("[u]Baz[/]"));
simple.AddRow("Hello", "[red]World![/]", "");
simple.AddRow("[blue]Bonjour[/]", "[white]le[/]", "[red]monde![/]");
simple.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
// Create other table.
var second = new Table().SetBorder(TableBorder.Square).SetBorderColor(Color.Green);
second.AddColumn(new TableColumn("[u]Foo[/]"));
second.AddColumn(new TableColumn("[u]Bar[/]"));
second.AddColumn(new TableColumn("[u]Baz[/]"));
second.AddRow("Hello", "[red]World![/]", "");
second.AddRow(simple, new Text("Whaaat"), new Text("Lolz"));
second.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
var table = new Table().SetBorder(TableBorder.Rounded);
table.AddColumn(new TableColumn(new Panel("[u]Foo[/]").SetBorderColor(Color.Red)));
table.AddColumn(new TableColumn(new Panel("[u]Bar[/]").SetBorderColor(Color.Green)));
table.AddColumn(new TableColumn(new Panel("[u]Baz[/]").SetBorderColor(Color.Blue)));
// Add some rows
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);
AnsiConsole.Render(table);
return new Table()
.Centered()
.Border(TableBorder.DoubleEdge)
.Title("TABLE [yellow]TITLE[/]")
.Caption("TABLE [yellow]CAPTION[/]")
.AddColumn(new TableColumn(new Panel("[u]ABC[/]").BorderColor(Color.Red)).Footer("[u]FOOTER 1[/]"))
.AddColumn(new TableColumn(new Panel("[u]DEF[/]").BorderColor(Color.Green)).Footer("[u]FOOTER 2[/]"))
.AddColumn(new TableColumn(new Panel("[u]GHI[/]").BorderColor(Color.Blue)).Footer("[u]FOOTER 3[/]"))
.AddRow(new Text("Hello").Centered(), new Markup("[red]World![/]"), Text.Empty)
.AddRow(second, new Text("Whaaat"), new Text("Lol"))
.AddRow(new Markup("[blue]Hej[/]").Centered(), new Markup("[yellow]Världen![/]"), Text.Empty);
}
}
}

View File

@@ -86,4 +86,7 @@ dotnet_diagnostic.RCS1057.severity = none
dotnet_diagnostic.RCS1227.severity = none
# IDE0004: Remove Unnecessary Cast
dotnet_diagnostic.IDE0004.severity = warning
dotnet_diagnostic.IDE0004.severity = warning
# CA1810: Initialize reference type static fields inline
dotnet_diagnostic.CA1810.severity = none

View File

@@ -24,3 +24,6 @@ dotnet_diagnostic.CA2000.severity = none
# SA1118: Parameter should not span multiple lines
dotnet_diagnostic.SA1118.severity = none
# CA1031: Do not catch general exception types
dotnet_diagnostic.CA1031.severity = none

View File

@@ -0,0 +1,23 @@
using System;
using System.Diagnostics.CodeAnalysis;
namespace Spectre.Console.Tests.Data
{
public static class TestExceptions
{
[SuppressMessage("Usage", "CA1801:Review unused parameters", Justification = "<Pending>")]
public static bool MethodThatThrows(int? number) => throw new InvalidOperationException("Throwing!");
public static void ThrowWithInnerException()
{
try
{
MethodThatThrows(null);
}
catch (Exception ex)
{
throw new InvalidOperationException("Something threw!", ex);
}
}
}
}

View File

@@ -1,13 +1,34 @@
using System;
using System.Text.RegularExpressions;
namespace Spectre.Console.Tests
{
public static class StringExtensions
{
private static readonly Regex _lineNumberRegex = new Regex(":\\d+", RegexOptions.Singleline);
private static readonly Regex _filenameRegex = new Regex("\\sin\\s.*cs:nn", RegexOptions.Multiline);
public static string NormalizeLineEndings(this string text)
{
return text?.Replace("\r\n", "\n", StringComparison.OrdinalIgnoreCase)
?.Replace("\r", string.Empty, StringComparison.OrdinalIgnoreCase);
}
public static string NormalizeStackTrace(this string text)
{
text = _lineNumberRegex.Replace(text, match =>
{
return ":nn";
});
return _filenameRegex.Replace(text, match =>
{
var value = match.Value;
var index = value.LastIndexOfAny(new[] { '\\', '/' });
var filename = value.Substring(index + 1, value.Length - index - 1);
return $" in /xyz/{filename}";
});
}
}
}

View File

@@ -6,10 +6,10 @@ namespace Spectre.Console.Tests
{
if (foreground)
{
return style.WithForeground(color);
return style.Foreground(color);
}
return style.WithBackground(color);
return style.Background(color);
}
}
}

View File

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

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Spectre.Console.Rendering;
@@ -50,5 +51,16 @@ namespace Spectre.Console.Tests
Writer.Write(segment.Text);
}
public string[] WriteExceptionAndGetLines(Exception ex, ExceptionFormats formats = ExceptionFormats.Default)
{
this.WriteException(ex, formats);
return Output.NormalizeStackTrace()
.NormalizeLineEndings()
.Split(new char[] { '\n' })
.Select(line => line.TrimEnd())
.ToArray();
}
}
}

View File

@@ -21,7 +21,7 @@ namespace Spectre.Console.Tests.Unit
var console = new TestableAnsiConsole(ColorSystem.TrueColor);
// When
console.Write("Hello World", Style.WithDecoration(decoration));
console.Write("Hello World", new Style().Decoration(decoration));
// Then
console.Output.ShouldBe(expected);
@@ -36,7 +36,7 @@ namespace Spectre.Console.Tests.Unit
var console = new TestableAnsiConsole(ColorSystem.TrueColor);
// When
console.Write("Hello World", Style.WithDecoration(decoration));
console.Write("Hello World", new Style().Decoration(decoration));
// Then
console.Output.ShouldBe(expected);

View File

@@ -15,9 +15,10 @@ namespace Spectre.Console.Tests.Unit
// When
console.Write(
"Hello",
Style.WithForeground(Color.RoyalBlue1)
.WithBackground(Color.NavajoWhite1)
.WithDecoration(Decoration.Italic));
new Style()
.Foreground(Color.RoyalBlue1)
.Background(Color.NavajoWhite1)
.Decoration(Decoration.Italic));
// Then
console.Output.ShouldBe("\u001b[3;90;47mHello\u001b[0m");
@@ -32,9 +33,10 @@ namespace Spectre.Console.Tests.Unit
// When
console.Write(
"Hello",
Style.WithForeground(Color.Default)
.WithBackground(Color.NavajoWhite1)
.WithDecoration(Decoration.Italic));
new Style()
.Foreground(Color.Default)
.Background(Color.NavajoWhite1)
.Decoration(Decoration.Italic));
// Then
console.Output.ShouldBe("\u001b[3;47mHello\u001b[0m");
@@ -49,9 +51,10 @@ namespace Spectre.Console.Tests.Unit
// When
console.Write(
"Hello",
Style.WithForeground(Color.RoyalBlue1)
.WithBackground(Color.Default)
.WithDecoration(Decoration.Italic));
new Style()
.Foreground(Color.RoyalBlue1)
.Background(Color.Default)
.Decoration(Decoration.Italic));
// Then
console.Output.ShouldBe("\u001b[3;90mHello\u001b[0m");
@@ -66,9 +69,10 @@ namespace Spectre.Console.Tests.Unit
// When
console.Write(
"Hello",
Style.WithForeground(Color.RoyalBlue1)
.WithBackground(Color.NavajoWhite1)
.WithDecoration(Decoration.None));
new Style()
.Foreground(Color.RoyalBlue1)
.Background(Color.NavajoWhite1)
.Decoration(Decoration.None));
// Then
console.Output.ShouldBe("\u001b[90;47mHello\u001b[0m");
@@ -83,8 +87,8 @@ namespace Spectre.Console.Tests.Unit
var console = new TestableAnsiConsole(ColorSystem.Standard, AnsiSupport.Yes);
// When
console.WriteLine("Hello", Style.WithBackground(ConsoleColor.Red));
console.WriteLine("World", Style.WithBackground(ConsoleColor.Green));
console.WriteLine("Hello", new Style().Background(ConsoleColor.Red));
console.WriteLine("World", new Style().Background(ConsoleColor.Green));
// Then
console.Output.NormalizeLineEndings()
@@ -98,7 +102,7 @@ namespace Spectre.Console.Tests.Unit
var console = new TestableAnsiConsole(ColorSystem.Standard, AnsiSupport.Yes);
// When
console.WriteLine("Hello\nWorld", Style.WithBackground(ConsoleColor.Red));
console.WriteLine("Hello\nWorld", new Style().Background(ConsoleColor.Red));
// Then
console.Output.NormalizeLineEndings()

View File

@@ -14,7 +14,7 @@ namespace Spectre.Console.Tests.Unit
public void Should_Return_Safe_Border()
{
// Given, When
var border = BoxBorder.None.GetSafeBorder(safe: true);
var border = BoxExtensions.GetSafeBorder(BoxBorder.None, safe: true);
// Then
border.ShouldBeSameAs(BoxBorder.None);
@@ -47,7 +47,7 @@ namespace Spectre.Console.Tests.Unit
public void Should_Return_Safe_Border()
{
// Given, When
var border = BoxBorder.Ascii.GetSafeBorder(safe: true);
var border = BoxExtensions.GetSafeBorder(BoxBorder.Ascii, safe: true);
// Then
border.ShouldBeSameAs(BoxBorder.Ascii);
@@ -80,7 +80,7 @@ namespace Spectre.Console.Tests.Unit
public void Should_Return_Safe_Border()
{
// Given, When
var border = BoxBorder.Double.GetSafeBorder(safe: true);
var border = BoxExtensions.GetSafeBorder(BoxBorder.Double, safe: true);
// Then
border.ShouldBeSameAs(BoxBorder.Double);
@@ -113,7 +113,7 @@ namespace Spectre.Console.Tests.Unit
public void Should_Return_Safe_Border()
{
// Given, When
var border = BoxBorder.Heavy.GetSafeBorder(safe: true);
var border = BoxExtensions.GetSafeBorder(BoxBorder.Heavy, safe: true);
// Then
border.ShouldBeSameAs(BoxBorder.Square);
@@ -144,7 +144,7 @@ namespace Spectre.Console.Tests.Unit
public void Should_Return_Safe_Border()
{
// Given, When
var border = BoxBorder.Rounded.GetSafeBorder(safe: true);
var border = BoxExtensions.GetSafeBorder(BoxBorder.Rounded, safe: true);
// Then
border.ShouldBeSameAs(BoxBorder.Square);
@@ -174,7 +174,7 @@ namespace Spectre.Console.Tests.Unit
public void Should_Return_Safe_Border()
{
// Given, When
var border = BoxBorder.Square.GetSafeBorder(safe: true);
var border = BoxExtensions.GetSafeBorder(BoxBorder.Square, safe: true);
// Then
border.ShouldBeSameAs(BoxBorder.Square);
@@ -203,7 +203,7 @@ namespace Spectre.Console.Tests.Unit
public static Panel GetPanel()
{
return new Panel("Hello World")
.SetHeader("Greeting");
.Header("Greeting");
}
}
}

View File

@@ -0,0 +1,153 @@
using System;
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public sealed class CalendarTests
{
[Fact]
public void Should_Render_Calendar_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var calendar = new Calendar(2020, 10)
.AddCalendarEvent(new DateTime(2020, 9, 1))
.AddCalendarEvent(new DateTime(2020, 10, 3))
.AddCalendarEvent(new DateTime(2020, 10, 12));
// When
console.Render(calendar);
// Then
console.Lines.Count.ShouldBe(11);
console.Lines[00].ShouldBe(" 2020 October ");
console.Lines[01].ShouldBe("┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐");
console.Lines[02].ShouldBe("│ Sun │ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │");
console.Lines[03].ShouldBe("├─────┼─────┼─────┼─────┼─────┼─────┼─────┤");
console.Lines[04].ShouldBe("│ │ │ │ │ 1 │ 2 │ 3* │");
console.Lines[05].ShouldBe("│ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │");
console.Lines[06].ShouldBe("│ 11 │ 12* │ 13 │ 14 │ 15 │ 16 │ 17 │");
console.Lines[07].ShouldBe("│ 18 │ 19 │ 20 │ 21 │ 22 │ 23 │ 24 │");
console.Lines[08].ShouldBe("│ 25 │ 26 │ 27 │ 28 │ 29 │ 30 │ 31 │");
console.Lines[09].ShouldBe("│ │ │ │ │ │ │ │");
console.Lines[10].ShouldBe("└─────┴─────┴─────┴─────┴─────┴─────┴─────┘");
}
[Fact]
public void Should_Center_Calendar_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var calendar = new Calendar(2020, 10)
.Centered()
.AddCalendarEvent(new DateTime(2020, 9, 1))
.AddCalendarEvent(new DateTime(2020, 10, 3))
.AddCalendarEvent(new DateTime(2020, 10, 12));
// When
console.Render(calendar);
// Then
console.Lines.Count.ShouldBe(11);
console.Lines[00].ShouldBe(" 2020 October ");
console.Lines[01].ShouldBe(" ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐ ");
console.Lines[02].ShouldBe(" │ Sun │ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │ ");
console.Lines[03].ShouldBe(" ├─────┼─────┼─────┼─────┼─────┼─────┼─────┤ ");
console.Lines[04].ShouldBe(" │ │ │ │ │ 1 │ 2 │ 3* │ ");
console.Lines[05].ShouldBe(" │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ ");
console.Lines[06].ShouldBe(" │ 11 │ 12* │ 13 │ 14 │ 15 │ 16 │ 17 │ ");
console.Lines[07].ShouldBe(" │ 18 │ 19 │ 20 │ 21 │ 22 │ 23 │ 24 │ ");
console.Lines[08].ShouldBe(" │ 25 │ 26 │ 27 │ 28 │ 29 │ 30 │ 31 │ ");
console.Lines[09].ShouldBe(" │ │ │ │ │ │ │ │ ");
console.Lines[10].ShouldBe(" └─────┴─────┴─────┴─────┴─────┴─────┴─────┘ ");
}
[Fact]
public void Should_Left_Align_Calendar_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var calendar = new Calendar(2020, 10)
.LeftAligned()
.AddCalendarEvent(new DateTime(2020, 9, 1))
.AddCalendarEvent(new DateTime(2020, 10, 3))
.AddCalendarEvent(new DateTime(2020, 10, 12));
// When
console.Render(calendar);
// Then
console.Lines.Count.ShouldBe(11);
console.Lines[00].ShouldBe(" 2020 October ");
console.Lines[01].ShouldBe("┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐");
console.Lines[02].ShouldBe("│ Sun │ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │");
console.Lines[03].ShouldBe("├─────┼─────┼─────┼─────┼─────┼─────┼─────┤");
console.Lines[04].ShouldBe("│ │ │ │ │ 1 │ 2 │ 3* │");
console.Lines[05].ShouldBe("│ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │");
console.Lines[06].ShouldBe("│ 11 │ 12* │ 13 │ 14 │ 15 │ 16 │ 17 │");
console.Lines[07].ShouldBe("│ 18 │ 19 │ 20 │ 21 │ 22 │ 23 │ 24 │");
console.Lines[08].ShouldBe("│ 25 │ 26 │ 27 │ 28 │ 29 │ 30 │ 31 │");
console.Lines[09].ShouldBe("│ │ │ │ │ │ │ │");
console.Lines[10].ShouldBe("└─────┴─────┴─────┴─────┴─────┴─────┴─────┘");
}
[Fact]
public void Should_Right_Align_Calendar_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var calendar = new Calendar(2020, 10)
.RightAligned()
.AddCalendarEvent(new DateTime(2020, 9, 1))
.AddCalendarEvent(new DateTime(2020, 10, 3))
.AddCalendarEvent(new DateTime(2020, 10, 12));
// When
console.Render(calendar);
// Then
console.Lines.Count.ShouldBe(11);
console.Lines[00].ShouldBe(" 2020 October ");
console.Lines[01].ShouldBe(" ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐");
console.Lines[02].ShouldBe(" │ Sun │ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │");
console.Lines[03].ShouldBe(" ├─────┼─────┼─────┼─────┼─────┼─────┼─────┤");
console.Lines[04].ShouldBe(" │ │ │ │ │ 1 │ 2 │ 3* │");
console.Lines[05].ShouldBe(" │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │");
console.Lines[06].ShouldBe(" │ 11 │ 12* │ 13 │ 14 │ 15 │ 16 │ 17 │");
console.Lines[07].ShouldBe(" │ 18 │ 19 │ 20 │ 21 │ 22 │ 23 │ 24 │");
console.Lines[08].ShouldBe(" │ 25 │ 26 │ 27 │ 28 │ 29 │ 30 │ 31 │");
console.Lines[09].ShouldBe(" │ │ │ │ │ │ │ │");
console.Lines[10].ShouldBe(" └─────┴─────┴─────┴─────┴─────┴─────┴─────┘");
}
[Fact]
public void Should_Render_Calendar_Correctly_For_Specific_Culture()
{
// Given
var console = new PlainConsole(width: 80);
var calendar = new Calendar(2020, 10, 15)
.Culture("de-DE")
.AddCalendarEvent(new DateTime(2020, 9, 1))
.AddCalendarEvent(new DateTime(2020, 10, 3))
.AddCalendarEvent(new DateTime(2020, 10, 12));
// When
console.Render(calendar);
// Then
console.Lines.Count.ShouldBe(11);
console.Lines[00].ShouldBe(" Oktober 2020 ");
console.Lines[01].ShouldBe("┌─────┬────┬────┬────┬────┬────┬────┐");
console.Lines[02].ShouldBe("│ Mo │ Di │ Mi │ Do │ Fr │ Sa │ So │");
console.Lines[03].ShouldBe("├─────┼────┼────┼────┼────┼────┼────┤");
console.Lines[04].ShouldBe("│ │ │ │ 1 │ 2 │ 3* │ 4 │");
console.Lines[05].ShouldBe("│ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │");
console.Lines[06].ShouldBe("│ 12* │ 13 │ 14 │ 15 │ 16 │ 17 │ 18 │");
console.Lines[07].ShouldBe("│ 19 │ 20 │ 21 │ 22 │ 23 │ 24 │ 25 │");
console.Lines[08].ShouldBe("│ 26 │ 27 │ 28 │ 29 │ 30 │ 31 │ │");
console.Lines[09].ShouldBe("│ │ │ │ │ │ │ │");
console.Lines[10].ShouldBe("└─────┴────┴────┴────┴────┴────┴────┘");
}
}
}

View File

@@ -228,6 +228,39 @@ namespace Spectre.Console.Tests.Unit
}
}
public sealed class TheToMarkupMethod
{
[Fact]
public void Should_Return_Expected_Markup_For_Default_Color()
{
// Given, When
var result = Color.Default.ToMarkup();
// Then
result.ShouldBe("default");
}
[Fact]
public void Should_Return_Expected_Markup_For_Known_Color()
{
// Given, When
var result = Color.Red.ToMarkup();
// Then
result.ShouldBe("red");
}
[Fact]
public void Should_Return_Expected_Markup_For_Custom_Color()
{
// Given, When
var result = new Color(255, 1, 12).ToMarkup();
// Then
result.ShouldBe("#FF010C");
}
}
public sealed class TheToStringMethod
{
[Fact]

View File

@@ -0,0 +1,99 @@
using System;
using Shouldly;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public sealed class ExceptionTests
{
[Fact]
public void Should_Write_Exception()
{
// Given
var console = new PlainConsole(width: 1024);
var dex = GetException(() => TestExceptions.MethodThatThrows(null));
// When
var result = console.WriteExceptionAndGetLines(dex);
// Then
result.Length.ShouldBe(4);
result[0].ShouldBe("System.InvalidOperationException: Throwing!");
result[1].ShouldBe(" at Spectre.Console.Tests.Data.TestExceptions.MethodThatThrows(Nullable`1 number) in /xyz/Exceptions.cs:nn");
result[2].ShouldBe(" at Spectre.Console.Tests.Unit.ExceptionTests.<>c.<Should_Write_Exception>b__0_0() in /xyz/ExceptionTests.cs:nn");
result[3].ShouldBe(" at Spectre.Console.Tests.Unit.ExceptionTests.GetException(Action action) in /xyz/ExceptionTests.cs:nn");
}
[Fact]
public void Should_Write_Exception_With_Shortened_Types()
{
// Given
var console = new PlainConsole(width: 1024);
var dex = GetException(() => TestExceptions.MethodThatThrows(null));
// When
var result = console.WriteExceptionAndGetLines(dex, ExceptionFormats.ShortenTypes);
// Then
result.Length.ShouldBe(4);
result[0].ShouldBe("InvalidOperationException: Throwing!");
result[1].ShouldBe(" at Spectre.Console.Tests.Data.TestExceptions.MethodThatThrows(Nullable`1 number) in /xyz/Exceptions.cs:nn");
result[2].ShouldBe(" at Spectre.Console.Tests.Unit.ExceptionTests.<>c.<Should_Write_Exception_With_Shortened_Types>b__1_0() in /xyz/ExceptionTests.cs:nn");
result[3].ShouldBe(" at Spectre.Console.Tests.Unit.ExceptionTests.GetException(Action action) in /xyz/ExceptionTests.cs:nn");
}
[Fact]
public void Should_Write_Exception_With_Shortened_Methods()
{
// Given
var console = new PlainConsole(width: 1024);
var dex = GetException(() => TestExceptions.MethodThatThrows(null));
// When
var result = console.WriteExceptionAndGetLines(dex, ExceptionFormats.ShortenMethods);
// Then
result.Length.ShouldBe(4);
result[0].ShouldBe("System.InvalidOperationException: Throwing!");
result[1].ShouldBe(" at MethodThatThrows(Nullable`1 number) in /xyz/Exceptions.cs:nn");
result[2].ShouldBe(" at <Should_Write_Exception_With_Shortened_Methods>b__2_0() in /xyz/ExceptionTests.cs:nn");
result[3].ShouldBe(" at GetException(Action action) in /xyz/ExceptionTests.cs:nn");
}
[Fact]
public void Should_Write_Exception_With_Inner_Exception()
{
// Given
var console = new PlainConsole(width: 1024);
var dex = GetException(() => TestExceptions.ThrowWithInnerException());
// When
var result = console.WriteExceptionAndGetLines(dex);
// Then
result.Length.ShouldBe(7);
result[0].ShouldBe("System.InvalidOperationException: Something threw!");
result[1].ShouldBe(" System.InvalidOperationException: Throwing!");
result[2].ShouldBe(" at Spectre.Console.Tests.Data.TestExceptions.MethodThatThrows(Nullable`1 number) in /xyz/Exceptions.cs:nn");
result[3].ShouldBe(" at Spectre.Console.Tests.Data.TestExceptions.ThrowWithInnerException() in /xyz/Exceptions.cs:nn");
result[4].ShouldBe(" at Spectre.Console.Tests.Data.TestExceptions.ThrowWithInnerException() in /xyz/Exceptions.cs:nn");
result[5].ShouldBe(" at Spectre.Console.Tests.Unit.ExceptionTests.<>c.<Should_Write_Exception_With_Inner_Exception>b__3_0() in /xyz/ExceptionTests.cs:nn");
result[6].ShouldBe(" at Spectre.Console.Tests.Unit.ExceptionTests.GetException(Action action) in /xyz/ExceptionTests.cs:nn");
}
public static Exception GetException(Action action)
{
try
{
action?.Invoke();
}
catch (Exception e)
{
return e;
}
throw new InvalidOperationException("Exception harness failed");
}
}
}

View File

@@ -6,6 +6,24 @@ namespace Spectre.Console.Tests.Unit
{
public sealed class MarkupTests
{
public sealed class TheEscapeMethod
{
[Theory]
[InlineData("Hello World", "Hello World")]
[InlineData("Hello World [", "Hello World [[")]
[InlineData("Hello World ]", "Hello World ]]")]
[InlineData("Hello [World]", "Hello [[World]]")]
[InlineData("Hello [[World]]", "Hello [[[[World]]]]")]
public void Should_Escape_Markup_As_Expected(string input, string expected)
{
// Given, When
var result = Markup.Escape(input);
// Then
result.ShouldBe(expected);
}
}
[Theory]
[InlineData("Hello [[ World ]")]
[InlineData("Hello [[ World ] !")]

View File

@@ -17,7 +17,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Corgi", "Waldo");
// When
console.Render(new Padder(table).SetPadding(1, 2, 3, 4));
console.Render(new Padder(table).Padding(1, 2, 3, 4));
// Then
console.Lines.Count.ShouldBe(12);
@@ -48,7 +48,7 @@ namespace Spectre.Console.Tests.Unit
// When
console.Render(new Padder(table)
.SetPadding(1, 2, 3, 4)
.Padding(1, 2, 3, 4)
.Expand());
// Then
@@ -77,11 +77,11 @@ namespace Spectre.Console.Tests.Unit
table.AddColumn("Bar", c => c.PadLeft(0).PadRight(0));
table.AddRow("Baz", "Qux");
table.AddRow(new Text("Corgi"), new Padder(new Panel("Waldo"))
.SetPadding(2, 1, 2, 1));
.Padding(2, 1, 2, 1));
// When
console.Render(new Padder(table)
.SetPadding(1, 2, 3, 4)
.Padding(1, 2, 3, 4)
.Expand());
// Then

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using Shouldly;
using Spectre.Console.Rendering;
using Xunit;
namespace Spectre.Console.Tests.Unit
@@ -242,7 +244,7 @@ namespace Spectre.Console.Tests.Unit
}
[Fact]
public void Should_Justify_Child_To_Right()
public void Should_Justify_Child_To_Right_Correctly()
{
// Given
var console = new PlainConsole(width: 25);
@@ -262,7 +264,7 @@ namespace Spectre.Console.Tests.Unit
}
[Fact]
public void Should_Justify_Child_To_Center()
public void Should_Center_Child_Correctly()
{
// Given
var console = new PlainConsole(width: 25);
@@ -298,5 +300,33 @@ namespace Spectre.Console.Tests.Unit
console.Lines[3].ShouldBe("│ └─────────────┘ │");
console.Lines[4].ShouldBe("└─────────────────┘");
}
[Fact]
public void Should_Wrap_Content_Correctly()
{
// Given
var console = new PlainConsole(width: 84);
var rows = new List<IRenderable>();
var grid = new Grid();
grid.AddColumn(new GridColumn().PadLeft(2).PadRight(0));
grid.AddColumn(new GridColumn().PadLeft(1).PadRight(0));
grid.AddRow("at", "[grey]System.Runtime.CompilerServices.TaskAwaiter.[/][yellow]HandleNonSuccessAndDebuggerNotification[/]([blue]Task[/] task)");
rows.Add(grid);
var panel = new Panel(grid)
.Expand().RoundedBorder()
.BorderStyle(new Style().Foreground(Color.Grey))
.Header("Short paths ", new Style().Foreground(Color.Grey));
// When
console.Render(panel);
// Then
console.Lines.Count.ShouldBe(4);
console.Lines[0].ShouldBe("╭─Short paths ─────────────────────────────────────────────────────────────────────╮");
console.Lines[1].ShouldBe("│ at System.Runtime.CompilerServices.TaskAwaiter. │");
console.Lines[2].ShouldBe("│ HandleNonSuccessAndDebuggerNotification(Task task) │");
console.Lines[3].ShouldBe("╰──────────────────────────────────────────────────────────────────────────────────╯");
}
}
}

View File

@@ -43,7 +43,7 @@ namespace Spectre.Console.Tests.Unit
.AddColumns("[red on black]Foo[/]", "[green bold]Bar[/]", "[blue italic]Qux[/]")
.AddRow("[invert underline]Corgi[/]", "[bold strikethrough]Waldo[/]", "[dim]Zap[/]")
.AddRow(new Panel("[blue]Hello World[/]")
.SetBorderColor(Color.Red).RoundedBorder()));
.BorderColor(Color.Red).RoundedBorder()));
// When
var html = recorder.ExportHtml();

View File

@@ -0,0 +1,125 @@
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public sealed class RuleTests
{
[Fact]
public void Should_Render_Default_Rule_Without_Title()
{
// Given
var console = new PlainConsole(width: 40);
// When
console.Render(new Rule());
// Then
console.Lines.Count.ShouldBe(1);
console.Lines[0].ShouldBe("────────────────────────────────────────");
}
[Fact]
public void Should_Render_Default_Rule_With_Title_Centered_By_Default()
{
// Given
var console = new PlainConsole(width: 40);
// When
console.Render(new Rule("Hello World"));
// Then
console.Lines.Count.ShouldBe(1);
console.Lines[0].ShouldBe("───────────── Hello World ──────────────");
}
[Fact]
public void Should_Render_Default_Rule_With_Title_Left_Aligned()
{
// Given
var console = new PlainConsole(width: 40);
// When
console.Render(new Rule("Hello World")
{
Alignment = Justify.Left,
});
// Then
console.Lines.Count.ShouldBe(1);
console.Lines[0].ShouldBe("── Hello World ─────────────────────────");
}
[Fact]
public void Should_Render_Default_Rule_With_Title_Right_Aligned()
{
// Given
var console = new PlainConsole(width: 40);
// When
console.Render(new Rule("Hello World")
{
Alignment = Justify.Right,
});
// Then
console.Lines.Count.ShouldBe(1);
console.Lines[0].ShouldBe("───────────────────────── Hello World ──");
}
[Fact]
public void Should_Convert_Line_Breaks_In_Title_To_Spaces()
{
// Given
var console = new PlainConsole(width: 40);
// When
console.Render(new Rule("Hello\nWorld\r\n!"));
// Then
console.Lines.Count.ShouldBe(1);
console.Lines[0].ShouldBe("──────────── Hello World ! ─────────────");
}
[Fact]
public void Should_Truncate_Title()
{
// Given
var console = new PlainConsole(width: 40);
// When
console.Render(new Rule(" Hello World "));
// Then
console.Lines.Count.ShouldBe(1);
console.Lines[0].ShouldBe("───────────── Hello World ──────────────");
}
[Theory]
[InlineData(0, "Hello World Hello World Hello World Hello World Hello World", "")]
[InlineData(1, "Hello World Hello World Hello World Hello World Hello World", "─")]
[InlineData(2, "Hello World Hello World Hello World Hello World Hello World", "──")]
[InlineData(3, "Hello World Hello World Hello World Hello World Hello World", "───")]
[InlineData(4, "Hello World Hello World Hello World Hello World Hello World", "────")]
[InlineData(5, "Hello World Hello World Hello World Hello World Hello World", "─────")]
[InlineData(6, "Hello World Hello World Hello World Hello World Hello World", "──────")]
[InlineData(7, "Hello World Hello World Hello World Hello World Hello World", "───────")]
[InlineData(8, "Hello World Hello World Hello World Hello World Hello World", "── H… ──")]
[InlineData(8, "A", "── A ───")]
[InlineData(8, "AB", "── AB ──")]
[InlineData(8, "ABC", "── A… ──")]
[InlineData(40, "Hello World Hello World Hello World Hello World Hello World", "──── Hello World Hello World Hello… ────")]
public void Should_Truncate_Too_Long_Title(int width, string input, string expected)
{
// Given
var console = new PlainConsole(width);
// When
console.Render(new Rule(input));
// Then
console.Lines.Count.ShouldBe(1);
console.Lines[0].ShouldBe(expected);
}
}
}

View File

@@ -1,3 +1,4 @@
using System.Text;
using Shouldly;
using Spectre.Console.Rendering;
using Xunit;
@@ -6,6 +7,16 @@ namespace Spectre.Console.Tests.Unit
{
public sealed class SegmentTests
{
[Fact]
public void Lol()
{
var context = new RenderContext(Encoding.UTF8, false);
var result = new Segment(" ").CellCount(context);
result.ShouldBe(4);
}
public sealed class TheSplitMethod
{
[Fact]
@@ -31,7 +42,10 @@ namespace Spectre.Console.Tests.Unit
[Fact]
public void Should_Split_Segment()
{
var context = new RenderContext(Encoding.UTF8, false);
var lines = Segment.SplitLines(
context,
new[]
{
new Segment("Foo"),
@@ -61,7 +75,9 @@ namespace Spectre.Console.Tests.Unit
[Fact]
public void Should_Split_Segments_With_Linebreak_In_Text()
{
var context = new RenderContext(Encoding.UTF8, false);
var lines = Segment.SplitLines(
context,
new[]
{
new Segment("Foo\n"),

View File

@@ -317,5 +317,60 @@ namespace Spectre.Console.Tests.Unit
result.ShouldBeFalse();
}
}
public sealed class TheToMarkupMethod
{
[Fact]
public void Should_Return_Expected_Markup_For_Style_With_Foreground_Color()
{
// Given
var style = new Style(Color.Red);
// When
var result = style.ToMarkup();
// Then
result.ShouldBe("red");
}
[Fact]
public void Should_Return_Expected_Markup_For_Style_With_Foreground_And_Background_Color()
{
// Given
var style = new Style(Color.Red, Color.Green);
// When
var result = style.ToMarkup();
// Then
result.ShouldBe("red on green");
}
[Fact]
public void Should_Return_Expected_Markup_For_Style_With_Foreground_And_Background_Color_And_Decoration()
{
// Given
var style = new Style(Color.Red, Color.Green, Decoration.Bold | Decoration.Underline);
// When
var result = style.ToMarkup();
// Then
result.ShouldBe("bold underline red on green");
}
[Fact]
public void Should_Return_Expected_Markup_For_Style_With_Only_Background_Color()
{
// Given
var style = new Style(background: Color.Green);
// When
var result = style.ToMarkup();
// Then
result.ShouldBe("default on green");
}
}
}
}

View File

@@ -42,10 +42,11 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(3);
console.Lines.Count.ShouldBe(4);
console.Lines[0].ShouldBe("Header 1 Header 2");
console.Lines[1].ShouldBe("Cell Cell ");
console.Lines[2].ShouldBe("Cell Cell ");
console.Lines[3].ShouldBe("Footer 1 Footer 2");
}
}
@@ -85,13 +86,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe("+---------------------+");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("|----------+----------|");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe("+---------------------+");
console.Lines[5].ShouldBe("|----------+----------|");
console.Lines[6].ShouldBe("| Footer 1 | Footer 2 |");
console.Lines[7].ShouldBe("+---------------------+");
}
}
@@ -131,13 +134,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe("+----------+----------+");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("|----------+----------|");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe("+----------+----------+");
console.Lines[5].ShouldBe("|----------+----------|");
console.Lines[6].ShouldBe("| Footer 1 | Footer 2 |");
console.Lines[7].ShouldBe("+----------+----------+");
}
}
@@ -177,13 +182,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe("+----------+----------+");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("|==========+==========|");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe("+----------+----------+");
console.Lines[6].ShouldBe("| Footer 1 | Footer 2 |");
console.Lines[7].ShouldBe("+----------+----------+");
}
}
@@ -223,13 +230,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe("┌──────────┬──────────┐");
console.Lines[1].ShouldBe("│ Header 1 │ Header 2 │");
console.Lines[2].ShouldBe("├──────────┼──────────┤");
console.Lines[3].ShouldBe("│ Cell │ Cell │");
console.Lines[4].ShouldBe("│ Cell │ Cell │");
console.Lines[5].ShouldBe("────────────────────");
console.Lines[5].ShouldBe("────────────────────");
console.Lines[6].ShouldBe("│ Footer 1 │ Footer 2 │");
console.Lines[7].ShouldBe("└──────────┴──────────┘");
}
}
@@ -269,13 +278,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe("╭──────────┬──────────╮");
console.Lines[1].ShouldBe("│ Header 1 │ Header 2 │");
console.Lines[2].ShouldBe("├──────────┼──────────┤");
console.Lines[3].ShouldBe("│ Cell │ Cell │");
console.Lines[4].ShouldBe("│ Cell │ Cell │");
console.Lines[5].ShouldBe("────────────────────");
console.Lines[5].ShouldBe("────────────────────");
console.Lines[6].ShouldBe("│ Footer 1 │ Footer 2 │");
console.Lines[7].ShouldBe("╰──────────┴──────────╯");
}
}
@@ -315,13 +326,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe(" Header 1 │ Header 2 ");
console.Lines[2].ShouldBe(" ──────────┼────────── ");
console.Lines[3].ShouldBe(" Cell │ Cell ");
console.Lines[4].ShouldBe(" Cell │ Cell ");
console.Lines[5].ShouldBe(" ");
console.Lines[5].ShouldBe(" ──────────┼────────── ");
console.Lines[6].ShouldBe(" Footer 1 │ Footer 2 ");
console.Lines[7].ShouldBe(" ");
}
}
@@ -361,13 +374,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe(" Header 1 │ Header 2 ");
console.Lines[2].ShouldBe(" ━━━━━━━━━━┿━━━━━━━━━━ ");
console.Lines[3].ShouldBe(" Cell │ Cell ");
console.Lines[4].ShouldBe(" Cell │ Cell ");
console.Lines[5].ShouldBe(" ");
console.Lines[5].ShouldBe(" ━━━━━━━━━━┿━━━━━━━━━━ ");
console.Lines[6].ShouldBe(" Footer 1 │ Footer 2 ");
console.Lines[7].ShouldBe(" ");
}
}
@@ -407,13 +422,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe(" Header 1 │ Header 2 ");
console.Lines[2].ShouldBe(" ══════════╪══════════ ");
console.Lines[3].ShouldBe(" Cell │ Cell ");
console.Lines[4].ShouldBe(" Cell │ Cell ");
console.Lines[5].ShouldBe(" ");
console.Lines[5].ShouldBe(" ══════════╪══════════ ");
console.Lines[6].ShouldBe(" Footer 1 │ Footer 2 ");
console.Lines[7].ShouldBe(" ");
}
}
@@ -453,13 +470,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe(" Header 1 Header 2 ");
console.Lines[2].ShouldBe("───────────────────────");
console.Lines[3].ShouldBe(" Cell Cell ");
console.Lines[4].ShouldBe(" Cell Cell ");
console.Lines[5].ShouldBe(" ");
console.Lines[5].ShouldBe("───────────────────────");
console.Lines[6].ShouldBe(" Footer 1 Footer 2 ");
console.Lines[7].ShouldBe(" ");
}
}
@@ -499,13 +518,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe("───────────────────────");
console.Lines[1].ShouldBe(" Header 1 Header 2 ");
console.Lines[2].ShouldBe("───────────────────────");
console.Lines[3].ShouldBe(" Cell Cell ");
console.Lines[4].ShouldBe(" Cell Cell ");
console.Lines[5].ShouldBe("───────────────────────");
console.Lines[6].ShouldBe(" Footer 1 Footer 2 ");
console.Lines[7].ShouldBe("───────────────────────");
}
}
@@ -545,13 +566,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe(" Header 1 Header 2 ");
console.Lines[2].ShouldBe("━━━━━━━━━━━━━━━━━━━━━━━");
console.Lines[3].ShouldBe(" Cell Cell ");
console.Lines[4].ShouldBe(" Cell Cell ");
console.Lines[5].ShouldBe(" ");
console.Lines[5].ShouldBe("━━━━━━━━━━━━━━━━━━━━━━━");
console.Lines[6].ShouldBe(" Footer 1 Footer 2 ");
console.Lines[7].ShouldBe(" ");
}
}
@@ -591,13 +614,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe("┏━━━━━━━━━━┳━━━━━━━━━━┓");
console.Lines[1].ShouldBe("┃ Header 1 ┃ Header 2 ┃");
console.Lines[2].ShouldBe("┣━━━━━━━━━━╋━━━━━━━━━━┫");
console.Lines[3].ShouldBe("┃ Cell ┃ Cell ┃");
console.Lines[4].ShouldBe("┃ Cell ┃ Cell ┃");
console.Lines[5].ShouldBe("━━━━━━━━━━━━━━━━━━━━");
console.Lines[5].ShouldBe("━━━━━━━━━━━━━━━━━━━━");
console.Lines[6].ShouldBe("┃ Footer 1 ┃ Footer 2 ┃");
console.Lines[7].ShouldBe("┗━━━━━━━━━━┻━━━━━━━━━━┛");
}
}
@@ -637,13 +662,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe("┏━━━━━━━━━━┯━━━━━━━━━━┓");
console.Lines[1].ShouldBe("┃ Header 1 │ Header 2 ┃");
console.Lines[2].ShouldBe("┠──────────┼──────────┨");
console.Lines[3].ShouldBe("┃ Cell │ Cell ┃");
console.Lines[4].ShouldBe("┃ Cell │ Cell ┃");
console.Lines[5].ShouldBe("┗━━━━━━━━━━┷━━━━━━━━━━┛");
console.Lines[5].ShouldBe("┠──────────┼──────────┨");
console.Lines[6].ShouldBe("┃ Footer 1 │ Footer 2 ┃");
console.Lines[7].ShouldBe("┗━━━━━━━━━━┷━━━━━━━━━━┛");
}
}
@@ -683,13 +710,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe("┏━━━━━━━━━━┳━━━━━━━━━━┓");
console.Lines[1].ShouldBe("┃ Header 1 ┃ Header 2 ┃");
console.Lines[2].ShouldBe("┡━━━━━━━━━━╇━━━━━━━━━━┩");
console.Lines[3].ShouldBe("│ Cell │ Cell │");
console.Lines[4].ShouldBe("│ Cell │ Cell │");
console.Lines[5].ShouldBe("────────────────────");
console.Lines[5].ShouldBe("────────────────────");
console.Lines[6].ShouldBe("│ Footer 1 │ Footer 2 │");
console.Lines[7].ShouldBe("└──────────┴──────────┘");
}
}
@@ -729,13 +758,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe("╔══════════╦══════════╗");
console.Lines[1].ShouldBe("║ Header 1 ║ Header 2 ║");
console.Lines[2].ShouldBe("╠══════════╬══════════╣");
console.Lines[3].ShouldBe("║ Cell ║ Cell ║");
console.Lines[4].ShouldBe("║ Cell ║ Cell ║");
console.Lines[5].ShouldBe("════════════════════");
console.Lines[5].ShouldBe("════════════════════");
console.Lines[6].ShouldBe("║ Footer 1 ║ Footer 2 ║");
console.Lines[7].ShouldBe("╚══════════╩══════════╝");
}
}
@@ -775,13 +806,15 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe("╔══════════╤══════════╗");
console.Lines[1].ShouldBe("║ Header 1 │ Header 2 ║");
console.Lines[2].ShouldBe("╟──────────┼──────────╢");
console.Lines[3].ShouldBe("║ Cell │ Cell ║");
console.Lines[4].ShouldBe("║ Cell │ Cell ║");
console.Lines[5].ShouldBe("╚══════════╧══════════╝");
console.Lines[5].ShouldBe("╟──────────┼──────────╢");
console.Lines[6].ShouldBe("║ Footer 1 │ Footer 2 ║");
console.Lines[7].ShouldBe("╚══════════╧══════════╝");
}
}
@@ -821,13 +854,14 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(7);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("| -------- | -------- |");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe(" ");
console.Lines[5].ShouldBe("| Footer 1 | Footer 2 |");
console.Lines[6].ShouldBe(" ");
}
[Fact]
@@ -841,13 +875,14 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(7);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("| -------- | :------- |");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe(" ");
console.Lines[5].ShouldBe("| Footer 1 | Footer 2 |");
console.Lines[6].ShouldBe(" ");
}
[Fact]
@@ -861,13 +896,14 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(7);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("| -------- | :------: |");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe(" ");
console.Lines[5].ShouldBe("| Footer 1 | Footer 2 |");
console.Lines[6].ShouldBe(" ");
}
[Fact]
@@ -881,13 +917,14 @@ namespace Spectre.Console.Tests.Unit
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines.Count.ShouldBe(7);
console.Lines[0].ShouldBe(" ");
console.Lines[1].ShouldBe("| Header 1 | Header 2 |");
console.Lines[2].ShouldBe("| -------- | -------: |");
console.Lines[3].ShouldBe("| Cell | Cell |");
console.Lines[4].ShouldBe("| Cell | Cell |");
console.Lines[5].ShouldBe(" ");
console.Lines[5].ShouldBe("| Footer 1 | Footer 2 |");
console.Lines[6].ShouldBe(" ");
}
}
@@ -896,8 +933,8 @@ namespace Spectre.Console.Tests.Unit
public static Table GetTable(Justify? header1 = null, Justify? header2 = null)
{
var table = new Table();
table.AddColumn("Header 1", c => c.Alignment = header1);
table.AddColumn("Header 2", c => c.Alignment = header2);
table.AddColumn("Header 1", c => c.Alignment(header1).Footer("Footer 1"));
table.AddColumn("Header 2", c => c.Alignment(header2).Footer("Footer 2"));
table.AddRow("Cell", "Cell");
table.AddRow("Cell", "Cell");
return table;

View File

@@ -168,6 +168,105 @@ namespace Spectre.Console.Tests.Unit
console.Lines[5].ShouldBe("└────────┴────────┴───────┘");
}
[Fact]
public void Should_Render_Table_With_Footers_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table();
table.AddColumn(new TableColumn("Foo").Footer("Oof").RightAligned());
table.AddColumn("Bar");
table.AddColumns(new TableColumn("Baz").Footer("Zab"));
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe("┌────────┬────────┬───────┐");
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
console.Lines[2].ShouldBe("├────────┼────────┼───────┤");
console.Lines[3].ShouldBe("│ Qux │ Corgi │ Waldo │");
console.Lines[4].ShouldBe("│ Grault │ Garply │ Fred │");
console.Lines[5].ShouldBe("├────────┼────────┼───────┤");
console.Lines[6].ShouldBe("│ Oof │ │ Zab │");
console.Lines[7].ShouldBe("└────────┴────────┴───────┘");
}
[Fact]
public void Should_Left_Align_Table_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table();
table.Alignment = Justify.Left;
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("┌────────┬────────┬───────┐");
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
console.Lines[2].ShouldBe("├────────┼────────┼───────┤");
console.Lines[3].ShouldBe("│ Qux │ Corgi │ Waldo │");
console.Lines[4].ShouldBe("│ Grault │ Garply │ Fred │");
console.Lines[5].ShouldBe("└────────┴────────┴───────┘");
}
[Fact]
public void Should_Center_Table_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table();
table.Alignment = Justify.Center;
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe(" ┌────────┬────────┬───────┐ ");
console.Lines[1].ShouldBe(" │ Foo │ Bar │ Baz │ ");
console.Lines[2].ShouldBe(" ├────────┼────────┼───────┤ ");
console.Lines[3].ShouldBe(" │ Qux │ Corgi │ Waldo │ ");
console.Lines[4].ShouldBe(" │ Grault │ Garply │ Fred │ ");
console.Lines[5].ShouldBe(" └────────┴────────┴───────┘ ");
}
[Fact]
public void Should_Right_Align_Table_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table();
table.Alignment = Justify.Right;
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe(" ┌────────┬────────┬───────┐");
console.Lines[1].ShouldBe(" │ Foo │ Bar │ Baz │");
console.Lines[2].ShouldBe(" ├────────┼────────┼───────┤");
console.Lines[3].ShouldBe(" │ Qux │ Corgi │ Waldo │");
console.Lines[4].ShouldBe(" │ Grault │ Garply │ Fred │");
console.Lines[5].ShouldBe(" └────────┴────────┴───────┘");
}
[Fact]
public void Should_Render_Table_Nested_In_Panels_Correctly()
{
@@ -250,52 +349,6 @@ namespace Spectre.Console.Tests.Unit
console.Lines[5].ShouldBe("└───────────────────────────┴───────────────────────────┴──────────────────────┘");
}
[Fact]
public void Should_Render_Table_With_Ascii_Border_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table { Border = TableBorder.Ascii };
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("+-------------------------+");
console.Lines[1].ShouldBe("| Foo | Bar | Baz |");
console.Lines[2].ShouldBe("|--------+--------+-------|");
console.Lines[3].ShouldBe("| Qux | Corgi | Waldo |");
console.Lines[4].ShouldBe("| Grault | Garply | Fred |");
console.Lines[5].ShouldBe("+-------------------------+");
}
[Fact]
public void Should_Render_Table_With_Rounded_Border_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table { Border = TableBorder.Rounded };
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(6);
console.Lines[0].ShouldBe("╭────────┬────────┬───────╮");
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
console.Lines[2].ShouldBe("├────────┼────────┼───────┤");
console.Lines[3].ShouldBe("│ Qux │ Corgi │ Waldo │");
console.Lines[4].ShouldBe("│ Grault │ Garply │ Fred │");
console.Lines[5].ShouldBe("╰────────┴────────┴───────╯");
}
[Fact]
public void Should_Render_Table_With_No_Border_Correctly()
{
@@ -383,5 +436,165 @@ namespace Spectre.Console.Tests.Unit
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
console.Lines[2].ShouldBe("└─────┴─────┴────────┘");
}
[Fact]
public void Should_Not_Draw_Tables_That_Are_Impossible_To_Draw()
{
// Given
var console = new PlainConsole(width: 25);
var first = new Table().Border(TableBorder.Rounded).BorderColor(Color.Red);
first.AddColumn(new TableColumn("[u]PS1[/]").Centered());
first.AddColumn(new TableColumn("[u]PS2[/]"));
first.AddColumn(new TableColumn("[u]PS3[/]"));
first.AddRow("Hello", "[red]World[/]", string.Empty);
first.AddRow("[blue]Bonjour[/]", "[white]le[/]", "[red]monde![/]");
first.AddRow("[blue]Hej[/]", "[yellow]Världen[/]", string.Empty);
var second = new Table().Border(TableBorder.Square).BorderColor(Color.Green);
second.AddColumn(new TableColumn("[u]Foo[/]"));
second.AddColumn(new TableColumn("[u]Bar[/]"));
second.AddColumn(new TableColumn("[u]Baz[/]"));
second.AddRow("Hello", "[red]World[/]", string.Empty);
second.AddRow(first, new Text("Whaaat"), new Text("Lolz"));
second.AddRow("[blue]Hej[/]", "[yellow]Världen[/]", string.Empty);
var table = new Table().Border(TableBorder.Rounded);
table.AddColumn(new TableColumn(new Panel("[u]ABC[/]").BorderColor(Color.Red)));
table.AddColumn(new TableColumn(new Panel("[u]DEF[/]").BorderColor(Color.Green)));
table.AddColumn(new TableColumn(new Panel("[u]GHI[/]").BorderColor(Color.Blue)));
table.AddRow(new Text("Hello").Centered(), new Markup("[red]World[/]"), Text.Empty);
table.AddRow(second, new Text("Whaat"), new Text("Lol").RightAligned());
table.AddRow(new Markup("[blue]Hej[/]"), new Markup("[yellow]Världen[/]"), Text.Empty);
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(12);
console.Lines[00].ShouldBe("╭───────┬───────┬───────╮");
console.Lines[01].ShouldBe("│ ┌───┐ │ ┌───┐ │ ┌───┐ │");
console.Lines[02].ShouldBe("│ │ A │ │ │ D │ │ │ G │ │");
console.Lines[03].ShouldBe("│ │ B │ │ │ E │ │ │ H │ │");
console.Lines[04].ShouldBe("│ │ C │ │ │ F │ │ │ I │ │");
console.Lines[05].ShouldBe("│ └───┘ │ └───┘ │ └───┘ │");
console.Lines[06].ShouldBe("├───────┼───────┼───────┤");
console.Lines[07].ShouldBe("│ Hello │ World │ │");
console.Lines[08].ShouldBe("│ … │ Whaat │ Lol │");
console.Lines[09].ShouldBe("│ Hej │ Värld │ │");
console.Lines[10].ShouldBe("│ │ en │ │");
console.Lines[11].ShouldBe("╰───────┴───────┴───────╯");
}
[Fact]
public void Should_Render_Table_With_Title_And_Caption_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table { Border = TableBorder.Rounded };
table.Title = new TableTitle("Hello World");
table.Caption = new TableTitle("Goodbye World");
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe(" Hello World ");
console.Lines[1].ShouldBe("╭────────┬────────┬───────╮");
console.Lines[2].ShouldBe("│ Foo │ Bar │ Baz │");
console.Lines[3].ShouldBe("├────────┼────────┼───────┤");
console.Lines[4].ShouldBe("│ Qux │ Corgi │ Waldo │");
console.Lines[5].ShouldBe("│ Grault │ Garply │ Fred │");
console.Lines[6].ShouldBe("╰────────┴────────┴───────╯");
console.Lines[7].ShouldBe(" Goodbye World ");
}
[Fact]
public void Should_Left_Align_Table_With_Title_And_Caption_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table { Border = TableBorder.Rounded };
table.LeftAligned();
table.Title = new TableTitle("Hello World");
table.Caption = new TableTitle("Goodbye World");
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe(" Hello World ");
console.Lines[1].ShouldBe("╭────────┬────────┬───────╮");
console.Lines[2].ShouldBe("│ Foo │ Bar │ Baz │");
console.Lines[3].ShouldBe("├────────┼────────┼───────┤");
console.Lines[4].ShouldBe("│ Qux │ Corgi │ Waldo │");
console.Lines[5].ShouldBe("│ Grault │ Garply │ Fred │");
console.Lines[6].ShouldBe("╰────────┴────────┴───────╯");
console.Lines[7].ShouldBe(" Goodbye World ");
}
[Fact]
public void Should_Center_Table_With_Title_And_Caption_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table { Border = TableBorder.Rounded };
table.Centered();
table.Title = new TableTitle("Hello World");
table.Caption = new TableTitle("Goodbye World");
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe(" Hello World ");
console.Lines[1].ShouldBe(" ╭────────┬────────┬───────╮ ");
console.Lines[2].ShouldBe(" │ Foo │ Bar │ Baz │ ");
console.Lines[3].ShouldBe(" ├────────┼────────┼───────┤ ");
console.Lines[4].ShouldBe(" │ Qux │ Corgi │ Waldo │ ");
console.Lines[5].ShouldBe(" │ Grault │ Garply │ Fred │ ");
console.Lines[6].ShouldBe(" ╰────────┴────────┴───────╯ ");
console.Lines[7].ShouldBe(" Goodbye World ");
}
[Fact]
public void Should_Right_Align_Table_With_Title_And_Caption_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
var table = new Table { Border = TableBorder.Rounded };
table.RightAligned();
table.Title = new TableTitle("Hello World");
table.Caption = new TableTitle("Goodbye World");
table.AddColumns("Foo", "Bar", "Baz");
table.AddRow("Qux", "Corgi", "Waldo");
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
// Then
console.Lines.Count.ShouldBe(8);
console.Lines[0].ShouldBe(" Hello World ");
console.Lines[1].ShouldBe(" ╭────────┬────────┬───────╮");
console.Lines[2].ShouldBe(" │ Foo │ Bar │ Baz │");
console.Lines[3].ShouldBe(" ├────────┼────────┼───────┤");
console.Lines[4].ShouldBe(" │ Qux │ Corgi │ Waldo │");
console.Lines[5].ShouldBe(" │ Grault │ Garply │ Fred │");
console.Lines[6].ShouldBe(" ╰────────┴────────┴───────╯");
console.Lines[7].ShouldBe(" Goodbye World ");
}
}
}

View File

@@ -108,7 +108,7 @@ namespace Spectre.Console.Tests.Unit
// Given
var console = new PlainConsole(14);
var text = new Text("foo pneumonoultramicroscopicsilicovolcanoconiosis bar qux")
.SetOverflow(overflow);
.Overflow(overflow);
// When
console.Render(text);

View File

@@ -35,6 +35,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Links", "..\examples\Links\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emojis", "..\examples\Emojis\Emojis.csproj", "{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Exceptions", "..\examples\Exceptions\Exceptions.csproj", "{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHub", "GitHub", "{C3E2CB5C-1517-4C75-B59A-93D4E22BEC8D}"
ProjectSection(SolutionItems) = preProject
..\.github\workflows\ci.yaml = ..\.github\workflows\ci.yaml
..\.github\workflows\docs.yaml = ..\.github\workflows\docs.yaml
..\.github\workflows\publish.yaml = ..\.github\workflows\publish.yaml
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Calendars", "..\examples\Calendars\Calendars.csproj", "{57691C7D-683D-46E6-AA4F-57A8C5F65D25}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rules", "..\examples\Rules\Rules.csproj", "{8622A261-02C6-40CA-9797-E3F01ED87D6B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -177,6 +190,42 @@ Global
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|x64.Build.0 = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|x86.ActiveCfg = Release|Any CPU
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2}.Release|x86.Build.0 = Release|Any CPU
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}.Debug|x64.ActiveCfg = Debug|Any CPU
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}.Debug|x64.Build.0 = Debug|Any CPU
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}.Debug|x86.ActiveCfg = Debug|Any CPU
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}.Debug|x86.Build.0 = Debug|Any CPU
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}.Release|Any CPU.Build.0 = Release|Any CPU
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}.Release|x64.ActiveCfg = Release|Any CPU
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}.Release|x64.Build.0 = Release|Any CPU
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}.Release|x86.ActiveCfg = Release|Any CPU
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32}.Release|x86.Build.0 = Release|Any CPU
{57691C7D-683D-46E6-AA4F-57A8C5F65D25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{57691C7D-683D-46E6-AA4F-57A8C5F65D25}.Debug|Any CPU.Build.0 = Debug|Any CPU
{57691C7D-683D-46E6-AA4F-57A8C5F65D25}.Debug|x64.ActiveCfg = Debug|Any CPU
{57691C7D-683D-46E6-AA4F-57A8C5F65D25}.Debug|x64.Build.0 = Debug|Any CPU
{57691C7D-683D-46E6-AA4F-57A8C5F65D25}.Debug|x86.ActiveCfg = Debug|Any CPU
{57691C7D-683D-46E6-AA4F-57A8C5F65D25}.Debug|x86.Build.0 = Debug|Any CPU
{57691C7D-683D-46E6-AA4F-57A8C5F65D25}.Release|Any CPU.ActiveCfg = Release|Any CPU
{57691C7D-683D-46E6-AA4F-57A8C5F65D25}.Release|Any CPU.Build.0 = Release|Any CPU
{57691C7D-683D-46E6-AA4F-57A8C5F65D25}.Release|x64.ActiveCfg = Release|Any CPU
{57691C7D-683D-46E6-AA4F-57A8C5F65D25}.Release|x64.Build.0 = Release|Any CPU
{57691C7D-683D-46E6-AA4F-57A8C5F65D25}.Release|x86.ActiveCfg = Release|Any CPU
{57691C7D-683D-46E6-AA4F-57A8C5F65D25}.Release|x86.Build.0 = Release|Any CPU
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Debug|x64.ActiveCfg = Debug|Any CPU
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Debug|x64.Build.0 = Debug|Any CPU
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Debug|x86.ActiveCfg = Debug|Any CPU
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Debug|x86.Build.0 = Debug|Any CPU
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Release|Any CPU.Build.0 = Release|Any CPU
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Release|x64.ActiveCfg = Release|Any CPU
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Release|x64.Build.0 = Release|Any CPU
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Release|x86.ActiveCfg = Release|Any CPU
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -191,6 +240,10 @@ Global
{094245E6-4C94-485D-B5AC-3153E878B112} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{6AF8C93B-AA41-4F44-8B1B-B8D166576174} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{1EABB956-957F-4C1A-8AC0-FD19C8F3C2F2} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{90C081A7-7C1D-4A4A-82B6-8FF473C3EA32} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{C3E2CB5C-1517-4C75-B59A-93D4E22BEC8D} = {20595AD4-8D75-4AF8-B6BC-9C38C160423F}
{57691C7D-683D-46E6-AA4F-57A8C5F65D25} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
{8622A261-02C6-40CA-9797-E3F01ED87D6B} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5729B071-67A0-48FB-8B1B-275E6822086C}

View File

@@ -0,0 +1,30 @@
using System;
namespace Spectre.Console
{
/// <summary>
/// A console capable of writing ANSI escape sequences.
/// </summary>
public static partial class AnsiConsole
{
/// <summary>
/// Writes an exception to the console.
/// </summary>
/// <param name="exception">The exception to write to the console.</param>
/// <param name="format">The exception format options.</param>
public static void WriteException(Exception exception, ExceptionFormats format = ExceptionFormats.Default)
{
Console.WriteException(exception, format);
}
/// <summary>
/// Writes an exception to the console.
/// </summary>
/// <param name="exception">The exception to write to the console.</param>
/// <param name="settings">The exception settings.</param>
public static void WriteException(Exception exception, ExceptionSettings settings)
{
Console.WriteException(exception, settings);
}
}
}

View File

@@ -1,7 +1,3 @@
using System;
using System.IO;
using Spectre.Console.Internal;
namespace Spectre.Console
{
/// <summary>
@@ -9,9 +5,6 @@ namespace Spectre.Console
/// </summary>
public static partial class AnsiConsole
{
private static ConsoleColor _defaultForeground;
private static ConsoleColor _defaultBackground;
internal static Style CurrentStyle { get; private set; } = Style.Plain;
internal static bool Created { get; private set; }
@@ -21,7 +14,7 @@ namespace Spectre.Console
public static Color Foreground
{
get => CurrentStyle.Foreground;
set => CurrentStyle = CurrentStyle.WithForeground(value);
set => CurrentStyle = CurrentStyle.Foreground(value);
}
/// <summary>
@@ -30,7 +23,7 @@ namespace Spectre.Console
public static Color Background
{
get => CurrentStyle.Background;
set => CurrentStyle = CurrentStyle.WithBackground(value);
set => CurrentStyle = CurrentStyle.Background(value);
}
/// <summary>
@@ -39,21 +32,7 @@ namespace Spectre.Console
public static Decoration Decoration
{
get => CurrentStyle.Decoration;
set => CurrentStyle = CurrentStyle.WithDecoration(value);
}
internal static void Initialize(TextWriter? @out)
{
if (@out?.IsStandardOut() ?? false)
{
Foreground = _defaultForeground = System.Console.ForegroundColor;
Background = _defaultBackground = System.Console.BackgroundColor;
}
else
{
Foreground = _defaultForeground = Color.Silver;
Background = _defaultBackground = Color.Black;
}
set => CurrentStyle = CurrentStyle.Decoration(value);
}
/// <summary>
@@ -78,8 +57,7 @@ namespace Spectre.Console
/// </summary>
public static void ResetColors()
{
Foreground = _defaultForeground;
Background = _defaultBackground;
CurrentStyle = Style.Plain;
}
}
}

View File

@@ -16,7 +16,6 @@ namespace Spectre.Console
ColorSystem = ColorSystemSupport.Detect,
Out = System.Console.Out,
});
Initialize(System.Console.Out);
Created = true;
return console;
});

View File

@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Spectre.Console.Rendering;
namespace Spectre.Console
@@ -11,70 +7,16 @@ namespace Spectre.Console
/// </summary>
public abstract partial class BoxBorder
{
private readonly Dictionary<BoxBorderPart, string> _lookup;
/// <summary>
/// Gets the safe border for this border or <c>null</c> if none exist.
/// </summary>
public virtual BoxBorder? SafeBorder { get; }
/// <summary>
/// Initializes a new instance of the <see cref="BoxBorder"/> class.
/// </summary>
protected BoxBorder()
{
_lookup = Initialize();
}
private Dictionary<BoxBorderPart, string> Initialize()
{
var lookup = new Dictionary<BoxBorderPart, string>();
foreach (BoxBorderPart? part in Enum.GetValues(typeof(BoxBorderPart)))
{
if (part == null)
{
continue;
}
var text = GetBorderPart(part.Value);
if (text.Length > 1)
{
throw new InvalidOperationException("A box part cannot contain more than one character.");
}
lookup.Add(part.Value, GetBorderPart(part.Value));
}
return lookup;
}
/// <summary>
/// Gets the string representation of a specific border part.
/// </summary>
/// <param name="part">The part to get a string representation for.</param>
/// <param name="count">The number of repetitions.</param>
/// <returns>A string representation of the specified border part.</returns>
public string GetPart(BoxBorderPart part, int count)
{
// TODO: This need some optimization...
return string.Join(string.Empty, Enumerable.Repeat(GetBorderPart(part)[0], count));
}
/// <summary>
/// Gets the string representation of a specific border part.
/// </summary>
/// <param name="part">The part to get a string representation for.</param>
/// <returns>A string representation of the specified border part.</returns>
public string GetPart(BoxBorderPart part)
{
return _lookup[part].ToString(CultureInfo.InvariantCulture);
}
/// <summary>
/// Gets the character representing the specified border part.
/// Gets the string representation of the specified border part.
/// </summary>
/// <param name="part">The part to get the character representation for.</param>
/// <returns>A character representation of the specified border part.</returns>
protected abstract string GetBorderPart(BoxBorderPart part);
public abstract string GetPart(BoxBorderPart part);
}
}

View File

@@ -245,9 +245,37 @@ namespace Spectre.Console
};
}
/// <summary>
/// Converts the color to a markup string.
/// </summary>
/// <returns>A <see cref="string"/> representing the color as markup.</returns>
public string ToMarkup()
{
if (IsDefault)
{
return "default";
}
if (Number != null)
{
var name = ColorTable.GetName(Number.Value);
if (!string.IsNullOrWhiteSpace(name))
{
return name;
}
}
return string.Format(CultureInfo.InvariantCulture, "#{0:X2}{1:X2}{2:X2}", R, G, B);
}
/// <inheritdoc/>
public override string ToString()
{
if (IsDefault)
{
return "default";
}
if (Number != null)
{
var name = ColorTable.GetName(Number.Value);

View File

@@ -1,3 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Spectre.Console
@@ -8,6 +10,35 @@ namespace Spectre.Console
public static partial class Emoji
{
private static readonly Regex _emojiCode = new Regex(@"(:(\S*?):)", RegexOptions.Compiled);
private static readonly Dictionary<string, string> _remappings;
static Emoji()
{
_remappings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// Remaps a specific emoji tag with a new emoji.
/// </summary>
/// <param name="tag">The emoji tag.</param>
/// <param name="emoji">The emoji.</param>
public static void Remap(string tag, string emoji)
{
if (tag is null)
{
throw new ArgumentNullException(nameof(tag));
}
if (emoji is null)
{
throw new ArgumentNullException(nameof(emoji));
}
tag = tag.TrimStart(':').TrimEnd(':');
emoji = emoji.TrimStart(':').TrimEnd(':');
_remappings[tag] = emoji;
}
/// <summary>
/// Replaces emoji markup with corresponding unicode characters.
@@ -16,7 +47,23 @@ namespace Spectre.Console
/// <returns>A string with emoji codes replaced with actual emoji.</returns>
public static string Replace(string value)
{
static string ReplaceEmoji(Match match) => _emojis[match.Groups[2].Value];
static string ReplaceEmoji(Match match)
{
var key = match.Groups[2].Value;
if (_remappings.Count > 0 && _remappings.TryGetValue(key, out var remappedEmoji))
{
return remappedEmoji;
}
if (_emojis.TryGetValue(key, out var emoji))
{
return emoji;
}
return match.Value;
}
return _emojiCode.Replace(value, ReplaceEmoji);
}
}

View File

@@ -0,0 +1,41 @@
using System;
namespace Spectre.Console
{
/// <summary>
/// Represents how an exception is formatted.
/// </summary>
[Flags]
public enum ExceptionFormats
{
/// <summary>
/// The default formatting.
/// </summary>
Default = 0,
/// <summary>
/// Whether or not paths should be shortened.
/// </summary>
ShortenPaths = 1,
/// <summary>
/// Whether or not types should be shortened.
/// </summary>
ShortenTypes = 2,
/// <summary>
/// Whether or not methods should be shortened.
/// </summary>
ShortenMethods = 4,
/// <summary>
/// Whether or not to show paths as links in the terminal.
/// </summary>
ShowLinks = 8,
/// <summary>
/// Shortens everything that can be shortened.
/// </summary>
ShortenEverything = ShortenMethods | ShortenTypes | ShortenPaths,
}
}

View File

@@ -0,0 +1,27 @@
namespace Spectre.Console
{
/// <summary>
/// Exception settings.
/// </summary>
public sealed class ExceptionSettings
{
/// <summary>
/// Gets or sets the exception format.
/// </summary>
public ExceptionFormats Format { get; set; }
/// <summary>
/// Gets or sets the exception style.
/// </summary>
public ExceptionStyle Style { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ExceptionSettings"/> class.
/// </summary>
public ExceptionSettings()
{
Format = ExceptionFormats.Default;
Style = new ExceptionStyle();
}
}
}

View File

@@ -0,0 +1,58 @@
namespace Spectre.Console
{
/// <summary>
/// Represent an exception style.
/// </summary>
public sealed class ExceptionStyle
{
/// <summary>
/// Gets or sets the message color.
/// </summary>
public Style Message { get; set; } = new Style(Color.Red, Color.Default, Decoration.Bold);
/// <summary>
/// Gets or sets the exception color.
/// </summary>
public Style Exception { get; set; } = new Style(Color.White);
/// <summary>
/// Gets or sets the method color.
/// </summary>
public Style Method { get; set; } = new Style(Color.Yellow);
/// <summary>
/// Gets or sets the parameter type color.
/// </summary>
public Style ParameterType { get; set; } = new Style(Color.Blue);
/// <summary>
/// Gets or sets the parameter name color.
/// </summary>
public Style ParameterName { get; set; } = new Style(Color.Silver);
/// <summary>
/// Gets or sets the parenthesis color.
/// </summary>
public Style Parenthesis { get; set; } = new Style(Color.Silver);
/// <summary>
/// Gets or sets the path color.
/// </summary>
public Style Path { get; set; } = new Style(Color.Yellow, Color.Default, Decoration.Bold);
/// <summary>
/// Gets or sets the line number color.
/// </summary>
public Style LineNumber { get; set; } = new Style(Color.Blue);
/// <summary>
/// Gets or sets the color for dimmed text such as "at" or "in".
/// </summary>
public Style Dimmed { get; set; } = new Style(Color.Grey);
/// <summary>
/// Gets or sets the color for non emphasized items.
/// </summary>
public Style NonEmphasized { get; set; } = new Style(Color.Silver);
}
}

View File

@@ -12,7 +12,7 @@ namespace Spectre.Console
/// <param name="obj">The alignable object.</param>
/// <param name="alignment">The alignment.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static T SetAlignment<T>(this T obj, Justify alignment)
public static T Alignment<T>(this T obj, Justify? alignment)
where T : class, IAlignable
{
if (obj is null)

View File

@@ -0,0 +1,32 @@
using System;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="IAnsiConsole"/>.
/// </summary>
public static partial class AnsiConsoleExtensions
{
/// <summary>
/// Writes an exception to the console.
/// </summary>
/// <param name="console">The console.</param>
/// <param name="exception">The exception to write to the console.</param>
/// <param name="format">The exception format options.</param>
public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionFormats format = ExceptionFormats.Default)
{
Render(console, exception.GetRenderable(format));
}
/// <summary>
/// Writes an exception to the console.
/// </summary>
/// <param name="console">The console.</param>
/// <param name="exception">The exception to write to the console.</param>
/// <param name="settings">The exception settings.</param>
public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionSettings settings)
{
Render(console, exception.GetRenderable(settings));
}
}
}

View File

@@ -27,10 +27,9 @@ namespace Spectre.Console
}
var options = new RenderContext(console.Encoding, console.Capabilities.LegacyConsole);
var segments = renderable.Render(options, console.Width).Where(x => !(x.Text.Length == 0 && !x.IsLineBreak)).ToArray();
var segments = renderable.Render(options, console.Width).ToArray();
segments = Segment.Merge(segments).ToArray();
var current = Style.Plain;
foreach (var segment in segments)
{
if (string.IsNullOrEmpty(segment.Text))

View File

@@ -0,0 +1,100 @@
using System;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="Calendar"/>.
/// </summary>
public static class CalendarExtensions
{
/// <summary>
/// Adds a calendar event.
/// </summary>
/// <param name="calendar">The calendar to add the calendar event to.</param>
/// <param name="date">The calendar event date.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static Calendar AddCalendarEvent(this Calendar calendar, DateTime date)
{
return AddCalendarEvent(calendar, string.Empty, date.Year, date.Month, date.Day);
}
/// <summary>
/// Adds a calendar event.
/// </summary>
/// <param name="calendar">The calendar to add the calendar event to.</param>
/// <param name="description">The calendar event description.</param>
/// <param name="date">The calendar event date.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static Calendar AddCalendarEvent(this Calendar calendar, string description, DateTime date)
{
return AddCalendarEvent(calendar, description, date.Year, date.Month, date.Day);
}
/// <summary>
/// Adds a calendar event.
/// </summary>
/// <param name="calendar">The calendar to add the calendar event to.</param>
/// <param name="year">The year of the calendar event.</param>
/// <param name="month">The month of the calendar event.</param>
/// <param name="day">The day of the calendar event.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static Calendar AddCalendarEvent(this Calendar calendar, int year, int month, int day)
{
return AddCalendarEvent(calendar, string.Empty, year, month, day);
}
/// <summary>
/// Adds a calendar event.
/// </summary>
/// <param name="calendar">The calendar.</param>
/// <param name="description">The calendar event description.</param>
/// <param name="year">The year of the calendar event.</param>
/// <param name="month">The month of the calendar event.</param>
/// <param name="day">The day of the calendar event.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static Calendar AddCalendarEvent(this Calendar calendar, string description, int year, int month, int day)
{
if (calendar is null)
{
throw new ArgumentNullException(nameof(calendar));
}
calendar.CalendarEvents.Add(new CalendarEvent(description, year, month, day));
return calendar;
}
/// <summary>
/// Sets the calendar's highlight <see cref="Style"/>.
/// </summary>
/// <param name="calendar">The calendar.</param>
/// <param name="style">The highlight style.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static Calendar HighlightStyle(this Calendar calendar, Style? style)
{
if (calendar is null)
{
throw new ArgumentNullException(nameof(calendar));
}
calendar.HightlightStyle = style ?? Style.Plain;
return calendar;
}
/// <summary>
/// Sets the calendar's header <see cref="Style"/>.
/// </summary>
/// <param name="calendar">The calendar.</param>
/// <param name="style">The header style.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static Calendar HeaderStyle(this Calendar calendar, Style? style)
{
if (calendar is null)
{
throw new ArgumentNullException(nameof(calendar));
}
calendar.HeaderStyle = style ?? Style.Plain;
return calendar;
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using Spectre.Console.Rendering;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="Exception"/>.
/// </summary>
public static class ExceptionExtensions
{
/// <summary>
/// Gets a <see cref="IRenderable"/> representation of the exception.
/// </summary>
/// <param name="exception">The exception to format.</param>
/// <param name="format">The exception format options.</param>
/// <returns>A <see cref="IRenderable"/> representing the exception.</returns>
public static IRenderable GetRenderable(this Exception exception, ExceptionFormats format = ExceptionFormats.Default)
{
if (exception is null)
{
throw new ArgumentNullException(nameof(exception));
}
return GetRenderable(exception, new ExceptionSettings
{
Format = format,
});
}
/// <summary>
/// Gets a <see cref="IRenderable"/> representation of the exception.
/// </summary>
/// <param name="exception">The exception to format.</param>
/// <param name="settings">The exception settings.</param>
/// <returns>A <see cref="IRenderable"/> representing the exception.</returns>
public static IRenderable GetRenderable(this Exception exception, ExceptionSettings settings)
{
if (exception is null)
{
throw new ArgumentNullException(nameof(exception));
}
if (settings is null)
{
throw new ArgumentNullException(nameof(settings));
}
return ExceptionFormatter.Format(exception, settings);
}
}
}

View File

@@ -17,7 +17,12 @@ namespace Spectre.Console
public static T Collapse<T>(this T obj)
where T : class, IExpandable
{
SetExpand<T>(obj, false);
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Expand = false;
return obj;
}
@@ -29,20 +34,14 @@ namespace Spectre.Console
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static T Expand<T>(this T obj)
where T : class, IExpandable
{
SetExpand<T>(obj, true);
return obj;
}
private static void SetExpand<T>(T obj, bool value)
where T : class, IExpandable
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Expand = value;
obj.Expand = true;
return obj;
}
}
}

View File

@@ -7,11 +7,29 @@ namespace Spectre.Console
/// </summary>
public static class HasBorderExtensions
{
/// <summary>
/// Enables the safe border.
/// </summary>
/// <typeparam name="T">An object type with a border.</typeparam>
/// <param name="obj">The object to enable the safe border for.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static T SafeBorder<T>(this T obj)
where T : class, IHasBorder
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.UseSafeBorder = true;
return obj;
}
/// <summary>
/// Disables the safe border.
/// </summary>
/// <typeparam name="T">An object type with a border.</typeparam>
/// <param name="obj">The object to set the border for.</param>
/// <param name="obj">The object to disable the safe border for.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static T NoSafeBorder<T>(this T obj)
where T : class, IHasBorder
@@ -29,10 +47,10 @@ namespace Spectre.Console
/// 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="obj">The object to set the border style 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)
public static T BorderStyle<T>(this T obj, Style style)
where T : class, IHasBorder
{
if (obj is null)
@@ -51,7 +69,7 @@ namespace Spectre.Console
/// <param name="obj">The object to set the border color for.</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)
public static T BorderColor<T>(this T obj, Color color)
where T : class, IHasBorder
{
if (obj is null)
@@ -59,7 +77,7 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(obj));
}
obj.BorderStyle = (obj.BorderStyle ?? Style.Plain).WithForeground(color);
obj.BorderStyle = (obj.BorderStyle ?? Style.Plain).Foreground(color);
return obj;
}
}

View File

@@ -7,6 +7,25 @@ namespace Spectre.Console
/// </summary>
public static class HasBoxBorderExtensions
{
/// <summary>
/// Sets the border.
/// </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 to use.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static T Border<T>(this T obj, BoxBorder border)
where T : class, IHasBoxBorder
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Border = border;
return obj;
}
/// <summary>
/// Do not display a border.
/// </summary>
@@ -16,7 +35,7 @@ namespace Spectre.Console
public static T NoBorder<T>(this T obj)
where T : class, IHasBoxBorder
{
return SetBorder(obj, BoxBorder.None);
return Border(obj, BoxBorder.None);
}
/// <summary>
@@ -28,7 +47,7 @@ namespace Spectre.Console
public static T SquareBorder<T>(this T obj)
where T : class, IHasBoxBorder
{
return SetBorder(obj, BoxBorder.Square);
return Border(obj, BoxBorder.Square);
}
/// <summary>
@@ -40,7 +59,7 @@ namespace Spectre.Console
public static T AsciiBorder<T>(this T obj)
where T : class, IHasBoxBorder
{
return SetBorder(obj, BoxBorder.Ascii);
return Border(obj, BoxBorder.Ascii);
}
/// <summary>
@@ -52,7 +71,7 @@ namespace Spectre.Console
public static T RoundedBorder<T>(this T obj)
where T : class, IHasBoxBorder
{
return SetBorder(obj, BoxBorder.Rounded);
return Border(obj, BoxBorder.Rounded);
}
/// <summary>
@@ -64,7 +83,7 @@ namespace Spectre.Console
public static T HeavyBorder<T>(this T obj)
where T : class, IHasBoxBorder
{
return SetBorder(obj, BoxBorder.Heavy);
return Border(obj, BoxBorder.Heavy);
}
/// <summary>
@@ -76,26 +95,7 @@ namespace Spectre.Console
public static T DoubleBorder<T>(this T obj)
where T : class, IHasBoxBorder
{
return SetBorder(obj, BoxBorder.Double);
}
/// <summary>
/// Sets the border.
/// </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 to use.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static T SetBorder<T>(this T obj, BoxBorder border)
where T : class, IHasBoxBorder
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Border = border;
return obj;
return Border(obj, BoxBorder.Double);
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Globalization;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="IHasCulture"/>.
/// </summary>
public static class HasCultureExtensions
{
/// <summary>
/// Sets the culture.
/// </summary>
/// <typeparam name="T">An object type with a culture.</typeparam>
/// <param name="obj">The object to set the culture for.</param>
/// <param name="culture">The culture to set.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static T Culture<T>(this T obj, CultureInfo culture)
where T : class, IHasCulture
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
if (culture is null)
{
throw new ArgumentNullException(nameof(culture));
}
obj.Culture = culture;
return obj;
}
/// <summary>
/// Sets the culture.
/// </summary>
/// <typeparam name="T">An object type with a culture.</typeparam>
/// <param name="obj">The object to set the culture for.</param>
/// <param name="name">The culture to set.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static T Culture<T>(this T obj, string name)
where T : class, IHasCulture
{
if (name is null)
{
throw new ArgumentNullException(nameof(name));
}
return Culture(obj, CultureInfo.GetCultureInfo(name));
}
/// <summary>
/// Sets the culture.
/// </summary>
/// <typeparam name="T">An object type with a culture.</typeparam>
/// <param name="obj">The object to set the culture for.</param>
/// <param name="culture">The culture to set.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static T Culture<T>(this T obj, int culture)
where T : class, IHasCulture
{
return Culture(obj, CultureInfo.GetCultureInfo(culture));
}
}
}

View File

@@ -16,7 +16,7 @@ namespace Spectre.Console
public static T NoBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.None);
return Border(obj, TableBorder.None);
}
/// <summary>
@@ -28,7 +28,7 @@ namespace Spectre.Console
public static T SquareBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.Square);
return Border(obj, TableBorder.Square);
}
/// <summary>
@@ -40,7 +40,7 @@ namespace Spectre.Console
public static T AsciiBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.Ascii);
return Border(obj, TableBorder.Ascii);
}
/// <summary>
@@ -52,7 +52,7 @@ namespace Spectre.Console
public static T Ascii2Border<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.Ascii2);
return Border(obj, TableBorder.Ascii2);
}
/// <summary>
@@ -64,7 +64,7 @@ namespace Spectre.Console
public static T AsciiDoubleHeadBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.AsciiDoubleHead);
return Border(obj, TableBorder.AsciiDoubleHead);
}
/// <summary>
@@ -76,7 +76,7 @@ namespace Spectre.Console
public static T RoundedBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.Rounded);
return Border(obj, TableBorder.Rounded);
}
/// <summary>
@@ -88,7 +88,7 @@ namespace Spectre.Console
public static T MinimalBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.Minimal);
return Border(obj, TableBorder.Minimal);
}
/// <summary>
@@ -100,7 +100,7 @@ namespace Spectre.Console
public static T MinimalHeavyHeadBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.MinimalHeavyHead);
return Border(obj, TableBorder.MinimalHeavyHead);
}
/// <summary>
@@ -112,7 +112,7 @@ namespace Spectre.Console
public static T MinimalDoubleHeadBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.MinimalDoubleHead);
return Border(obj, TableBorder.MinimalDoubleHead);
}
/// <summary>
@@ -124,7 +124,7 @@ namespace Spectre.Console
public static T SimpleBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.Simple);
return Border(obj, TableBorder.Simple);
}
/// <summary>
@@ -136,7 +136,7 @@ namespace Spectre.Console
public static T SimpleHeavyBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.SimpleHeavy);
return Border(obj, TableBorder.SimpleHeavy);
}
/// <summary>
@@ -148,7 +148,7 @@ namespace Spectre.Console
public static T HorizontalBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.Horizontal);
return Border(obj, TableBorder.Horizontal);
}
/// <summary>
@@ -160,7 +160,7 @@ namespace Spectre.Console
public static T HeavyBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.Heavy);
return Border(obj, TableBorder.Heavy);
}
/// <summary>
@@ -172,7 +172,7 @@ namespace Spectre.Console
public static T HeavyEdgeBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.HeavyEdge);
return Border(obj, TableBorder.HeavyEdge);
}
/// <summary>
@@ -184,7 +184,7 @@ namespace Spectre.Console
public static T HeavyHeadBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.HeavyHead);
return Border(obj, TableBorder.HeavyHead);
}
/// <summary>
@@ -196,7 +196,7 @@ namespace Spectre.Console
public static T DoubleBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.Double);
return Border(obj, TableBorder.Double);
}
/// <summary>
@@ -208,7 +208,7 @@ namespace Spectre.Console
public static T DoubleEdgeBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.DoubleEdge);
return Border(obj, TableBorder.DoubleEdge);
}
/// <summary>
@@ -220,7 +220,7 @@ namespace Spectre.Console
public static T MarkdownBorder<T>(this T obj)
where T : class, IHasTableBorder
{
return SetBorder(obj, TableBorder.Markdown);
return Border(obj, TableBorder.Markdown);
}
/// <summary>
@@ -230,7 +230,7 @@ namespace Spectre.Console
/// <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, TableBorder border)
public static T Border<T>(this T obj, TableBorder border)
where T : class, IHasTableBorder
{
if (obj is null)

View File

@@ -0,0 +1,32 @@
using System;
using System.ComponentModel;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="IAlignable"/>.
/// </summary>
public static class ObsoleteAlignableExtensions
{
/// <summary>
/// Sets the alignment for an <see cref="IAlignable"/> object.
/// </summary>
/// <typeparam name="T">The alignable object type.</typeparam>
/// <param name="obj">The alignable object.</param>
/// <param name="alignment">The alignment.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Alignment(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static T SetAlignment<T>(this T obj, Justify alignment)
where T : class, IAlignable
{
if (obj is null)
{
throw new System.ArgumentNullException(nameof(obj));
}
obj.Alignment = alignment;
return obj;
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.ComponentModel;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="Calendar"/>.
/// </summary>
public static class ObsoleteCalendarExtensions
{
/// <summary>
/// Sets the calendar's highlight <see cref="Style"/>.
/// </summary>
/// <param name="calendar">The calendar.</param>
/// <param name="style">The highlight style.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use HighlightStyle(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Calendar SetHighlightStyle(this Calendar calendar, Style? style)
{
if (calendar is null)
{
throw new ArgumentNullException(nameof(calendar));
}
calendar.HightlightStyle = style ?? Style.Plain;
return calendar;
}
/// <summary>
/// Sets the calendar's header <see cref="Style"/>.
/// </summary>
/// <param name="calendar">The calendar.</param>
/// <param name="style">The header style.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use HeaderStyle(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Calendar SetHeaderStyle(this Calendar calendar, Style? style)
{
if (calendar is null)
{
throw new ArgumentNullException(nameof(calendar));
}
calendar.HeaderStyle = style ?? Style.Plain;
return calendar;
}
}
}

View File

@@ -0,0 +1,53 @@
using System;
using System.ComponentModel;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="IHasBorder"/>.
/// </summary>
public static class ObsoleteHasBorderExtensions
{
/// <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>
[Obsolete("Use BorderStyle(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
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">An object type with a border.</typeparam>
/// <param name="obj">The object to set the border color for.</param>
/// <param name="color">The border color to set.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use BorderColor(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static T SetBorderColor<T>(this T obj, Color color)
where T : class, IHasBorder
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.BorderStyle = (obj.BorderStyle ?? Style.Plain).Foreground(color);
return obj;
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.ComponentModel;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="IHasBoxBorder"/>.
/// </summary>
public static class ObsoleteHasBoxBorderExtensions
{
/// <summary>
/// Sets the border.
/// </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 to use.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Border(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static T SetBorder<T>(this T obj, BoxBorder border)
where T : class, IHasBoxBorder
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Border = border;
return obj;
}
}
}

View File

@@ -0,0 +1,80 @@
using System;
using System.ComponentModel;
using System.Globalization;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="IHasCulture"/>.
/// </summary>
public static class ObsoleteHasCultureExtensions
{
/// <summary>
/// Sets the culture.
/// </summary>
/// <typeparam name="T">An object type with a culture.</typeparam>
/// <param name="obj">The object to set the culture for.</param>
/// <param name="culture">The culture to set.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Culture(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static T SetCulture<T>(this T obj, CultureInfo culture)
where T : class, IHasCulture
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
if (culture is null)
{
throw new ArgumentNullException(nameof(culture));
}
obj.Culture = culture;
return obj;
}
/// <summary>
/// Sets the culture.
/// </summary>
/// <typeparam name="T">An object type with a culture.</typeparam>
/// <param name="obj">The object to set the culture for.</param>
/// <param name="name">The culture to set.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Culture(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static T SetCulture<T>(this T obj, string name)
where T : class, IHasCulture
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Culture = CultureInfo.GetCultureInfo(name);
return obj;
}
/// <summary>
/// Sets the culture.
/// </summary>
/// <typeparam name="T">An object type with a culture.</typeparam>
/// <param name="obj">The object to set the culture for.</param>
/// <param name="name">The culture to set.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Culture(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static T SetCulture<T>(this T obj, int name)
where T : class, IHasCulture
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Culture = CultureInfo.GetCultureInfo(name);
return obj;
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.ComponentModel;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="IHasTableBorder"/>.
/// </summary>
public static class ObsoleteHasTableBorderExtensions
{
/// <summary>
/// Sets the border.
/// </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 to use.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Border(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static T SetBorder<T>(this T obj, TableBorder border)
where T : class, IHasTableBorder
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Border = border;
return obj;
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.ComponentModel;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="IOverflowable"/>.
/// </summary>
public static class ObsoleteOverflowableExtensions
{
/// <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>
[Obsolete("Use Overflow(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
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;
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.ComponentModel;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="IPaddable"/>.
/// </summary>
public static class ObsoletePaddableExtensions
{
/// <summary>
/// Sets the left and right padding.
/// </summary>
/// <typeparam name="T">An object implementing <see cref="IPaddable"/>.</typeparam>
/// <param name="obj">The paddable object instance.</param>
/// <param name="left">The left padding to apply.</param>
/// <param name="top">The top padding to apply.</param>
/// <param name="right">The right padding to apply.</param>
/// <param name="bottom">The bottom padding to apply.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Padding(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static T SetPadding<T>(this T obj, int left, int top, int right, int bottom)
where T : class, IPaddable
{
return SetPadding(obj, new Padding(left, top, right, bottom));
}
/// <summary>
/// Sets the padding.
/// </summary>
/// <typeparam name="T">An object implementing <see cref="IPaddable"/>.</typeparam>
/// <param name="obj">The paddable object instance.</param>
/// <param name="padding">The padding to apply.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Padding(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static T SetPadding<T>(this T obj, Padding padding)
where T : class, IPaddable
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Padding = padding;
return obj;
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
using System.ComponentModel;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="Panel"/>.
/// </summary>
public static class ObsoletePanelExtensions
{
/// <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>
[Obsolete("Use Header(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
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));
}
style ??= panel.Header?.Style;
alignment ??= panel.Header?.Alignment;
return SetHeader(panel, new PanelHeader(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>
[Obsolete("Use Header(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Panel SetHeader(this Panel panel, PanelHeader header)
{
if (panel is null)
{
throw new ArgumentNullException(nameof(panel));
}
panel.Header = header;
return panel;
}
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.ComponentModel;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="RuleExtensions"/>.
/// </summary>
public static class ObsoleteRuleExtensions
{
/// <summary>
/// Sets the rule title.
/// </summary>
/// <param name="rule">The rule.</param>
/// <param name="title">The title.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Title(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Rule SetTitle(this Rule rule, string title)
{
if (rule is null)
{
throw new ArgumentNullException(nameof(rule));
}
if (title is null)
{
throw new ArgumentNullException(nameof(title));
}
rule.Title = title;
return rule;
}
/// <summary>
/// Sets the rule style.
/// </summary>
/// <param name="rule">The rule.</param>
/// <param name="style">The rule style.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Style(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Rule SetStyle(this Rule rule, Style style)
{
if (rule is null)
{
throw new ArgumentNullException(nameof(rule));
}
if (style is null)
{
throw new ArgumentNullException(nameof(style));
}
rule.Style = style;
return rule;
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.ComponentModel;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="string"/>.
/// </summary>
public static class ObsoleteStringExtensions
{
/// <summary>
/// Escapes text so that it wont be interpreted as markup.
/// </summary>
/// <param name="text">The text to escape.</param>
/// <returns>A string that is safe to use in markup.</returns>
[Obsolete("Use EscapeMarkup(..) instead.", false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public static string SafeMarkup(this string text)
{
return text.EscapeMarkup();
}
}
}

View File

@@ -0,0 +1,100 @@
using System;
using System.ComponentModel;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="Style"/>.
/// </summary>
public static class ObsoleteStyleExtensions
{
/// <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>
[Obsolete("Use Foreground(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
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>
[Obsolete("Use Background(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
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>
[Obsolete("Use Decoration(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
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);
}
/// <summary>
/// Creates a new style from the specified one with
/// the specified link.
/// </summary>
/// <param name="style">The style.</param>
/// <param name="link">The link.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Link(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Style WithLink(this Style style, string link)
{
if (style is null)
{
throw new ArgumentNullException(nameof(style));
}
return new Style(
foreground: style.Foreground,
background: style.Background,
decoration: style.Decoration,
link: link);
}
}
}

View File

@@ -0,0 +1,202 @@
using System;
using System.ComponentModel;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="Table"/>.
/// </summary>
public static class ObsoleteTableExtensions
{
/// <summary>
/// Sets the table width.
/// </summary>
/// <param name="table">The table.</param>
/// <param name="width">The width.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Width(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Table SetWidth(this Table table, int width)
{
if (table is null)
{
throw new ArgumentNullException(nameof(table));
}
table.Width = width;
return table;
}
/// <summary>
/// Sets the table heading.
/// </summary>
/// <param name="table">The table.</param>
/// <param name="text">The heading.</param>
/// <param name="style">The style.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Heading(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Table SetHeading(this Table table, string text, Style? style = null)
{
if (table is null)
{
throw new ArgumentNullException(nameof(table));
}
if (text is null)
{
throw new ArgumentNullException(nameof(text));
}
return SetHeading(table, new TableTitle(text, style));
}
/// <summary>
/// Sets the table heading.
/// </summary>
/// <param name="table">The table.</param>
/// <param name="heading">The heading.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Heading(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Table SetHeading(this Table table, TableTitle heading)
{
if (table is null)
{
throw new ArgumentNullException(nameof(table));
}
table.Title = heading;
return table;
}
/// <summary>
/// Sets the table footnote.
/// </summary>
/// <param name="table">The table.</param>
/// <param name="text">The footnote.</param>
/// <param name="style">The style.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Caption(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Table SetFootnote(this Table table, string text, Style? style = null)
{
if (table is null)
{
throw new ArgumentNullException(nameof(table));
}
if (text is null)
{
throw new ArgumentNullException(nameof(text));
}
return SetFootnote(table, new TableTitle(text, style));
}
/// <summary>
/// Sets the table footnote.
/// </summary>
/// <param name="table">The table.</param>
/// <param name="footnote">The footnote.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Caption(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Table SetFootnote(this Table table, TableTitle footnote)
{
if (table is null)
{
throw new ArgumentNullException(nameof(table));
}
table.Caption = footnote;
return table;
}
/// <summary>
/// Sets the table footnote.
/// </summary>
/// <param name="table">The table.</param>
/// <param name="text">The footnote.</param>
/// <param name="style">The style.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Caption(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Table Footnote(this Table table, string text, Style? style = null)
{
if (table is null)
{
throw new ArgumentNullException(nameof(table));
}
if (text is null)
{
throw new ArgumentNullException(nameof(text));
}
return Footnote(table, new TableTitle(text, style));
}
/// <summary>
/// Sets the table footnote.
/// </summary>
/// <param name="table">The table.</param>
/// <param name="footnote">The footnote.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Caption(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Table Footnote(this Table table, TableTitle footnote)
{
if (table is null)
{
throw new ArgumentNullException(nameof(table));
}
table.Caption = footnote;
return table;
}
/// <summary>
/// Sets the table heading.
/// </summary>
/// <param name="table">The table.</param>
/// <param name="text">The heading.</param>
/// <param name="style">The style.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Title(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Table Heading(this Table table, string text, Style? style = null)
{
if (table is null)
{
throw new ArgumentNullException(nameof(table));
}
if (text is null)
{
throw new ArgumentNullException(nameof(text));
}
return Heading(table, new TableTitle(text, style));
}
/// <summary>
/// Sets the table heading.
/// </summary>
/// <param name="table">The table.</param>
/// <param name="heading">The heading.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
[Obsolete("Use Title(..) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static Table Heading(this Table table, TableTitle heading)
{
if (table is null)
{
throw new ArgumentNullException(nameof(table));
}
table.Title = heading;
return table;
}
}
}

View File

@@ -21,7 +21,7 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(obj));
}
return SetOverflow(obj, Overflow.Fold);
return Overflow(obj, Console.Overflow.Fold);
}
/// <summary>
@@ -38,7 +38,7 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(obj));
}
return SetOverflow(obj, Overflow.Crop);
return Overflow(obj, Console.Overflow.Crop);
}
/// <summary>
@@ -55,7 +55,7 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(obj));
}
return SetOverflow(obj, Overflow.Ellipsis);
return Overflow(obj, Console.Overflow.Ellipsis);
}
/// <summary>
@@ -65,7 +65,7 @@ namespace Spectre.Console
/// <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)
public static T Overflow<T>(this T obj, Overflow overflow)
where T : class, IOverflowable
{
if (obj is null)

View File

@@ -22,7 +22,7 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(obj));
}
return SetPadding(obj, new Padding(left, obj.Padding.Top, obj.Padding.Right, obj.Padding.Bottom));
return Padding(obj, new Padding(left, obj.Padding.Top, obj.Padding.Right, obj.Padding.Bottom));
}
/// <summary>
@@ -40,7 +40,7 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(obj));
}
return SetPadding(obj, new Padding(obj.Padding.Left, top, obj.Padding.Right, obj.Padding.Bottom));
return Padding(obj, new Padding(obj.Padding.Left, top, obj.Padding.Right, obj.Padding.Bottom));
}
/// <summary>
@@ -58,7 +58,7 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(obj));
}
return SetPadding(obj, new Padding(obj.Padding.Left, obj.Padding.Top, right, obj.Padding.Bottom));
return Padding(obj, new Padding(obj.Padding.Left, obj.Padding.Top, right, obj.Padding.Bottom));
}
/// <summary>
@@ -76,7 +76,7 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(obj));
}
return SetPadding(obj, new Padding(obj.Padding.Left, obj.Padding.Top, obj.Padding.Right, bottom));
return Padding(obj, new Padding(obj.Padding.Left, obj.Padding.Top, obj.Padding.Right, bottom));
}
/// <summary>
@@ -89,10 +89,10 @@ namespace Spectre.Console
/// <param name="right">The right padding to apply.</param>
/// <param name="bottom">The bottom padding to apply.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static T SetPadding<T>(this T obj, int left, int top, int right, int bottom)
public static T Padding<T>(this T obj, int left, int top, int right, int bottom)
where T : class, IPaddable
{
return SetPadding(obj, new Padding(left, top, right, bottom));
return Padding(obj, new Padding(left, top, right, bottom));
}
/// <summary>
@@ -102,7 +102,7 @@ namespace Spectre.Console
/// <param name="obj">The paddable object instance.</param>
/// <param name="padding">The padding to apply.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static T SetPadding<T>(this T obj, Padding padding)
public static T Padding<T>(this T obj, Padding padding)
where T : class, IPaddable
{
if (obj is null)

View File

@@ -15,7 +15,7 @@ namespace Spectre.Console
/// <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)
public static Panel Header(this Panel panel, string text, Style? style = null, Justify? alignment = null)
{
if (panel is null)
{
@@ -27,7 +27,69 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(text));
}
return SetHeader(panel, new PanelHeader(text, style, alignment));
style ??= panel.Header?.Style;
alignment ??= panel.Header?.Alignment;
return Header(panel, new PanelHeader(text, style, alignment));
}
/// <summary>
/// Sets the panel header style.
/// </summary>
/// <param name="panel">The panel.</param>
/// <param name="style">The header style.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static Panel HeaderStyle(this Panel panel, Style style)
{
if (panel is null)
{
throw new ArgumentNullException(nameof(panel));
}
if (style is null)
{
throw new ArgumentNullException(nameof(style));
}
if (panel.Header != null)
{
// Update existing style
panel.Header.Style = style;
}
else
{
// Create header
Header(panel, string.Empty, style, null);
}
return panel;
}
/// <summary>
/// Sets the panel header alignment.
/// </summary>
/// <param name="panel">The panel.</param>
/// <param name="alignment">The header alignment.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static Panel HeaderAlignment(this Panel panel, Justify alignment)
{
if (panel is null)
{
throw new ArgumentNullException(nameof(panel));
}
if (panel.Header != null)
{
// Update existing style
panel.Header.Alignment = alignment;
}
else
{
// Create header
Header(panel, string.Empty, null, alignment);
}
return panel;
}
/// <summary>
@@ -36,7 +98,7 @@ namespace Spectre.Console
/// <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, PanelHeader header)
public static Panel Header(this Panel panel, PanelHeader header)
{
if (panel is null)
{

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