Compare commits
	
		
			59 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | e280b82679 | ||
|  | 6932c95731 | ||
|  | ee305702e8 | ||
|  | 63abcc92ba | ||
|  | acf01e056f | ||
|  | 501db5d287 | ||
|  | cbed41e637 | ||
|  | 3c504155bc | ||
|  | ae32785f21 | ||
|  | c61e386440 | ||
|  | b7cd7dd53e | ||
|  | 3e1251b86a | ||
|  | 01fdbac51e | ||
|  | b0b988a1e7 | ||
|  | 2a9fa223de | ||
|  | 4f6eca4fcb | ||
|  | a5125d640c | ||
|  | a59e0dcb21 | ||
|  | bde61cc6ff | ||
|  | 5c33b87a9c | ||
|  | aaf77c3b25 | ||
|  | d70ad661fc | ||
|  | 0d209d8f18 | ||
|  | 380c6aca45 | ||
|  | b1da5e7ba8 | ||
|  | be3350a411 | ||
|  | a1d11e9d0c | ||
|  | 93d1971f48 | ||
|  | bca1c889d1 | ||
|  | 9915a0d6a8 | ||
|  | f34fc43d00 | ||
|  | e7f497050c | ||
|  | 3e5e22d6c2 | ||
|  | 10daf727e9 | ||
|  | 03334f693d | ||
|  | c9c0ad733f | ||
|  | 041bd016a2 | ||
|  | 037a215a78 | ||
|  | 9afc1ea721 | ||
|  | b52056ee49 | ||
|  | 3941fd81ab | ||
|  | 5a1b8a1710 | ||
|  | 1410cba6c5 | ||
|  | 70fc14e9cd | ||
|  | 0b4359a52a | ||
|  | cb2924a609 | ||
|  | 5c119ee0c3 | ||
|  | b9d182b6e3 | ||
|  | bfffef630f | ||
|  | a2f507e58f | ||
|  | d1d06d6a6b | ||
|  | 52718c499c | ||
|  | 7ef1ac483a | ||
|  | c0875c912a | ||
|  | 3f2ca49071 | ||
|  | 0a0380ae0a | ||
|  | ae92c606bb | ||
|  | 68e92f3365 | ||
|  | 39a8588dc3 | 
							
								
								
									
										28
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,28 @@ | ||||
| --- | ||||
| name: Bug report | ||||
| about: Create a report to help us improve | ||||
| title: '' | ||||
| labels: bug | ||||
| assignees: '' | ||||
|  | ||||
| --- | ||||
|  | ||||
| **Information** | ||||
|  - OS: [eg Windows/Linux/MacOS] | ||||
|  - Version: [e.g. 0.33.0] | ||||
|  - Terminal: [e.g Windows Terminal] | ||||
|  | ||||
| **Describe the bug** | ||||
| A clear and concise description of what the bug is. | ||||
|  | ||||
| **To Reproduce** | ||||
| Steps to reproduce the behavior. | ||||
|  | ||||
| **Expected behavior** | ||||
| A clear and concise description of what you expected to happen. | ||||
|  | ||||
| **Screenshots** | ||||
| If applicable, add screenshots to help explain your problem. | ||||
|  | ||||
| **Additional context** | ||||
| Add any other context about the problem here. | ||||
							
								
								
									
										20
									
								
								.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,20 @@ | ||||
| --- | ||||
| name: Feature request | ||||
| about: Suggest an idea for this project | ||||
| title: '' | ||||
| labels: enhancement | ||||
| assignees: '' | ||||
|  | ||||
| --- | ||||
|  | ||||
| **Is your feature request related to a problem? Please describe.** | ||||
| A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] | ||||
|  | ||||
| **Describe the solution you'd like** | ||||
| A clear and concise description of what you want to happen. | ||||
|  | ||||
| **Describe alternatives you've considered** | ||||
| A clear and concise description of any alternative solutions or features you've considered. | ||||
|  | ||||
| **Additional context** | ||||
| Add any other context or screenshots about the feature request here. | ||||
							
								
								
									
										27
									
								
								.github/workflows/ci.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -21,7 +21,7 @@ jobs: | ||||
|     - name: Setup dotnet | ||||
|       uses: actions/setup-dotnet@v1 | ||||
|       with: | ||||
|         dotnet-version: '3.1.301' # SDK Version to use. | ||||
|         dotnet-version: 5.0.100 | ||||
|  | ||||
|     - name: Build | ||||
|       shell: bash | ||||
| @@ -55,25 +55,32 @@ jobs: | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|  | ||||
|       - name: Setup dotnet | ||||
|       - name: Setup dotnet 3.1.402 | ||||
|         uses: actions/setup-dotnet@v1 | ||||
|         with: | ||||
|           dotnet-version: 3.1.301 | ||||
|           dotnet-version: 3.1.402 | ||||
|  | ||||
|       - name: Setup dotnet 5.0.100 | ||||
|         uses: actions/setup-dotnet@v1 | ||||
|         with: | ||||
|           dotnet-version: 5.0.100 | ||||
|  | ||||
|       - name: Integration Tests | ||||
|         shell: bash | ||||
|         run: | | ||||
|           dotnet tool restore | ||||
|           dotnet example info | ||||
|           dotnet example tables | ||||
|           dotnet example grids | ||||
|           dotnet example panels | ||||
|           dotnet example colors | ||||
|           dotnet example emojis | ||||
|           dotnet example exceptions | ||||
|           dotnet example --all | ||||
|  | ||||
|       - name: Build | ||||
|         shell: bash | ||||
|         run: | | ||||
|           dotnet tool restore | ||||
|           dotnet cake | ||||
|        | ||||
|       - name: Upload Verify Test Results | ||||
|         if: failure() | ||||
|         uses: actions/upload-artifact@v2 | ||||
|         with: | ||||
|           name: verify-test-results | ||||
|           path: | | ||||
|             **/*.received.* | ||||
							
								
								
									
										2
									
								
								.github/workflows/docs.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -24,7 +24,7 @@ jobs: | ||||
|     - name: Setup dotnet | ||||
|       uses: actions/setup-dotnet@v1 | ||||
|       with: | ||||
|         dotnet-version: '3.1.301' # SDK Version to use. | ||||
|         dotnet-version: 5.0.100 | ||||
|  | ||||
|     - name: Publish | ||||
|       shell: bash | ||||
|   | ||||
							
								
								
									
										20
									
								
								.github/workflows/publish.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -29,7 +29,7 @@ jobs: | ||||
|     - name: Setup dotnet | ||||
|       uses: actions/setup-dotnet@v1 | ||||
|       with: | ||||
|         dotnet-version: '3.1.301' # SDK Version to use. | ||||
|         dotnet-version: 5.0.100 | ||||
|  | ||||
|     - name: Build | ||||
|       shell: bash | ||||
| @@ -64,10 +64,15 @@ jobs: | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|  | ||||
|       - name: Setup dotnet | ||||
|       - name: Setup dotnet 3.1.402 | ||||
|         uses: actions/setup-dotnet@v1 | ||||
|         with: | ||||
|           dotnet-version: 3.1.301 | ||||
|           dotnet-version: 3.1.402 | ||||
|  | ||||
|       - name: Setup dotnet 5.0.100 | ||||
|         uses: actions/setup-dotnet@v1 | ||||
|         with: | ||||
|           dotnet-version: 5.0.100 | ||||
|  | ||||
|       - name: Build | ||||
|         shell: bash | ||||
| @@ -90,10 +95,15 @@ jobs: | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|  | ||||
|       - name: Setup dotnet | ||||
|       - name: Setup dotnet 3.1.402 | ||||
|         uses: actions/setup-dotnet@v1 | ||||
|         with: | ||||
|           dotnet-version: 3.1.301 | ||||
|           dotnet-version: 3.1.402 | ||||
|  | ||||
|       - name: Setup dotnet 5.0.100 | ||||
|         uses: actions/setup-dotnet@v1 | ||||
|         with: | ||||
|           dotnet-version: 5.0.100 | ||||
|  | ||||
|       - name: Publish | ||||
|         shell: bash | ||||
|   | ||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -88,3 +88,5 @@ packages | ||||
|  | ||||
| # Windows | ||||
| Thumbs.db | ||||
|  | ||||
| *.received.* | ||||
							
								
								
									
										413
									
								
								README.jp.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,413 @@ | ||||
| # `Spectre.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ビットカラーに対応しています。 | ||||
|   ライブラリは現在のターミナルの性能を検知し、必要なカラーにダウングレードします | ||||
|  | ||||
| ## 例 | ||||
|  | ||||
|  | ||||
|  | ||||
| ## 使用方法 | ||||
|  | ||||
| `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 restore | ||||
| ``` | ||||
|  | ||||
| このリポジトリで提供している例が一覧表示されます | ||||
|  | ||||
| ``` | ||||
| > 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); | ||||
| ``` | ||||
|  | ||||
| これは次のように出力を描画します。 | ||||
|  | ||||
|  | ||||
|  | ||||
| ### 罫線 | ||||
|  | ||||
|  | ||||
| ```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); | ||||
| ``` | ||||
|  | ||||
|  | ||||
| ### 例外の省略表示 | ||||
|  | ||||
| 例外の特定部分を短くして、さらに読みやすくしたり、パスをクリック可能なハイパーリンクにすることもできます。 | ||||
| ハイパーリンクがクリックできるかはターミナル次第です。 | ||||
|  | ||||
|  | ||||
| ```csharp | ||||
| AnsiConsole.WriteException(ex,  | ||||
|     ExceptionFormats.ShortenPaths | ExceptionFormats.ShortenTypes | | ||||
|     ExceptionFormats.ShortenMethods | ExceptionFormats.ShowLinks); | ||||
| ``` | ||||
|  | ||||
|  | ||||
|  | ||||
| ### 例外出力のカスタマイズ | ||||
|  | ||||
| 例外の特定部分を短縮するだけでなく、デフォルトのスタイルを上書きすることもできます。 | ||||
|  | ||||
| ```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), | ||||
|     } | ||||
| }); | ||||
| ``` | ||||
|  | ||||
|  | ||||
							
								
								
									
										97
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -2,18 +2,17 @@ | ||||
|  | ||||
| _[](https://www.nuget.org/packages/spectre.console)_ | ||||
|  | ||||
| A .NET Standard 2.0 library that makes it easier to create beautiful console applications.   | ||||
| A .NET 5/.NET Standard 2.0 library that makes it easier to create beautiful, cross platform, console applications.   | ||||
| It is heavily inspired by the excellent [Rich library](https://github.com/willmcgugan/rich)  | ||||
| for Python. | ||||
|  | ||||
| ## Table of Contents | ||||
|  | ||||
| 1. [Features](#features) | ||||
| 2. [Example](#example) | ||||
| 3. [Usage](#usage)   | ||||
|    3.1. [Using the static API](#using-the-static-api)   | ||||
|    3.2. [Creating a console](#creating-a-console) | ||||
| 4. [Running examples](#running-examples) | ||||
| 2. [Installing](#installing) | ||||
| 3. [Documentation](#documentation) | ||||
| 4. [Examples](#examples) | ||||
| 5. [License](#license) | ||||
|  | ||||
| ## Features | ||||
|  | ||||
| @@ -26,98 +25,48 @@ for Python. | ||||
|   The library will detect the capabilities of the current terminal  | ||||
|   and downgrade colors as needed.   | ||||
|  | ||||
| ## Example | ||||
|  | ||||
|  | ||||
|  | ||||
| ## Usage | ||||
| ## Installing | ||||
|  | ||||
| The `Spectre.Console` API is stateful and is not thread-safe. | ||||
| If you need to write to the console from different threads, make sure that  | ||||
| you take appropriate precautions, just like when you use the  | ||||
| regular `System.Console` API. | ||||
|  | ||||
| If the current terminal does not support ANSI escape sequences,  | ||||
| `Spectre.Console` will fallback to using the `System.Console` API. | ||||
|  | ||||
| _NOTE: This library is currently under development and API's  | ||||
| might change or get removed at any point up until a 1.0 release._ | ||||
|  | ||||
| ### Using the static API | ||||
|  | ||||
| The static API is perfect when you just want to output text | ||||
| like you usually do with the `System.Console` API, but prettier. | ||||
| The fastest way of getting started using `Spectre.Console` is to install the NuGet package. | ||||
|  | ||||
| ```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"); | ||||
| dotnet add package Spectre.Console | ||||
| ``` | ||||
|  | ||||
| If you want to get a reference to the default `IAnsiConsole`,  | ||||
| you can access it via `AnsiConsole.Console`. | ||||
| ## Documentation | ||||
|  | ||||
| ### Creating a console | ||||
| The documentation for `Spectre.Console` can be found at | ||||
| https://spectresystems.github.io/spectre.console/ | ||||
|  | ||||
| Sometimes it's useful to explicitly create a console with specific  | ||||
| capabilities, such as during unit testing when you want control  | ||||
| over the environment your code runs in.  | ||||
| ## Examples | ||||
|  | ||||
| It's recommended to not use `AnsiConsole` in code that run as  | ||||
| part of a unit test. | ||||
|  | ||||
| ```csharp | ||||
| IAnsiConsole console = AnsiConsole.Create( | ||||
|     new AnsiConsoleSettings() | ||||
|     { | ||||
|         Ansi = AnsiSupport.Yes, | ||||
|         ColorSystem = ColorSystemSupport.TrueColor, | ||||
|         Out = new StringWriter(), | ||||
|     }); | ||||
| ``` | ||||
|  | ||||
| _NOTE: Even if you can specify a specific color system to use  | ||||
| when manually creating a console, remember that the user's terminal  | ||||
| might not be able to use it, so unless you're creating an IAnsiConsole  | ||||
| for testing, always use `ColorSystemSupport.Detect` and `AnsiSupport.Detect`._ | ||||
|  | ||||
| ## Running examples | ||||
|  | ||||
| To see Spectre.Console in action, install the  | ||||
| To see `Spectre.Console` in action, install the  | ||||
| [dotnet-example](https://github.com/patriksvensson/dotnet-example) | ||||
| global tool. | ||||
|  | ||||
| ``` | ||||
| > dotnet tool install -g dotnet-example | ||||
| > dotnet tool restore | ||||
| ``` | ||||
|  | ||||
| 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. │ | ||||
| ╰────────┴───────────────────────────────┴─────────────────────────────────────────────────╯ | ||||
| ``` | ||||
|  | ||||
| And to run an example: | ||||
|  | ||||
| ``` | ||||
| > dotnet example table | ||||
| ┌──────────┬──────────┬────────┐ | ||||
| │ Foo      │ Bar      │ Baz    │ | ||||
| ├──────────┼──────────┼────────┤ | ||||
| │ Hello    │ World!   │        │ | ||||
| │ Bonjour  │ le       │ monde! │ | ||||
| │ Hej      │ Världen! │        │ | ||||
| └──────────┴──────────┴────────┘ | ||||
| > dotnet example tables | ||||
| ``` | ||||
|  | ||||
| ## License | ||||
|  | ||||
| Copyright © Spectre Systems. | ||||
|  | ||||
| Spectre.Console is provided as-is under the MIT license. For more information see LICENSE. | ||||
|  | ||||
| * For SixLabors.ImageSharp, see https://github.com/SixLabors/ImageSharp/blob/master/LICENSE | ||||
							
								
								
									
										65
									
								
								README.zh.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,65 @@ | ||||
| # `Spectre.Console` | ||||
|  | ||||
| _[](https://www.nuget.org/packages/spectre.console)_ | ||||
|  | ||||
| `Spectre.Console`是一个 .NET 5/.NET Standard 2.0 的库,能让您在终端里更方便地生成精美的界面。 | ||||
|  | ||||
| 深受 [Rich](https://github.com/willmcgugan/rich) 这个优秀库的启发。 | ||||
|  | ||||
| ## 目录 | ||||
|  | ||||
| 1. [功能](#features) | ||||
| 2. [安装](#installing) | ||||
| 3. [文档](#documentation) | ||||
| 4. [例子](#examples) | ||||
| 5. [License](#license) | ||||
|  | ||||
| ## 功能 | ||||
|  | ||||
| * 编写时考虑到了单元测试。 | ||||
| * 支持 tables、grid、panel 和 [rich](https://github.com/willmcgugan/rich) 所支持的标记语言。 | ||||
| * 支持大部分的 SRG 参数,包括粗体、暗淡字、斜体、下划线、删除线和闪烁文本。 | ||||
| * 支持终端显示 3/4/8/24 位色。自动检测终端类型,自适应颜色范围。 | ||||
|  | ||||
|  | ||||
|  | ||||
| ## 安装 | ||||
|  | ||||
| 最快的安装方式,就是用NuGet包管理直接安装Spectre.Console。 | ||||
|  | ||||
| ```csharp | ||||
| dotnet add package Spectre.Console | ||||
| ``` | ||||
|  | ||||
| ## 文档 | ||||
|  | ||||
| `Spectre.Console`的文档可以在这里查看 | ||||
| https://spectresystems.github.io/spectre.console/ | ||||
|  | ||||
| ## 例子 | ||||
|  | ||||
| 如果想直接运行`Spectre.Console`的例子,则需要安装[dotnet-example](https://github.com/patriksvensson/dotnet-example)工具。 | ||||
|  | ||||
| ``` | ||||
| > dotnet tool restore | ||||
| ``` | ||||
|  | ||||
| 然后你可以列出仓库里的所有例子: | ||||
|  | ||||
| ``` | ||||
| > dotnet example | ||||
| ``` | ||||
|  | ||||
| 跑一个看看效果: | ||||
|  | ||||
| ``` | ||||
| > dotnet example tables | ||||
| ``` | ||||
|  | ||||
| ## License | ||||
|  | ||||
| 版权所有 © Spectre Systems。 | ||||
|  | ||||
| Spectre.Console 基于 MIT 协议提供。查看 LICENSE 文件了解更多信息。 | ||||
|  | ||||
| * SixLabors.ImageSharp 的协议请查看 https://github.com/SixLabors/ImageSharp/blob/master/LICENSE | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory> | ||||
|     <DefaultItemExcludes>$(DefaultItemExcludes);output\**;.gitignore</DefaultItemExcludes> | ||||
|     <MinVerSkip Condition="'$(Configuration)' == 'Debug'">true</MinVerSkip> | ||||
| @@ -31,8 +31,8 @@ | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="Statiq.Web" Version="1.0.0-beta.5" /> | ||||
|     <PackageReference Include="MinVer" PrivateAssets="All" Version="2.3.0" /> | ||||
|     <PackageReference Include="Statiq.Web" Version="1.0.0-beta.13" /> | ||||
|     <PackageReference Include="MinVer" PrivateAssets="All" Version="2.3.1" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|   | ||||
| @@ -10,7 +10,7 @@ The documentation site uses [Statiq](https://statiq.dev), a static site generato | ||||
| > 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). | ||||
| After the build is complete, you can navigate to [http://localhost:5080/spectre.console](http://localhost:5080/spectre.console). | ||||
|  | ||||
| **Note that the site runs under a virtual directory.** | ||||
|  | ||||
|   | ||||
| @@ -140,6 +140,11 @@ | ||||
|  | ||||
|                                             @foreach (IDocument document in OutputPages.GetChildrenOf(root).OnlyVisible()) | ||||
|                                             { | ||||
|                                                 if(string.IsNullOrWhiteSpace(document.GetTitle())) | ||||
|                                                 { | ||||
|                                                     continue; | ||||
|                                                 } | ||||
|  | ||||
|                                                 DocumentList<IDocument> documentChildren = OutputPages.GetChildrenOf(document); | ||||
|                                                 <div class="sidebar-nav-item @(Document.IdEquals(document) ? "active" : null) @(documentChildren.Any() ? "has-children" : null)"> | ||||
|                                                     @if(document.ShowLink()) | ||||
|   | ||||
| @@ -30,6 +30,25 @@ 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  | ||||
|   | ||||
							
								
								
									
										43
									
								
								docs/input/appendix/spinners.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,43 @@ | ||||
| Title: Spinners | ||||
| Order: 4 | ||||
| --- | ||||
|  | ||||
| For all available spinners, see https://jsfiddle.net/sindresorhus/2eLtsbey/embedded/result/ | ||||
|  | ||||
| # Usage | ||||
|  | ||||
| Spinners can be used with [Progress](xref:progress) and [Status](xref:status). | ||||
|  | ||||
| ```csharp | ||||
| AnsiConsole.Status() | ||||
|     .Spinner(Spinner.Known.Star) | ||||
|     .Start("Thinking...", ctx => { | ||||
|         // Omitted | ||||
|     }); | ||||
| ``` | ||||
|  | ||||
| # Implementing a spinner | ||||
|  | ||||
| To implement your own spinner, all you have to do is  | ||||
| inherit from the `Spinner` base class. | ||||
|  | ||||
| In the example below, the spinner will alterate between | ||||
| the characters `A`, `B` and `C` every 100 ms. | ||||
|  | ||||
| ```csharp | ||||
| public sealed class MySpinner : Spinner | ||||
| { | ||||
|     // The interval for each frame | ||||
|     public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); | ||||
|      | ||||
|     // Whether or not the spinner contains unicode characters | ||||
|     public override bool IsUnicode => false; | ||||
|  | ||||
|     // The individual frames of the spinner | ||||
|     public override IReadOnlyList<string> Frames =>  | ||||
|         new List<string> | ||||
|         { | ||||
|             "A", "B", "C", | ||||
|         }; | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										
											BIN
										
									
								
								docs/input/assets/images/custom_exception.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 159 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docs/input/assets/images/progress.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 164 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docs/input/assets/images/progress.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 14 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docs/input/assets/images/progress_fallback.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 33 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docs/input/assets/images/rule.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 24 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docs/input/assets/images/status.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 257 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docs/input/assets/images/table.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 MiB | 
| @@ -31,5 +31,4 @@ $(document).ready(function () { | ||||
|         }; // keyup | ||||
|     }) | ||||
|  | ||||
|  | ||||
| }); // ready | ||||
| @@ -9,9 +9,9 @@ You can make exception a bit more readable by using the `WriteException` method. | ||||
| AnsiConsole.WriteException(ex); | ||||
| ``` | ||||
|  | ||||
| <img src="assets/images/exception.png" style="max-width: 100%; margin-bottom: 20px"> | ||||
|  | ||||
| <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 | ||||
| @@ -19,8 +19,34 @@ the hyperlinks are clickable is up to the terminal. | ||||
|  | ||||
| ```csharp | ||||
| AnsiConsole.WriteException(ex,  | ||||
|     ExceptionFormat.ShortenPaths | ExceptionFormat.ShortenTypes | | ||||
|     ExceptionFormat.ShortenMethods | ExceptionFormat.ShowLinks); | ||||
|     ExceptionFormats.ShortenPaths | ExceptionFormats.ShortenTypes | | ||||
|     ExceptionFormats.ShortenMethods | ExceptionFormats.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 = 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), | ||||
|     } | ||||
| }); | ||||
| ``` | ||||
|  | ||||
| <img src="assets/images/custom_exception.png" style="max-width: 100%;"> | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| Title: Welcome | ||||
| Title: Welcome | ||||
| Order: 0 | ||||
| --- | ||||
|  | ||||
| @@ -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%;" /> | ||||
| @@ -6,7 +6,7 @@ The class `Markup` allows you to output rich text to the console. | ||||
|  | ||||
| # Syntax | ||||
|  | ||||
| Console markup uses a syntax inspired by bbcode. If you write the style (see Styles)  | ||||
| Console markup uses a syntax inspired by bbcode. If you write the style (see [Styles](xref:styles))  | ||||
| in square brackets, e.g. `[bold red]`, that style will apply until it is closed with a `[/]`. | ||||
|  | ||||
| ```csharp | ||||
| @@ -21,6 +21,7 @@ rendering of `IRenderable` also have overloads for rendering rich text. | ||||
| var table = new Table(); | ||||
| table.AddColumn(new TableColumn(new Markup("[yellow]Foo[/]"))); | ||||
| table.AddColumn(new TableColumn("[blue]Bar[/]")); | ||||
| AnsiConsole.Render(table); | ||||
| ``` | ||||
|  | ||||
| # Convenience methods | ||||
| @@ -43,14 +44,24 @@ AnsiConsole.Markup("[[Hello]] "); // [Hello] | ||||
| AnsiConsole.Markup("[red][[World]][/]"); // [World] | ||||
| ``` | ||||
|  | ||||
| You can also use the `EscapeMarkup` extension method. | ||||
|  | ||||
| ```csharp | ||||
| AnsiConsole.Markup("[red]{0}[/]", "Hello [World]".EscapeMarkup()); | ||||
| ``` | ||||
| You can also use the `Markup.Escape` method. | ||||
|  | ||||
| ```csharp | ||||
| AnsiConsole.Markup("[red]{0}[/]", Markup.Escape("Hello [World]")); | ||||
| ``` | ||||
| # Setting background color | ||||
|  | ||||
| You can set the background color in markup by prefixing the color with | ||||
| `on`. | ||||
|  | ||||
| ``` | ||||
| [bold yellow on blue]Hello[/] | ||||
| [default on blue]World[/] | ||||
| ```csharp | ||||
| AnsiConsole.Markup("[bold yellow on blue]Hello[/]"); | ||||
| AnsiConsole.Markup("[default on blue]World[/]"); | ||||
| ``` | ||||
|  | ||||
| # Rendering emojis | ||||
| @@ -58,10 +69,10 @@ You can set the background color in markup by prefixing the color with | ||||
| To output an emoji as part of markup, you can use emoji shortcodes. | ||||
|  | ||||
| ```csharp | ||||
| AnsiConsole.MarkupLine("Hello :globe_showing_europe_africa:!"); | ||||
| AnsiConsole.Markup("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 | ||||
|  | ||||
|   | ||||
							
								
								
									
										78
									
								
								docs/input/progress.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,78 @@ | ||||
| Title: Progress | ||||
| Order: 5 | ||||
| --- | ||||
|  | ||||
| Spectre.Console can display information about long running tasks in the console.  | ||||
|  | ||||
| <img src="assets/images/progress.png" style="max-width: 100%;margin-bottom:20px;"> | ||||
|  | ||||
| If the current terminal isn't considered "interactive", such as when running  | ||||
| in a continuous integration system, or the terminal can't display  | ||||
| ANSI control sequence, any progress will be displayed in a simpler way. | ||||
|  | ||||
| <img src="assets/images/progress_fallback.png" style="max-width: 100%;"> | ||||
|  | ||||
| # Usage | ||||
|  | ||||
| ```csharp | ||||
| // Synchronous | ||||
| AnsiConsole.Progress() | ||||
|     .Start(ctx =>  | ||||
|     { | ||||
|         // Define tasks | ||||
|         var task1 = ctx.AddTask("[green]Reticulating splines[/]"); | ||||
|         var task2 = ctx.AddTask("[green]Folding space[/]"); | ||||
|  | ||||
|         while(!ctx.IsFinished)  | ||||
|         { | ||||
|             task1.Increment(1.5); | ||||
|             task2.Increment(0.5); | ||||
|         } | ||||
|     }); | ||||
| ``` | ||||
|  | ||||
| ## Asynchronous progress | ||||
|  | ||||
| If you prefer to use async/await, you can use `StartAsync` instead of `Start`. | ||||
|  | ||||
| ```csharp | ||||
| // Asynchronous | ||||
| await AnsiConsole.Progress() | ||||
|     .StartAsync(async ctx => | ||||
|     { | ||||
|         // Define tasks | ||||
|         var task1 = ctx.AddTask("[green]Reticulating splines[/]"); | ||||
|         var task2 = ctx.AddTask("[green]Folding space[/]"); | ||||
|  | ||||
|         while (!ctx.IsFinished) | ||||
|         { | ||||
|             // Simulate some work | ||||
|             await Task.Delay(250); | ||||
|  | ||||
|             // Increment | ||||
|             task1.Increment(1.5); | ||||
|             task2.Increment(0.5); | ||||
|         } | ||||
|     }); | ||||
| ``` | ||||
|  | ||||
| # Configure | ||||
|  | ||||
| ```csharp | ||||
| // Asynchronous | ||||
| AnsiConsole.Progress() | ||||
|     .AutoRefresh(false) // Turn off auto refresh | ||||
|     .AutoClear(false)   // Do not remove the task list when done | ||||
|     .Columns(new ProgressColumn[]  | ||||
|     { | ||||
|         new TaskDescriptionColumn(),    // Task description | ||||
|         new ProgressBarColumn(),        // Progress bar | ||||
|         new PercentageColumn(),         // Percentage | ||||
|         new RemainingTimeColumn(),      // Remaining time | ||||
|         new SpinnerColumn(),            // Spinner | ||||
|     }) | ||||
|     .Start(ctx => | ||||
|     { | ||||
|         // Omitted | ||||
|     }); | ||||
| ``` | ||||
							
								
								
									
										99
									
								
								docs/input/prompt.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,99 @@ | ||||
| Title: Prompt | ||||
| Order: 4 | ||||
| --- | ||||
|  | ||||
| Sometimes you want to get some input from the user, and for this | ||||
| you can use the `Prompt<TResult>`. | ||||
|  | ||||
| # Confirmation | ||||
|  | ||||
| ```csharp | ||||
| if (!AnsiConsole.Confirm("Run example?")) | ||||
| { | ||||
|     return; | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
| Run example? [y/n] (y): _ | ||||
| ``` | ||||
|  | ||||
| # Simple | ||||
|  | ||||
| ```csharp | ||||
| // Ask for the user's name | ||||
| string name = AnsiConsole.Ask<string>("What's your [green]name[/]?"); | ||||
|  | ||||
| // Ask for the user's age | ||||
| int age = AnsiConsole.Ask<int>("What's your [green]age[/]?"); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
| What's your name? Patrik | ||||
| What's your age? 37 | ||||
| ``` | ||||
|  | ||||
| # Choices | ||||
|  | ||||
| ```csharp | ||||
| var fruit = AnsiConsole.Prompt( | ||||
|     new TextPrompt<string>("What's your [green]favorite fruit[/]?") | ||||
|         .InvalidChoiceMessage("[red]That's not a valid fruit[/]") | ||||
|         .DefaultValue("Orange") | ||||
|         .AddChoice("Apple") | ||||
|         .AddChoice("Banana") | ||||
|         .AddChoice("Orange")); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
| What's your favorite fruit? [Apple/Banana/Orange] (Orange): _ | ||||
| ``` | ||||
|  | ||||
| # Validation | ||||
|  | ||||
| ```csharp | ||||
| var age = AnsiConsole.Prompt( | ||||
|     new TextPrompt<int>("What's the secret number?") | ||||
|         .Validate(age => | ||||
|         { | ||||
|             return age switch | ||||
|             { | ||||
|                 < 99 => ValidationResult.Error("[red]Too low[/]"), | ||||
|                 > 99 => ValidationResult.Error("[red]Too high[/]"), | ||||
|                 _ => ValidationResult.Success(), | ||||
|             }; | ||||
|         })); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
| What's the secret number? 32 | ||||
| Too low | ||||
| What's the secret number? 102 | ||||
| Too high | ||||
| What's the secret number? _ | ||||
| ``` | ||||
|  | ||||
| # Secrets | ||||
|  | ||||
| ```csharp | ||||
| var password = AnsiConsole.Prompt( | ||||
|     new TextPrompt<string>("Enter [green]password[/]") | ||||
|         .PromptStyle("red") | ||||
|         .Secret()); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
| Enter password: ************_ | ||||
| ``` | ||||
|  | ||||
| # Optional | ||||
|  | ||||
| ```csharp | ||||
| var color = AnsiConsole.Prompt( | ||||
|     new TextPrompt<string>("[grey][[Optional]][/] [green]Favorite color[/]?") | ||||
|         .AllowEmpty()); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
| [Optional] Favorite color? _ | ||||
| ``` | ||||
| @@ -5,7 +5,7 @@ Order: 1 | ||||
| The fastest way of getting started using Spectre.Console is | ||||
| to install the NuGet package. | ||||
|  | ||||
| ```shell | ||||
| ```text | ||||
| > dotnet add package Spectre.Console | ||||
| ``` | ||||
|  | ||||
|   | ||||
							
								
								
									
										60
									
								
								docs/input/status.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,60 @@ | ||||
| Title: Status | ||||
| Order: 6 | ||||
| --- | ||||
|  | ||||
| Spectre.Console can display information about long running tasks in the console.  | ||||
|  | ||||
| <img src="assets/images/status.gif" style="max-width: 100%;margin-bottom:20px;"> | ||||
|  | ||||
| If the current terminal isn't considered "interactive", such as when running  | ||||
| in a continuous integration system, or the terminal can't display  | ||||
| ANSI control sequence, any progress will be displayed in a simpler way. | ||||
|  | ||||
| # Usage | ||||
|  | ||||
| ```csharp | ||||
| // Synchronous | ||||
| AnsiConsole.Status() | ||||
|     .Start("Thinking...", ctx =>  | ||||
|     { | ||||
|         // Simulate some work | ||||
|         AnsiConsole.MarkupLine("Doing some work..."); | ||||
|         Thread.Sleep(1000); | ||||
|          | ||||
|         // Update the status and spinner | ||||
|         ctx.Status("Thinking some more"); | ||||
|         ctx.Spinner(Spinner.Known.Star); | ||||
|         ctx.SpinnerStyle(Style.Parse("green")); | ||||
|  | ||||
|         // Simulate some work | ||||
|         AnsiConsole.MarkupLine("Doing some more work..."); | ||||
|         Thread.Sleep(2000); | ||||
|     }); | ||||
| ``` | ||||
|  | ||||
| ## Asynchronous progress | ||||
|  | ||||
| If you prefer to use async/await, you can use `StartAsync` instead of `Start`. | ||||
|  | ||||
| ```csharp | ||||
| // Asynchronous | ||||
| await AnsiConsole.Status() | ||||
|     .StartAsync("Thinking...", async ctx =>  | ||||
|     { | ||||
|         // Omitted | ||||
|     }); | ||||
| ``` | ||||
|  | ||||
| # Configure | ||||
|  | ||||
| ```csharp | ||||
| AnsiConsole.Status() | ||||
|     .AutoRefresh(false) | ||||
|     .Spinner(Spinner.Known.Star) | ||||
|     .SpinnerStyle(Style.Parse("green bold")) | ||||
|     .Start("Thinking...", ctx =>  | ||||
|     { | ||||
|         // Omitted | ||||
|         ctx.Refresh(); | ||||
|     }); | ||||
| ``` | ||||
							
								
								
									
										121
									
								
								docs/input/widgets/calendar.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,121 @@ | ||||
| Title: Calendar | ||||
| Order: 2 | ||||
| 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); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
|                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.Culture("ja-JP"); | ||||
| AnsiConsole.Render(calendar); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
|                Oktober 2020 | ||||
| ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐ | ||||
| │ Mån │ Tis │ Ons │ Tor │ Fre │ Lör │ Sön │ | ||||
| ├─────┼─────┼─────┼─────┼─────┼─────┼─────┤ | ||||
| │     │     │     │ 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(); | ||||
| AnsiConsole.Render(calendar); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
| ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐ | ||||
| │ 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.HeaderStyle(Style.Parse("blue bold")); | ||||
| AnsiConsole.Render(calendar); | ||||
| ``` | ||||
|  | ||||
|  | ||||
| ## Calendar Events | ||||
|  | ||||
| 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); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
|                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.HighlightStyle(Style.Parse("yellow bold")); | ||||
| AnsiConsole.Render(calendar); | ||||
| ``` | ||||
							
								
								
									
										106
									
								
								docs/input/widgets/canvas-image.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,106 @@ | ||||
| Title: Canvas Image | ||||
| Order: 5 | ||||
| --- | ||||
|  | ||||
| To add [ImageSharp](https://github.com/SixLabors/ImageSharp) superpowers to  | ||||
| your console application to draw images, you will need to install  | ||||
| the [Spectre.Console.ImageSharp](https://www.nuget.org/packages/Spectre.Console.ImageSharp) NuGet package. | ||||
|  | ||||
| ```text | ||||
| > dotnet add package Spectre.Console.ImageSharp | ||||
| ``` | ||||
|  | ||||
| # Loading images | ||||
|  | ||||
| Once you've added the `Spectre.Console.ImageSharp` NuGet package,  | ||||
| you can create a new instance of `CanvasImage` to draw images to the console. | ||||
|  | ||||
| ```csharp | ||||
| // Load an image | ||||
| var image = new CanvasImage("cake.png"); | ||||
|  | ||||
| // Set the max width of the image. | ||||
| // If no max width is set, the image will take | ||||
| // up as much space as there is available. | ||||
| image.MaxWidth(16); | ||||
|  | ||||
| // Render the image to the console | ||||
| AnsiConsole.Render(image); | ||||
| ``` | ||||
|  | ||||
| ## Result | ||||
|  | ||||
| <pre style="font-size:90%;font-family:consolas,'Courier New',monospace;line-height: normal; padding: 0px;background-color: #222222; padding: 20px;"> | ||||
| <span>        </span><span style="background-color: #542813">  </span><span style="background-color: #572F1B">  </span><span style="background-color: #4E1F09">  </span><span style="background-color: #5B3826">  </span><span style="background-color: #5E3A29">  </span><span style="background-color: #532611">  </span><span>            </span> | ||||
| <span>        </span><span style="background-color: #562E1B">  </span><span style="background-color: #634737">  </span><span style="background-color: #562E1A">  </span><span style="background-color: #5D4132">  </span><span style="background-color: #6D584B">  </span><span style="background-color: #624332">  </span><span style="background-color: #562B17">  </span><span>          </span> | ||||
| <span>        </span><span style="background-color: #512714">  </span><span style="background-color: #654E40">  </span><span style="background-color: #705243">  </span><span style="background-color: #745749">  </span><span style="background-color: #6D5B4F">  </span><span style="background-color: #715E52">  </span><span style="background-color: #644636">  </span><span style="background-color: #6A4433">  </span><span style="background-color: #542916">  </span><span style="background-color: #431C0B">  </span><span>    </span> | ||||
| <span>      </span><span style="background-color: #491E0A">  </span><span style="background-color: #5C3523">  </span><span style="background-color: #695346">  </span><span style="background-color: #705C4F">  </span><span style="background-color: #654838">  </span><span style="background-color: #654A3A">  </span><span style="background-color: #726154">  </span><span style="background-color: #715D50">  </span><span style="background-color: #B8A79F">  </span><span style="background-color: #AE988F">  </span><span style="background-color: #6F4A39">  </span><span style="background-color: #441906">  </span><span>  </span> | ||||
| <span>    </span><span style="background-color: #532916">  </span><span style="background-color: #8A6C5E">  </span><span style="background-color: #C2B3AB">  </span><span style="background-color: #8B786E">  </span><span style="background-color: #6B584C">  </span><span style="background-color: #695143">  </span><span style="background-color: #6C5648">  </span><span style="background-color: #6F5D51">  </span><span style="background-color: #816A55">  </span><span style="background-color: #E7E1DA">  </span><span style="background-color: #F9F5EE">  </span><span style="background-color: #BAA593">  </span><span style="background-color: #61381F">  </span><span>  </span> | ||||
| <span style="background-color: #421C0A">  </span><span style="background-color: #603826">  </span><span style="background-color: #9E8479">  </span><span style="background-color: #E2DAD6">  </span><span style="background-color: #FBF9F6">  </span><span style="background-color: #F0EADF">  </span><span style="background-color: #C4B59D">  </span><span style="background-color: #9D8663">  </span><span style="background-color: #786451">  </span><span style="background-color: #705D4E">  </span><span style="background-color: #BFA052">  </span><span style="background-color: #FEE88B">  </span><span style="background-color: #FDE580">  </span><span style="background-color: #E2C362">  </span><span style="background-color: #794E1D">  </span><span>  </span> | ||||
| <span style="background-color: #4B1D05">  </span><span style="background-color: #A6844C">  </span><span style="background-color: #E9D595">  </span><span style="background-color: #F1DC92">  </span><span style="background-color: #F5DD83">  </span><span style="background-color: #FBE278">  </span><span style="background-color: #FFE36E">  </span><span style="background-color: #F1D25E">  </span><span style="background-color: #866F4B">  </span><span style="background-color: #726256">  </span><span style="background-color: #967945">  </span><span style="background-color: #F5D456">  </span><span style="background-color: #F8D756">  </span><span style="background-color: #E1BE4A">  </span><span style="background-color: #7D511B">  </span><span>  </span> | ||||
| <span style="background-color: #4F2005">  </span><span style="background-color: #C9A441">  </span><span style="background-color: #FFE05C">    </span><span style="background-color: #FEDF5B">  </span><span style="background-color: #FCDC59">  </span><span style="background-color: #F7D555">  </span><span style="background-color: #E5C04A">  </span><span style="background-color: #795E3B">  </span><span style="background-color: #726256">  </span><span style="background-color: #755F4C">  </span><span style="background-color: #A17124">  </span><span style="background-color: #AE7414">  </span><span style="background-color: #AE791D">  </span><span style="background-color: #794D18">  </span><span>  </span> | ||||
| <span style="background-color: #4E1F04">  </span><span style="background-color: #B78D31">  </span><span style="background-color: #DDB33E">  </span><span style="background-color: #D0A132">  </span><span style="background-color: #C28F25">  </span><span style="background-color: #B67E1A">  </span><span style="background-color: #AC7111">  </span><span style="background-color: #9E610A">  </span><span style="background-color: #5F3212">  </span><span style="background-color: #6A574B">  </span><span style="background-color: #726256">  </span><span style="background-color: #744D2A">  </span><span style="background-color: #955401">  </span><span style="background-color: #8C5106">  </span><span style="background-color: #5F310C">  </span><span>  </span> | ||||
| <span style="background-color: #4B1A00">  </span><span style="background-color: #854903">  </span><span style="background-color: #9B5A02">  </span><span style="background-color: #995700">        </span><span style="background-color: #935200">  </span><span style="background-color: #592402">  </span><span style="background-color: #5B3F30">  </span><span style="background-color: #726256">  </span><span style="background-color: #705A4A">  </span><span style="background-color: #844C0C">  </span><span style="background-color: #824400">  </span><span style="background-color: #4C1B00">  </span><span>  </span> | ||||
| <span style="background-color: #4B1A00">  </span><span style="background-color: #824500">  </span><span style="background-color: #995700">          </span><span style="background-color: #935200">  </span><span style="background-color: #592300">  </span><span style="background-color: #4F2411">  </span><span style="background-color: #6B584C">  </span><span style="background-color: #736256">  </span><span style="background-color: #734E2C">  </span><span style="background-color: #7C4101">  </span><span style="background-color: #4C1B00">  </span><span>  </span> | ||||
| <span style="background-color: #4B1A00">  </span><span style="background-color: #824500">  </span><span style="background-color: #995700">          </span><span style="background-color: #935200">  </span><span style="background-color: #592300">  </span><span style="background-color: #4A1902">  </span><span style="background-color: #5C4031">  </span><span style="background-color: #726256">  </span><span style="background-color: #705B4B">  </span><span style="background-color: #6A390F">  </span><span style="background-color: #4C1A00">  </span><span>  </span> | ||||
| <span style="background-color: #4B1A00">  </span><span style="background-color: #824500">  </span><span style="background-color: #995700">          </span><span style="background-color: #935200">  </span><span style="background-color: #592300">  </span><span style="background-color: #4A1700">  </span><span style="background-color: #4F2512">  </span><span style="background-color: #6B594D">  </span><span style="background-color: #736256">  </span><span style="background-color: #634432">  </span><span style="background-color: #4C1D08">  </span><span>  </span> | ||||
| <span style="background-color: #4B1A00">  </span><span style="background-color: #814400">  </span><span style="background-color: #955400">  </span><span style="background-color: #915100">  </span><span style="background-color: #8C4D00">  </span><span style="background-color: #864800">  </span><span style="background-color: #7F4301">  </span><span style="background-color: #743A01">  </span><span style="background-color: #521E01">  </span><span style="background-color: #4A1700">  </span><span style="background-color: #4A1902">  </span><span style="background-color: #5D4132">  </span><span style="background-color: #726256">  </span><span style="background-color: #6F5B4E">  </span><span style="background-color: #5D3A28">  </span><span style="background-color: #53220C">  </span> | ||||
| <span style="background-color: #471801">  </span><span style="background-color: #642D01">  </span><span style="background-color: #6B3301">  </span><span style="background-color: #642E02">  </span><span style="background-color: #5D2902">  </span><span style="background-color: #542203">  </span><span style="background-color: #4C1C04">  </span><span style="background-color: #461905">  </span><span style="background-color: #4A1C07">  </span><span style="background-color: #4C1A03">  </span><span style="background-color: #4B1801">  </span><span style="background-color: #502613">  </span><span style="background-color: #69564A">  </span><span style="background-color: #705F54">  </span><span style="background-color: #604232">  </span><span style="background-color: #51200A">  </span> | ||||
| <span style="background-color: #411806">  </span><span style="background-color: #431A07">  </span><span style="background-color: #411D0D">  </span><span>              </span><span style="background-color: #4D1B05">  </span><span style="background-color: #4D1D07">  </span><span style="background-color: #533324">  </span><span style="background-color: #583E30">  </span><span style="background-color: #53301F">  </span><span style="background-color: #53230D">  </span> | ||||
| </pre> | ||||
|  | ||||
| # Manipulating images | ||||
|  | ||||
| You can take full advantage of [ImageSharp](https://github.com/SixLabors/ImageSharp) | ||||
| and manipulate images directly via it's [Processing API](https://docs.sixlabors.com/api/ImageSharp/SixLabors.ImageSharp.Processing.html). | ||||
|  | ||||
| ```csharp | ||||
| // Load an image | ||||
| var image = new CanvasImage("cake.png"); | ||||
| image.MaxWidth(32); | ||||
|  | ||||
| // Set a sampler that will be used when scaling the image. | ||||
| image.BilinearResampler(); | ||||
|  | ||||
| // Mutate the image using ImageSharp | ||||
| image.Mutate(ctx => ctx.Grayscale().Rotate(-45).EntropyCrop()); | ||||
|  | ||||
| // Render the image to the console | ||||
| AnsiConsole.Render(image); | ||||
| ``` | ||||
|  | ||||
| ## Result | ||||
|  | ||||
| <pre style="font-size:90%;font-family:consolas,'Courier New',monospace;line-height: normal; padding: 0px;background-color: #222222; padding: 20px;"> | ||||
| <span>                    </span><span style="background-color: #282828">  </span><span style="background-color: #222222">  </span><span style="background-color: #232323">  </span><span style="background-color: #353535">  </span><span style="background-color: #4B4B4B">  </span><span style="background-color: #595959">    </span><span style="background-color: #3B3B3B">  </span><span style="background-color: #202020">  </span><span style="background-color: #191919">  </span><span>                        </span> | ||||
| <span>          </span><span style="background-color: #343434">  </span><span style="background-color: #2B2B2B">  </span><span style="background-color: #292929">  </span><span style="background-color: #272727">  </span><span style="background-color: #252525">  </span><span style="background-color: #292929">  </span><span style="background-color: #555555">  </span><span style="background-color: #929292">  </span><span style="background-color: #C7C7C7">  </span><span style="background-color: #E5E5E5">  </span><span style="background-color: #F0F0F0">  </span><span style="background-color: #E4E4E4">  </span><span style="background-color: #A8A8A8">  </span><span style="background-color: #515151">  </span><span style="background-color: #202020">  </span><span style="background-color: #191919">  </span><span>                      </span> | ||||
| <span>    </span><span style="background-color: #2E2E2E">  </span><span style="background-color: #2B2B2B">  </span><span style="background-color: #333333">  </span><span style="background-color: #373737">  </span><span style="background-color: #3C3C3C">  </span><span style="background-color: #414141">  </span><span style="background-color: #474747">  </span><span style="background-color: #4B4B4B">  </span><span style="background-color: #454545">  </span><span style="background-color: #828282">  </span><span style="background-color: #E0E0E0">  </span><span style="background-color: #FFFFFF">    </span><span style="background-color: #FCFCFC">  </span><span style="background-color: #DEDEDE">  </span><span style="background-color: #DADADA">  </span><span style="background-color: #BCBCBC">  </span><span style="background-color: #515151">  </span><span style="background-color: #202020">  </span><span style="background-color: #191919">  </span><span>                    </span> | ||||
| <span>    </span><span style="background-color: #272727">  </span><span style="background-color: #414141">  </span><span style="background-color: #5C5C5C">  </span><span style="background-color: #616161">  </span><span style="background-color: #636363">  </span><span style="background-color: #656565">  </span><span style="background-color: #666666">    </span><span style="background-color: #656565">  </span><span style="background-color: #5A5A5A">  </span><span style="background-color: #707070">  </span><span style="background-color: #F3F3F3">  </span><span style="background-color: #FFFFFF">  </span><span style="background-color: #F0F0F0">  </span><span style="background-color: #DDDDDD">      </span><span style="background-color: #BABABA">  </span><span style="background-color: #505050">  </span><span style="background-color: #202020">  </span><span style="background-color: #1B1B1B">  </span><span>                  </span> | ||||
| <span>    </span><span style="background-color: #242424">  </span><span style="background-color: #3B3B3B">  </span><span style="background-color: #545454">  </span><span style="background-color: #606060">  </span><span style="background-color: #656565">  </span><span style="background-color: #666666">        </span><span style="background-color: #606060">  </span><span style="background-color: #575757">  </span><span style="background-color: #E8E8E8">  </span><span style="background-color: #F6F6F6">  </span><span style="background-color: #E1E1E1">  </span><span style="background-color: #DDDDDD">    </span><span style="background-color: #D9D9D9">  </span><span style="background-color: #A0A0A0">  </span><span style="background-color: #989898">  </span><span style="background-color: #4E4E4E">  </span><span style="background-color: #222222">  </span><span>                  </span> | ||||
| <span style="background-color: #2F2F2F">  </span><span style="background-color: #2C2C2C">  </span><span style="background-color: #222222">  </span><span style="background-color: #282828">  </span><span style="background-color: #2D2D2D">  </span><span style="background-color: #3E3E3E">  </span><span style="background-color: #4D4D4D">  </span><span style="background-color: #616161">    </span><span style="background-color: #636363">  </span><span style="background-color: #666666">  </span><span style="background-color: #606060">  </span><span style="background-color: #535353">  </span><span style="background-color: #D4D4D4">  </span><span style="background-color: #E2E2E2">  </span><span style="background-color: #DDDDDD">    </span><span style="background-color: #DCDCDC">  </span><span style="background-color: #AFAFAF">  </span><span style="background-color: #666666">  </span><span style="background-color: #6F6F6F">  </span><span style="background-color: #717171">  </span><span style="background-color: #242424">  </span><span style="background-color: #191919">  </span><span>                </span> | ||||
| <span style="background-color: #2C2C2C">  </span><span style="background-color: #343434">  </span><span style="background-color: #2E2E2E">  </span><span style="background-color: #262626">  </span><span style="background-color: #404040">  </span><span style="background-color: #868686">  </span><span style="background-color: #4D4D4D">  </span><span style="background-color: #5A5A5A">  </span><span style="background-color: #3D3D3D">  </span><span style="background-color: #474747">  </span><span style="background-color: #646464">  </span><span style="background-color: #616161">  </span><span style="background-color: #4D4D4D">  </span><span style="background-color: #9D9D9D">  </span><span style="background-color: #C8C8C8">  </span><span style="background-color: #DADADA">  </span><span style="background-color: #DDDDDD">  </span><span style="background-color: #C4C4C4">  </span><span style="background-color: #717171">  </span><span style="background-color: #5F5F5F">    </span><span style="background-color: #595959">  </span><span style="background-color: #343434">  </span><span style="background-color: #1F1F1F">  </span><span style="background-color: #191919">  </span><span>              </span> | ||||
| <span style="background-color: #343434">  </span><span style="background-color: #575757">  </span><span style="background-color: #555555">  </span><span style="background-color: #454545">  </span><span style="background-color: #4C4C4C">  </span><span style="background-color: #656565">  </span><span style="background-color: #5B5B5B">  </span><span style="background-color: #434343">  </span><span style="background-color: #3E3E3E">  </span><span style="background-color: #595959">  </span><span style="background-color: #666666">    </span><span style="background-color: #606060">  </span><span style="background-color: #595959">  </span><span style="background-color: #5E5E5E">  </span><span style="background-color: #787878">  </span><span style="background-color: #9E9E9E">  </span><span style="background-color: #797979">  </span><span style="background-color: #5E5E5E">  </span><span style="background-color: #5F5F5F">      </span><span style="background-color: #575757">  </span><span style="background-color: #343434">  </span><span style="background-color: #1F1F1F">  </span><span style="background-color: #191919">  </span><span>            </span> | ||||
| <span style="background-color: #2B2B2B">  </span><span style="background-color: #3B3B3B">  </span><span style="background-color: #575757">  </span><span style="background-color: #646464">  </span><span style="background-color: #5F5F5F">  </span><span style="background-color: #5E5E5E">  </span><span style="background-color: #575757">  </span><span style="background-color: #3D3D3D">  </span><span style="background-color: #525252">  </span><span style="background-color: #656565">  </span><span style="background-color: #666666">        </span><span style="background-color: #656565">  </span><span style="background-color: #616161">  </span><span style="background-color: #595959">  </span><span style="background-color: #4B4B4B">  </span><span style="background-color: #454545">  </span><span style="background-color: #4B4B4B">  </span><span style="background-color: #555555">  </span><span style="background-color: #5D5D5D">  </span><span style="background-color: #5F5F5F">  </span><span style="background-color: #575757">  </span><span style="background-color: #343434">  </span><span style="background-color: #1F1F1F">  </span><span style="background-color: #191919">  </span><span>          </span> | ||||
| <span style="background-color: #3A3A3A">  </span><span style="background-color: #292929">  </span><span style="background-color: #323232">  </span><span style="background-color: #4A4A4A">  </span><span style="background-color: #626262">  </span><span style="background-color: #666666">  </span><span style="background-color: #656565">  </span><span style="background-color: #5F5F5F">  </span><span style="background-color: #616161">  </span><span style="background-color: #5E5E5E">  </span><span style="background-color: #616161">  </span><span style="background-color: #5F5F5F">  </span><span style="background-color: #666666">            </span><span style="background-color: #626262">  </span><span style="background-color: #575757">  </span><span style="background-color: #4B4B4B">  </span><span style="background-color: #454545">  </span><span style="background-color: #4A4A4A">  </span><span style="background-color: #545454">    </span><span style="background-color: #343434">  </span><span style="background-color: #1F1F1F">  </span><span style="background-color: #191919">  </span><span>        </span> | ||||
| <span>    </span><span style="background-color: #252525">  </span><span style="background-color: #383838">  </span><span style="background-color: #5F5F5F">  </span><span style="background-color: #616161">  </span><span style="background-color: #5B5B5B">  </span><span style="background-color: #505050">  </span><span style="background-color: #545454">  </span><span style="background-color: #8A8A8A">  </span><span style="background-color: #C5C5C5">  </span><span style="background-color: #959595">  </span><span style="background-color: #5E5E5E">  </span><span style="background-color: #636363">  </span><span style="background-color: #666666">              </span><span style="background-color: #626262">  </span><span style="background-color: #595959">  </span><span style="background-color: #4D4D4D">  </span><span style="background-color: #454545">  </span><span style="background-color: #414141">  </span><span style="background-color: #282828">  </span><span style="background-color: #1E1E1E">  </span><span style="background-color: #1D1D1D">  </span><span>      </span> | ||||
| <span>    </span><span style="background-color: #212121">  </span><span style="background-color: #2C2C2C">  </span><span style="background-color: #4F4F4F">  </span><span style="background-color: #515151">  </span><span style="background-color: #5F5F5F">  </span><span style="background-color: #898989">  </span><span style="background-color: #CDCDCD">  </span><span style="background-color: #E8E8E8">  </span><span style="background-color: #DEDEDE">  </span><span style="background-color: #D8D8D8">  </span><span style="background-color: #939393">  </span><span style="background-color: #4D4D4D">  </span><span style="background-color: #525252">  </span><span style="background-color: #5E5E5E">  </span><span style="background-color: #646464">  </span><span style="background-color: #666666">              </span><span style="background-color: #636363">  </span><span style="background-color: #5A5A5A">  </span><span style="background-color: #4A4A4A">  </span><span style="background-color: #383838">  </span><span style="background-color: #323232">  </span><span style="background-color: #2A2A2A">  </span><span style="background-color: #282828">  </span><span>  </span> | ||||
| <span>    </span><span style="background-color: #272727">  </span><span style="background-color: #404040">  </span><span style="background-color: #C8C8C8">  </span><span style="background-color: #DFDFDF">  </span><span style="background-color: #F0F0F0">  </span><span style="background-color: #FDFDFD">  </span><span style="background-color: #F3F3F3">  </span><span style="background-color: #DFDFDF">  </span><span style="background-color: #DDDDDD">    </span><span style="background-color: #D7D7D7">  </span><span style="background-color: #757575">  </span><span style="background-color: #2B2B2B">  </span><span style="background-color: #333333">  </span><span style="background-color: #444444">  </span><span style="background-color: #535353">  </span><span style="background-color: #5F5F5F">  </span><span style="background-color: #646464">  </span><span style="background-color: #666666">              </span><span style="background-color: #646464">  </span><span style="background-color: #5B5B5B">  </span><span style="background-color: #4F4F4F">  </span><span style="background-color: #3A3A3A">  </span><span style="background-color: #292929">  </span> | ||||
| <span>    </span><span style="background-color: #242424">  </span><span style="background-color: #4F4F4F">  </span><span style="background-color: #E7E7E7">  </span><span style="background-color: #FFFFFF">    </span><span style="background-color: #F2F2F2">  </span><span style="background-color: #DFDFDF">  </span><span style="background-color: #DDDDDD">      </span><span style="background-color: #C2C2C2">  </span><span style="background-color: #6E6E6E">  </span><span style="background-color: #434343">  </span><span style="background-color: #242424">  </span><span style="background-color: #222222">  </span><span style="background-color: #282828">  </span><span style="background-color: #343434">  </span><span style="background-color: #454545">  </span><span style="background-color: #555555">  </span><span style="background-color: #606060">  </span><span style="background-color: #656565">  </span><span style="background-color: #666666">              </span><span style="background-color: #595959">  </span><span style="background-color: #313131">  </span> | ||||
| <span>    </span><span style="background-color: #222222">  </span><span style="background-color: #5F5F5F">  </span><span style="background-color: #F2F2F2">  </span><span style="background-color: #FFFFFF">  </span><span style="background-color: #F4F4F4">  </span><span style="background-color: #D7D7D7">  </span><span style="background-color: #DCDCDC">  </span><span style="background-color: #DDDDDD">    </span><span style="background-color: #D1D1D1">  </span><span style="background-color: #818181">  </span><span style="background-color: #5F5F5F">  </span><span style="background-color: #5D5D5D">  </span><span style="background-color: #434343">  </span><span style="background-color: #242424">  </span><span style="background-color: #202020">    </span><span style="background-color: #222222">  </span><span style="background-color: #282828">  </span><span style="background-color: #353535">  </span><span style="background-color: #464646">  </span><span style="background-color: #565656">  </span><span style="background-color: #606060">  </span><span style="background-color: #656565">  </span><span style="background-color: #666666">        </span><span style="background-color: #585858">  </span><span style="background-color: #333333">  </span> | ||||
| <span>    </span><span style="background-color: #222222">  </span><span style="background-color: #707070">  </span><span style="background-color: #FAFAFA">    </span><span style="background-color: #D2D2D2">  </span><span style="background-color: #D9D9D9">  </span><span style="background-color: #DDDDDD">    </span><span style="background-color: #D9D9D9">  </span><span style="background-color: #979797">  </span><span style="background-color: #616161">  </span><span style="background-color: #5F5F5F">    </span><span style="background-color: #5D5D5D">  </span><span style="background-color: #434343">  </span><span style="background-color: #242424">  </span><span style="background-color: #202020">        </span><span style="background-color: #222222">  </span><span style="background-color: #292929">  </span><span style="background-color: #363636">  </span><span style="background-color: #474747">  </span><span style="background-color: #575757">  </span><span style="background-color: #606060">  </span><span style="background-color: #616161">  </span><span style="background-color: #575757">  </span><span style="background-color: #404040">  </span><span style="background-color: #2B2B2B">  </span> | ||||
| <span>    </span><span style="background-color: #212121">  </span><span style="background-color: #858585">  </span><span style="background-color: #FCFCFC">  </span><span style="background-color: #D9D9D9">  </span><span style="background-color: #D2D2D2">  </span><span style="background-color: #DDDDDD">    </span><span style="background-color: #DCDCDC">  </span><span style="background-color: #AEAEAE">  </span><span style="background-color: #666666">  </span><span style="background-color: #5F5F5F">        </span><span style="background-color: #5D5D5D">  </span><span style="background-color: #434343">  </span><span style="background-color: #242424">  </span><span style="background-color: #202020">            </span><span style="background-color: #222222">  </span><span style="background-color: #292929">  </span><span style="background-color: #363636">  </span><span style="background-color: #3E3E3E">  </span><span style="background-color: #363636">  </span><span style="background-color: #2B2B2B">  </span><span style="background-color: #282828">  </span> | ||||
| <span>    </span><span style="background-color: #222222">  </span><span style="background-color: #9B9B9B">  </span><span style="background-color: #EAEAEA">  </span><span style="background-color: #D0D0D0">  </span><span style="background-color: #DDDDDD">      </span><span style="background-color: #C3C3C3">  </span><span style="background-color: #707070">  </span><span style="background-color: #5F5F5F">            </span><span style="background-color: #5D5D5D">  </span><span style="background-color: #434343">  </span><span style="background-color: #242424">  </span><span style="background-color: #202020">              </span><span style="background-color: #212121">  </span><span style="background-color: #242424">  </span><span style="background-color: #272727">  </span><span style="background-color: #2C2C2C">  </span><span>  </span> | ||||
| <span>    </span><span style="background-color: #292929">  </span><span style="background-color: #ACACAC">  </span><span style="background-color: #DDDDDD">  </span><span style="background-color: #DCDCDC">  </span><span style="background-color: #DDDDDD">    </span><span style="background-color: #D1D1D1">  </span><span style="background-color: #818181">  </span><span style="background-color: #5F5F5F">                </span><span style="background-color: #5D5D5D">  </span><span style="background-color: #434343">  </span><span style="background-color: #242424">  </span><span style="background-color: #202020">    </span><span style="background-color: #212121">  </span><span style="background-color: #222222">  </span><span style="background-color: #232323">  </span><span style="background-color: #242424">  </span><span style="background-color: #262626">  </span><span style="background-color: #2E2E2E">  </span><span>      </span> | ||||
| <span>    </span><span style="background-color: #2D2D2D">  </span><span style="background-color: #A6A6A6">  </span><span style="background-color: #DDDDDD">      </span><span style="background-color: #D9D9D9">  </span><span style="background-color: #989898">  </span><span style="background-color: #616161">  </span><span style="background-color: #5F5F5F">                  </span><span style="background-color: #5D5D5D">  </span><span style="background-color: #3E3E3E">  </span><span style="background-color: #222222">  </span><span style="background-color: #242424">  </span><span style="background-color: #262626">  </span><span style="background-color: #2B2B2B">  </span><span style="background-color: #363636">  </span><span>            </span> | ||||
| <span>    </span><span style="background-color: #212121">  </span><span style="background-color: #575757">  </span><span style="background-color: #BEBEBE">  </span><span style="background-color: #DDDDDD">  </span><span style="background-color: #DCDCDC">  </span><span style="background-color: #AFAFAF">  </span><span style="background-color: #666666">  </span><span style="background-color: #5F5F5F">                    </span><span style="background-color: #5B5B5B">  </span><span style="background-color: #373737">  </span><span style="background-color: #222222">  </span><span>                    </span> | ||||
| <span>    </span><span style="background-color: #171717">  </span><span style="background-color: #212121">  </span><span style="background-color: #585858">  </span><span style="background-color: #BEBEBE">  </span><span style="background-color: #C3C3C3">  </span><span style="background-color: #717171">  </span><span style="background-color: #5F5F5F">                    </span><span style="background-color: #5E5E5E">  </span><span style="background-color: #424242">  </span><span style="background-color: #252525">  </span><span style="background-color: #242424">  </span><span>                    </span> | ||||
| <span>      </span><span style="background-color: #171717">  </span><span style="background-color: #212121">  </span><span style="background-color: #545454">  </span><span style="background-color: #717171">  </span><span style="background-color: #5F5F5F">                      </span><span style="background-color: #4D4D4D">  </span><span style="background-color: #292929">  </span><span style="background-color: #232323">  </span><span>                      </span> | ||||
| <span>        </span><span style="background-color: #171717">  </span><span style="background-color: #1F1F1F">  </span><span style="background-color: #343434">  </span><span style="background-color: #565656">  </span><span style="background-color: #5F5F5F">                  </span><span style="background-color: #565656">  </span><span style="background-color: #303030">  </span><span style="background-color: #222222">  </span><span>                        </span> | ||||
| <span>          </span><span style="background-color: #171717">  </span><span style="background-color: #1F1F1F">  </span><span style="background-color: #343434">  </span><span style="background-color: #565656">  </span><span style="background-color: #5F5F5F">              </span><span style="background-color: #5C5C5C">  </span><span style="background-color: #393939">  </span><span style="background-color: #232323">  </span><span style="background-color: #252525">  </span><span>                        </span> | ||||
| <span>            </span><span style="background-color: #171717">  </span><span style="background-color: #1F1F1F">  </span><span style="background-color: #343434">  </span><span style="background-color: #565656">  </span><span style="background-color: #5F5F5F">          </span><span style="background-color: #5E5E5E">  </span><span style="background-color: #444444">  </span><span style="background-color: #252525">  </span><span style="background-color: #222222">  </span><span>                          </span> | ||||
| <span>              </span><span style="background-color: #171717">  </span><span style="background-color: #1F1F1F">  </span><span style="background-color: #343434">  </span><span style="background-color: #565656">  </span><span style="background-color: #5F5F5F">        </span><span style="background-color: #4F4F4F">  </span><span style="background-color: #2A2A2A">  </span><span style="background-color: #222222">  </span><span>                            </span> | ||||
| <span>                </span><span style="background-color: #171717">  </span><span style="background-color: #1F1F1F">  </span><span style="background-color: #343434">  </span><span style="background-color: #565656">  </span><span style="background-color: #5F5F5F">    </span><span style="background-color: #575757">  </span><span style="background-color: #323232">  </span><span style="background-color: #222222">  </span><span>                              </span> | ||||
| <span>                  </span><span style="background-color: #171717">  </span><span style="background-color: #1F1F1F">  </span><span style="background-color: #343434">  </span><span style="background-color: #565656">  </span><span style="background-color: #5C5C5C">  </span><span style="background-color: #3C3C3C">  </span><span style="background-color: #232323">  </span><span style="background-color: #252525">  </span><span>                              </span> | ||||
| <span>                    </span><span style="background-color: #171717">  </span><span style="background-color: #1F1F1F">  </span><span style="background-color: #343434">  </span><span style="background-color: #404040">  </span><span style="background-color: #262626">  </span><span style="background-color: #232323">  </span><span>                                </span> | ||||
| <span>                      </span><span style="background-color: #171717">  </span><span style="background-color: #1E1E1E">  </span><span style="background-color: #222222">    </span><span>                                  </span> | ||||
| </pre> | ||||
							
								
								
									
										52
									
								
								docs/input/widgets/canvas.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,52 @@ | ||||
| Title: Canvas | ||||
| Order: 4 | ||||
| --- | ||||
|  | ||||
| `Canvas` is a widget that allows you to render arbitrary "pixels"  | ||||
| (or _coxels_, as [Simon Cropp](https://twitter.com/SimonCropp/status/1331554791726534657?s=20)  | ||||
| suggested we should call them). | ||||
|  | ||||
| # Drawing primitives | ||||
|  | ||||
| ```csharp | ||||
| // Create a canvas | ||||
| var canvas = new Canvas(16, 16); | ||||
|  | ||||
| // Draw some shapes | ||||
| for(var i = 0; i < canvas.Width; i++) | ||||
| { | ||||
|     // Cross | ||||
|     canvas.SetPixel(i, i, Color.White); | ||||
|     canvas.SetPixel(canvas.Width - i - 1, i, Color.White); | ||||
|  | ||||
|     // Border | ||||
|     canvas.SetPixel(i, 0, Color.Red); | ||||
|     canvas.SetPixel(0, i, Color.Green); | ||||
|     canvas.SetPixel(i, canvas.Height - 1, Color.Blue); | ||||
|     canvas.SetPixel(canvas.Width - 1, i, Color.Yellow); | ||||
| } | ||||
|  | ||||
| // Render the canvas | ||||
| AnsiConsole.Render(canvas); | ||||
| ``` | ||||
|  | ||||
| ## Result | ||||
|  | ||||
| <pre style="font-size:100%;font-family:consolas,'Courier New',monospace;line-height: normal; padding: 0px;background-color: #222222; padding: 20px;"> | ||||
| <span style="background-color: #008000">  </span><span style="background-color: #FF0000">                              </span> | ||||
| <span style="background-color: #008000">  </span><span style="background-color: #800080">  </span><span>                        </span><span style="background-color: #800080">  </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span>  </span><span style="background-color: #800080">  </span><span>                    </span><span style="background-color: #800080">  </span><span>  </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span>    </span><span style="background-color: #800080">  </span><span>                </span><span style="background-color: #800080">  </span><span>    </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span>      </span><span style="background-color: #800080">  </span><span>            </span><span style="background-color: #800080">  </span><span>      </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span>        </span><span style="background-color: #800080">  </span><span>        </span><span style="background-color: #800080">  </span><span>        </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span>          </span><span style="background-color: #800080">  </span><span>    </span><span style="background-color: #800080">  </span><span>          </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span>            </span><span style="background-color: #800080">    </span><span>            </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span>            </span><span style="background-color: #800080">    </span><span>            </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span>          </span><span style="background-color: #800080">  </span><span>    </span><span style="background-color: #800080">  </span><span>          </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span>        </span><span style="background-color: #800080">  </span><span>        </span><span style="background-color: #800080">  </span><span>        </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span>      </span><span style="background-color: #800080">  </span><span>            </span><span style="background-color: #800080">  </span><span>      </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span>    </span><span style="background-color: #800080">  </span><span>                </span><span style="background-color: #800080">  </span><span>    </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span>  </span><span style="background-color: #800080">  </span><span>                    </span><span style="background-color: #800080">  </span><span>  </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span style="background-color: #800080">  </span><span>                        </span><span style="background-color: #800080">  </span><span style="background-color: #FFFF00">  </span> | ||||
| <span style="background-color: #008000">  </span><span style="background-color: #0000FF">                            </span><span style="background-color: #FFFF00">  </span> | ||||
| </pre> | ||||
							
								
								
									
										34
									
								
								docs/input/widgets/figlet.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,34 @@ | ||||
| Title: Figlet | ||||
| Order: 3 | ||||
| RedirectFrom: figlet | ||||
| --- | ||||
|  | ||||
| Spectre.Console can render [FIGlet](http://www.figlet.org/) text by using the `FigletText` class. | ||||
|  | ||||
| # Default font | ||||
|  | ||||
| ```csharp | ||||
| AnsiConsole.Render( | ||||
|     new FigletText("Hello") | ||||
|         .LeftAligned() | ||||
|         .Color(Color.Red)); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
|  _   _          _   _           | ||||
| | | | |   ___  | | | |   ___   | ||||
| | |_| |  / _ \ | | | |  / _ \  | ||||
| |  _  | |  __/ | | | | | (_) | | ||||
| |_| |_|  \___| |_| |_|  \___/  | ||||
| ``` | ||||
|  | ||||
| # Custom font | ||||
|  | ||||
| ```csharp | ||||
| var font = FigletFont.Load("starwars.flf"); | ||||
|  | ||||
| AnsiConsole.Render( | ||||
|     new FigletText(font, "Hello") | ||||
|         .LeftAligned() | ||||
|         .Color(Color.Red)); | ||||
| ``` | ||||
							
								
								
									
										12
									
								
								docs/input/widgets/index.cshtml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | ||||
| Title: Widgets | ||||
| Order: 9 | ||||
| --- | ||||
|  | ||||
| <h1>Sections</h1> | ||||
|  | ||||
| <ul> | ||||
| @foreach (IDocument child in OutputPages.GetChildrenOf(Document)) | ||||
| { | ||||
|   <li>@Html.DocumentLink(child)</li> | ||||
| } | ||||
| </ul> | ||||
							
								
								
									
										72
									
								
								docs/input/widgets/rule.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,72 @@ | ||||
| Title: Rule | ||||
| Order: 1 | ||||
| RedirectFrom: rule | ||||
| --- | ||||
|  | ||||
| The `Rule` class is used to render a horizontal rule (line) to the terminal. | ||||
|  | ||||
| <img src="../assets/images/rule.png" style="width: 100%;" /> | ||||
|  | ||||
| # 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); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
| ───────────────────────────────── 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); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
| ── Hello ──────────────────────────────────────────────────────────────── | ||||
| ``` | ||||
|  | ||||
| You can also specify it via an extension method: | ||||
|  | ||||
| ```csharp | ||||
| var rule = new Rule("[red]Hello[/]"); | ||||
| rule.LeftAligned(); | ||||
| AnsiConsole.Render(rule); | ||||
| ``` | ||||
|  | ||||
| ```text | ||||
| ── Hello ──────────────────────────────────────────────────────────────── | ||||
| ``` | ||||
|  | ||||
|  | ||||
| ## Styling | ||||
|  | ||||
| ```csharp | ||||
| var rule = new Rule("[red]Hello[/]"); | ||||
| rule.Style = Style.Parse("red dim"); | ||||
| AnsiConsole.Render(rule); | ||||
| ``` | ||||
| You can also specify it via an extension method | ||||
|  | ||||
| ```csharp | ||||
| var rule = new Rule("[red]Hello[/]"); | ||||
| rule.RuleStyle("red dim"); | ||||
| AnsiConsole.Render(rule); | ||||
| ``` | ||||
| @@ -1,5 +1,6 @@ | ||||
| Title: Tables | ||||
| Order: 3 | ||||
| Title: Table | ||||
| Order: 0 | ||||
| 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 appearance | ||||
| 
 | ||||
| @@ -50,10 +51,10 @@ For a list of borders, see the [Borders](xref:borders) appendix section. | ||||
| 
 | ||||
| ```csharp | ||||
| // Sets the border | ||||
| table.SetBorder(Border.None); | ||||
| table.SetBorder(Border.Ascii); | ||||
| table.SetBorder(Border.Square); | ||||
| table.SetBorder(Border.Rounded); | ||||
| table.Border(TableBorder.None); | ||||
| table.Border(TableBorder.Ascii); | ||||
| table.Border(TableBorder.Square); | ||||
| table.Border(TableBorder.Rounded); | ||||
| ``` | ||||
| 
 | ||||
| ## Expand / Collapse | ||||
| @@ -78,7 +79,16 @@ table.HideHeaders(); | ||||
| 
 | ||||
| ```csharp | ||||
| // Sets the table width to 50 cells | ||||
| table.SetWidth(50); | ||||
| table.Width(50); | ||||
| ``` | ||||
| 
 | ||||
| ## Alignment | ||||
| 
 | ||||
| ```csharp | ||||
| table.Alignment(Justify.Right); | ||||
| table.RightAligned(); | ||||
| table.Centered(); | ||||
| table.LeftAligned(); | ||||
| ``` | ||||
| 
 | ||||
| # Column appearance | ||||
| @@ -90,31 +100,37 @@ table.SetWidth(50); | ||||
| ## Alignment | ||||
| 
 | ||||
| ```csharp | ||||
| // Set the alignment explicitly | ||||
| column.SetAlignment(Justify.Right); | ||||
| table.Columns[0].Alignment(Justify.Right); | ||||
| table.Columns[0].LeftAligned(); | ||||
| table.Columns[0].Centered(); | ||||
| table.Columns[0].RightAligned(); | ||||
| ``` | ||||
| 
 | ||||
| ## Padding | ||||
| 
 | ||||
| ```csharp | ||||
| // Set left and right padding | ||||
| column.SetPadding(left: 3, right: 5); | ||||
| // Set padding individually | ||||
| table.Columns[0].PadLeft(3); | ||||
| table.Columns[0].PadRight(5); | ||||
| 
 | ||||
| // Set padding individually. | ||||
| column.PadLeft(3); | ||||
| column.PadRight(5); | ||||
| // Or chained together | ||||
| table.Columns[0].PadLeft(3).PadRight(5); | ||||
| 
 | ||||
| // Or with the shorthand method if the left and right  | ||||
| // padding are identical. Vertical padding is ignored. | ||||
| table.Columns[0].Padding(4, 0); | ||||
| ``` | ||||
| 
 | ||||
| ## Disable column wrapping | ||||
| 
 | ||||
| ```csharp | ||||
| // Disable column wrapping | ||||
| column.NoWrap(); | ||||
| table.Columns[0].NoWrap(); | ||||
| ``` | ||||
| 
 | ||||
| ## Set column width | ||||
| 
 | ||||
| ```csharp | ||||
| // Set the column width (no fluent extension method for this yet) | ||||
| column.Width = 15; | ||||
| // Set the column width | ||||
| table.Columns[0].Width(15); | ||||
| ``` | ||||
| @@ -3,7 +3,7 @@ | ||||
|   "isRoot": true, | ||||
|   "tools": { | ||||
|     "cake.tool": { | ||||
|       "version": "0.38.4", | ||||
|       "version": "1.0.0-rc0001", | ||||
|       "commands": [ | ||||
|         "dotnet-cake" | ||||
|       ] | ||||
| @@ -15,7 +15,7 @@ | ||||
|       ] | ||||
|     }, | ||||
|     "dotnet-example": { | ||||
|       "version": "0.8.0", | ||||
|       "version": "1.1.0", | ||||
|       "commands": [ | ||||
|         "dotnet-example" | ||||
|       ] | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Borders</Title> | ||||
|     <Description>Demonstrates the different kind of borders.</Description> | ||||
|   | ||||
| @@ -8,26 +8,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($" [blue]{name}[/] ", Justify.Center) | ||||
|                     .Border(border) | ||||
|                     .BorderStyle(Style.Parse("grey")); | ||||
|             } | ||||
|  | ||||
|             var items = new[] | ||||
| @@ -46,19 +42,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($" [blue]{name}[/] ", Justify.Center) | ||||
|                     .NoBorder(); | ||||
|             } | ||||
|  | ||||
| @@ -85,5 +80,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(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										15
									
								
								examples/Calendars/Calendars.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>net5.0</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> | ||||
							
								
								
									
										19
									
								
								examples/Calendars/Program.cs
									
									
									
									
									
										Normal 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)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										22
									
								
								examples/Canvas/Canvas.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Canvas</Title> | ||||
|     <Description>Demonstrates how to render pixels and images.</Description> | ||||
|   </PropertyGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\..\src\Spectre.Console.ImageSharp\Spectre.Console.ImageSharp.csproj" /> | ||||
|     <ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <None Update="cake.png"> | ||||
|       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||
|     </None> | ||||
|   </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
							
								
								
									
										87
									
								
								examples/Canvas/Mandelbrot.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,87 @@ | ||||
| /* | ||||
| Ported from: https://rosettacode.org/wiki/Mandelbrot_set#C.23 | ||||
| Licensed under GNU Free Documentation License 1.2 | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using Spectre.Console; | ||||
|  | ||||
| namespace CanvasExample | ||||
| { | ||||
|     public static class Mandelbrot | ||||
|     { | ||||
|         private const double MaxValueExtent = 2.0; | ||||
|  | ||||
|         private struct ComplexNumber | ||||
|         { | ||||
|             public double Real { get; } | ||||
|             public double Imaginary { get; } | ||||
|  | ||||
|             public ComplexNumber(double real, double imaginary) | ||||
|             { | ||||
|                 Real = real; | ||||
|                 Imaginary = imaginary; | ||||
|             } | ||||
|  | ||||
|             public static ComplexNumber operator +(ComplexNumber x, ComplexNumber y) | ||||
|             { | ||||
|                 return new ComplexNumber(x.Real + y.Real, x.Imaginary + y.Imaginary); | ||||
|             } | ||||
|  | ||||
|             public static ComplexNumber operator *(ComplexNumber x, ComplexNumber y) | ||||
|             { | ||||
|                 return new ComplexNumber(x.Real * y.Real - x.Imaginary * y.Imaginary, | ||||
|                     x.Real * y.Imaginary + x.Imaginary * y.Real); | ||||
|             } | ||||
|  | ||||
|             public double Abs() | ||||
|             { | ||||
|                 return Real * Real + Imaginary * Imaginary; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public static Canvas Generate(int width, int height) | ||||
|         { | ||||
|             var canvas = new Canvas(width, height); | ||||
|  | ||||
|             var scale = 2 * MaxValueExtent / Math.Min(canvas.Width, canvas.Height); | ||||
|             for (var i = 0; i < canvas.Height; i++) | ||||
|             { | ||||
|                 var y = (canvas.Height / 2 - i) * scale; | ||||
|                 for (var j = 0; j < canvas.Width; j++) | ||||
|                 { | ||||
|                     var x = (j - canvas.Width / 2) * scale; | ||||
|                     var value = Calculate(new ComplexNumber(x, y)); | ||||
|                     canvas.SetPixel(j, i, GetColor(value)); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return canvas; | ||||
|         } | ||||
|  | ||||
|         private static double Calculate(ComplexNumber c) | ||||
|         { | ||||
|             const int MaxIterations = 1000; | ||||
|             const double MaxNorm = MaxValueExtent * MaxValueExtent; | ||||
|  | ||||
|             var iteration = 0; | ||||
|             var z = new ComplexNumber(); | ||||
|             do | ||||
|             { | ||||
|                 z = z * z + c; | ||||
|                 iteration++; | ||||
|             } while (z.Abs() < MaxNorm && iteration < MaxIterations); | ||||
|  | ||||
|             return iteration < MaxIterations | ||||
|                 ? (double)iteration / MaxIterations | ||||
|                 : 0; | ||||
|         } | ||||
|  | ||||
|         private static Color GetColor(double value) | ||||
|         { | ||||
|             const double MaxColor = 256; | ||||
|             const double ContrastValue = 0.2; | ||||
|             return new Color(0, 0, (byte)(MaxColor * Math.Pow(value, ContrastValue))); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										36
									
								
								examples/Canvas/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,36 @@ | ||||
| using SixLabors.ImageSharp.Processing; | ||||
| using Spectre.Console; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace CanvasExample | ||||
| { | ||||
|     public static class Program | ||||
|     { | ||||
|         public static void Main() | ||||
|         { | ||||
|             // Draw a mandelbrot set using a Canvas | ||||
|             var mandelbrot = Mandelbrot.Generate(32, 32); | ||||
|             Render(mandelbrot, "Mandelbrot"); | ||||
|  | ||||
|             // Draw an image using CanvasImage powered by ImageSharp. | ||||
|             // This requires the "Spectre.Console.ImageSharp" NuGet package. | ||||
|             var image = new CanvasImage("cake.png"); | ||||
|             image.BilinearResampler(); | ||||
|             image.MaxWidth(16); | ||||
|             Render(image, "Image from file (16 wide)"); | ||||
|  | ||||
|             // Draw image again, but without render width | ||||
|             image.NoMaxWidth(); | ||||
|             image.Mutate(ctx => ctx.Grayscale().Rotate(-45).EntropyCrop()); | ||||
|             Render(image, "Image from file (fit, greyscale, rotated)"); | ||||
|         } | ||||
|  | ||||
|         private static void Render(IRenderable canvas, string title) | ||||
|         { | ||||
|             AnsiConsole.WriteLine(); | ||||
|             AnsiConsole.Render(new Rule($"[yellow]{title}[/]").LeftAligned().RuleStyle("grey")); | ||||
|             AnsiConsole.WriteLine(); | ||||
|             AnsiConsole.Render(canvas); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								examples/Canvas/cake.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 52 KiB | 
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Colors</Title> | ||||
|     <Description>Demonstrates how to use [yellow]c[/][red]o[/][green]l[/][blue]o[/][aqua]r[/][lime]s[/] in the console.</Description> | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Columns</Title> | ||||
|     <Description>Demonstrates how to render data into columns.</Description> | ||||
|   | ||||
| @@ -1,26 +1,18 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Net.Http; | ||||
| using System.Threading.Tasks; | ||||
| using Newtonsoft.Json.Linq; | ||||
| using Spectre.Console; | ||||
|  | ||||
| namespace ColumnsExample | ||||
| { | ||||
|     public static class Program | ||||
|     { | ||||
|         public static async Task Main() | ||||
|         public static void Main() | ||||
|         { | ||||
|             // Download some random users | ||||
|             using var client = new HttpClient(); | ||||
|             dynamic users = JObject.Parse( | ||||
|                 await client.GetStringAsync("https://randomuser.me/api/?results=15")); | ||||
|  | ||||
|             // Create a card for each user | ||||
|             var cards = new List<Panel>(); | ||||
|             foreach(var user in users.results) | ||||
|             foreach(var user in User.LoadUsers()) | ||||
|             { | ||||
|                 cards.Add(new Panel(GetCard(user)) | ||||
|                     .SetHeader($"{user.location.country}") | ||||
|                 cards.Add( | ||||
|                     new Panel(GetCardContent(user)) | ||||
|                         .Header($"{user.Country}") | ||||
|                         .RoundedBorder().Expand()); | ||||
|             } | ||||
|  | ||||
| @@ -28,12 +20,12 @@ namespace ColumnsExample | ||||
|             AnsiConsole.Render(new Columns(cards)); | ||||
|         } | ||||
|  | ||||
|         private static string GetCard(dynamic user) | ||||
|         private static string GetCardContent(User user) | ||||
|         { | ||||
|             var name = $"{user.name.first} {user.name.last}"; | ||||
|             var country = $"{user.location.city}"; | ||||
|             var name = $"{user.FirstName} {user.LastName}"; | ||||
|             var city = $"{user.City}"; | ||||
|  | ||||
|             return $"[b]{name}[/]\n[yellow]{country}[/]"; | ||||
|             return $"[b]{name}[/]\n[yellow]{city}[/]"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										89
									
								
								examples/Columns/User.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,89 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace ColumnsExample | ||||
| { | ||||
|     public sealed class User | ||||
|     { | ||||
|         public string FirstName { get; set; } | ||||
|         public string LastName { get; set; } | ||||
|         public string City { get; set; } | ||||
|         public string Country { get; set; } | ||||
|  | ||||
|         public static List<User> LoadUsers() | ||||
|         { | ||||
|             return new List<User> | ||||
|             { | ||||
|                 new User | ||||
|                 { | ||||
|                     FirstName = "Andrea", | ||||
|                     LastName = "Johansen", | ||||
|                     City = "Hornbæk", | ||||
|                     Country = "Denmark", | ||||
|                 }, | ||||
|                 new User | ||||
|                 { | ||||
|                     FirstName = "Brandon", | ||||
|                     LastName = "Cole", | ||||
|                     City = "Washington", | ||||
|                     Country = "United States", | ||||
|                 }, | ||||
|                 new User | ||||
|                 { | ||||
|                     FirstName = "Patrik", | ||||
|                     LastName = "Svensson", | ||||
|                     City = "Stockholm", | ||||
|                     Country = "Sweden", | ||||
|                 }, | ||||
|                 new User | ||||
|                 { | ||||
|                     FirstName = "Freya", | ||||
|                     LastName = "Thompson", | ||||
|                     City = "Rotorua", | ||||
|                     Country = "New Zealand", | ||||
|                 }, | ||||
|                 new User | ||||
|                 { | ||||
|                     FirstName = "طاها", | ||||
|                     LastName = "رضایی", | ||||
|                     City = "اهواز", | ||||
|                     Country = "Iran", | ||||
|                 }, | ||||
|                 new User | ||||
|                 { | ||||
|                     FirstName = "Yara", | ||||
|                     LastName = "Simon", | ||||
|                     City = "Develier", | ||||
|                     Country = "Switzerland", | ||||
|                 }, | ||||
|                 new User | ||||
|                 { | ||||
|                     FirstName = "Giray", | ||||
|                     LastName = "Erbay", | ||||
|                     City = "Karabük", | ||||
|                     Country = "Turkey", | ||||
|                 }, | ||||
|                 new User | ||||
|                 { | ||||
|                     FirstName = "Miodrag", | ||||
|                     LastName = "Schaffer", | ||||
|                     City = "Möckern", | ||||
|                     Country = "Germany", | ||||
|                 }, | ||||
|                 new User | ||||
|                 { | ||||
|                     FirstName = "Carmela", | ||||
|                     LastName = "Lo Castro", | ||||
|                     City = "Firenze", | ||||
|                     Country = "Italy", | ||||
|                 }, | ||||
|                 new User | ||||
|                 { | ||||
|                     FirstName = "Roberto", | ||||
|                     LastName = "Sims", | ||||
|                     City = "Mallow", | ||||
|                     Country = "Ireland", | ||||
|                 }, | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										15
									
								
								examples/Cursor/Cursor.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Cursor</Title> | ||||
|     <Description>Demonstrates how to move the cursor.</Description> | ||||
|   </PropertyGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
							
								
								
									
										20
									
								
								examples/Cursor/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,20 @@ | ||||
| using Spectre.Console; | ||||
|  | ||||
| namespace Cursor | ||||
| { | ||||
|     public static class Program | ||||
|     { | ||||
|         public static void Main(string[] args) | ||||
|         { | ||||
|             AnsiConsole.Write("Hello"); | ||||
|  | ||||
|             // Move the cursor 3 cells to the right | ||||
|             AnsiConsole.Cursor.Move(CursorDirection.Right, 3); | ||||
|             AnsiConsole.Write("World"); | ||||
|  | ||||
|             // Move the cursor 5 cells to the left. | ||||
|             AnsiConsole.Cursor.Move(CursorDirection.Left, 5); | ||||
|             AnsiConsole.WriteLine("Universe"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Emojis</Title> | ||||
|     <Description>Demonstrates how to render emojis.</Description> | ||||
|   | ||||
| @@ -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()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Exceptions</Title> | ||||
|     <Description>Demonstrates how to render formatted exceptions.</Description> | ||||
|   | ||||
| @@ -14,11 +14,35 @@ namespace Exceptions | ||||
|             } | ||||
|             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), | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
							
								
								
									
										15
									
								
								examples/Figlet/Figlet.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Figlet</Title> | ||||
|     <Description>Demonstrates how to render FIGlet text.</Description> | ||||
|   </PropertyGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
							
								
								
									
										14
									
								
								examples/Figlet/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,14 @@ | ||||
| using Spectre.Console; | ||||
|  | ||||
| namespace EmojiExample | ||||
| { | ||||
|     public static class Program | ||||
|     { | ||||
|         public static void Main(string[] args) | ||||
|         { | ||||
|             AnsiConsole.Render(new FigletText("Left aligned").LeftAligned().Color(Color.Red)); | ||||
|             AnsiConsole.Render(new FigletText("Centered").Centered().Color(Color.Green)); | ||||
|             AnsiConsole.Render(new FigletText("Right aligned").RightAligned().Color(Color.Blue)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Grids</Title> | ||||
|     <Description>Demonstrates how to render grids in a console.</Description> | ||||
|   | ||||
| @@ -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); | ||||
|         } | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Info</Title> | ||||
|     <Description>Displays the capabilities of the current console.</Description> | ||||
|   | ||||
| @@ -12,12 +12,13 @@ namespace InfoExample | ||||
|                 .AddRow("[b]Color system[/]", $"{AnsiConsole.Capabilities.ColorSystem}") | ||||
|                 .AddRow("[b]Supports ansi?[/]", $"{YesNo(AnsiConsole.Capabilities.SupportsAnsi)}") | ||||
|                 .AddRow("[b]Legacy console?[/]", $"{YesNo(AnsiConsole.Capabilities.LegacyConsole)}") | ||||
|                 .AddRow("[b]Interactive?[/]", $"{YesNo(AnsiConsole.Capabilities.SupportsInteraction)}") | ||||
|                 .AddRow("[b]Buffer width[/]", $"{AnsiConsole.Console.Width}") | ||||
|                 .AddRow("[b]Buffer height[/]", $"{AnsiConsole.Console.Height}"); | ||||
|  | ||||
|             AnsiConsole.Render( | ||||
|                 new Panel(grid) | ||||
|                     .SetHeader("Information")); | ||||
|                     .Header("Information")); | ||||
|         } | ||||
|  | ||||
|         private static string YesNo(bool value) | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Links</Title> | ||||
|     <Description>Demonstrates how to render links in a console.</Description> | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Panels</Title> | ||||
|     <Description>Demonstrates how to render items in panels.</Description> | ||||
|   | ||||
| @@ -13,28 +13,30 @@ 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("[red]Left[/]")); | ||||
|  | ||||
|             // 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("[green]Center[/]") | ||||
|                     .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("[blue]Right[/]") | ||||
|                     .HeaderAlignment(Justify.Right)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										45
									
								
								examples/Progress/DescriptionGenerator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,45 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace ProgressExample | ||||
| { | ||||
|     public static class DescriptionGenerator | ||||
|     { | ||||
|         private static readonly string[] _verbs = new[] { "Downloading", "Rerouting", "Retriculating", "Collapsing", "Folding", "Solving", "Colliding", "Measuring" }; | ||||
|         private static readonly string[] _nouns = new[] { "internet", "splines", "space", "capacitators", "quarks", "algorithms", "data structures", "spacetime" }; | ||||
|  | ||||
|         private static readonly Random _random; | ||||
|         private static readonly HashSet<string> _used; | ||||
|  | ||||
|         static DescriptionGenerator() | ||||
|         { | ||||
|             _random = new Random(DateTime.Now.Millisecond); | ||||
|             _used = new HashSet<string>(); | ||||
|         } | ||||
|  | ||||
|         public static bool TryGenerate(out string name) | ||||
|         { | ||||
|             var iterations = 0; | ||||
|             while (iterations < 25) | ||||
|             { | ||||
|                 name = Generate(); | ||||
|                 if (!_used.Contains(name)) | ||||
|                 { | ||||
|                     _used.Add(name); | ||||
|                     return true; | ||||
|                 } | ||||
|  | ||||
|                 iterations++; | ||||
|             } | ||||
|  | ||||
|             name = Generate(); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         public static string Generate() | ||||
|         { | ||||
|             return _verbs[_random.Next(0, _verbs.Length)] | ||||
|                 + " " + _nouns[_random.Next(0, _nouns.Length)]; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										75
									
								
								examples/Progress/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,75 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Threading; | ||||
| using Spectre.Console; | ||||
|  | ||||
| namespace ProgressExample | ||||
| { | ||||
|     public static class Program | ||||
|     { | ||||
|         public static void Main() | ||||
|         { | ||||
|             AnsiConsole.MarkupLine("[yellow]Initializing warp drive[/]..."); | ||||
|  | ||||
|             // Show progress | ||||
|             AnsiConsole.Progress() | ||||
|                 .AutoClear(false) | ||||
|                 .Columns(new ProgressColumn[] | ||||
|                 { | ||||
|                     new TaskDescriptionColumn(),    // Task description | ||||
|                     new ProgressBarColumn(),        // Progress bar | ||||
|                     new PercentageColumn(),         // Percentage | ||||
|                     new RemainingTimeColumn(),      // Remaining time | ||||
|                     new SpinnerColumn(),            // Spinner | ||||
|                 }) | ||||
|                 .Start(ctx => | ||||
|                 { | ||||
|                     var random = new Random(DateTime.Now.Millisecond); | ||||
|                     var tasks = CreateTasks(ctx, random); | ||||
|  | ||||
|                     while (!ctx.IsFinished) | ||||
|                     { | ||||
|                         // Increment progress | ||||
|                         foreach (var (task, increment) in tasks) | ||||
|                         { | ||||
|                             task.Increment(random.NextDouble() * increment); | ||||
|                         } | ||||
|  | ||||
|                         // Write some random things to the terminal | ||||
|                         if (random.NextDouble() < 0.1) | ||||
|                         { | ||||
|                             WriteLogMessage(); | ||||
|                         } | ||||
|  | ||||
|                         // Simulate some delay | ||||
|                         Thread.Sleep(100); | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|             // Done | ||||
|             AnsiConsole.MarkupLine("[green]Done![/]"); | ||||
|         } | ||||
|  | ||||
|         private static List<(ProgressTask, int)> CreateTasks(ProgressContext progress, Random random) | ||||
|         { | ||||
|             var tasks = new List<(ProgressTask, int)>(); | ||||
|             while (tasks.Count < 5) | ||||
|             { | ||||
|                 if (DescriptionGenerator.TryGenerate(out var name)) | ||||
|                 { | ||||
|                     tasks.Add((progress.AddTask(name), random.Next(2, 10))); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return tasks; | ||||
|         } | ||||
|  | ||||
|         private static void WriteLogMessage() | ||||
|         { | ||||
|             AnsiConsole.MarkupLine( | ||||
|                 "[grey]LOG:[/] " + | ||||
|                 DescriptionGenerator.Generate() + | ||||
|                 "[grey]...[/]"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										19
									
								
								examples/Progress/Progress.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,19 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Progress</Title> | ||||
|     <Description>Demonstrates how to show progress bars.</Description> | ||||
|   </PropertyGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
							
								
								
									
										84
									
								
								examples/Prompt/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,84 @@ | ||||
| using Spectre.Console; | ||||
|  | ||||
| namespace Cursor | ||||
| { | ||||
|     public static class Program | ||||
|     { | ||||
|         public static void Main(string[] args) | ||||
|         { | ||||
|             // Check if we can accept key strokes | ||||
|             if (!AnsiConsole.Capabilities.SupportsInteraction) | ||||
|             { | ||||
|                 AnsiConsole.MarkupLine("[red]Environment does not support interaction.[/]"); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // Confirmation | ||||
|             if (!AnsiConsole.Confirm("Run prompt example?")) | ||||
|             { | ||||
|                 AnsiConsole.MarkupLine("Ok... :("); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // String | ||||
|             AnsiConsole.WriteLine(); | ||||
|             AnsiConsole.Render(new Rule("[yellow]Strings[/]").RuleStyle("grey").LeftAligned()); | ||||
|             var name = AnsiConsole.Ask<string>("What's your [green]name[/]?"); | ||||
|  | ||||
|             // String with choices | ||||
|             AnsiConsole.WriteLine(); | ||||
|             AnsiConsole.Render(new Rule("[yellow]Choices[/]").RuleStyle("grey").LeftAligned()); | ||||
|             var fruit = AnsiConsole.Prompt( | ||||
|                 new TextPrompt<string>("What's your [green]favorite fruit[/]?") | ||||
|                     .InvalidChoiceMessage("[red]That's not a valid fruit[/]") | ||||
|                     .DefaultValue("Orange") | ||||
|                     .AddChoice("Apple") | ||||
|                     .AddChoice("Banana") | ||||
|                     .AddChoice("Orange")); | ||||
|  | ||||
|             // Integer | ||||
|             AnsiConsole.WriteLine(); | ||||
|             AnsiConsole.Render(new Rule("[yellow]Integers[/]").RuleStyle("grey").LeftAligned()); | ||||
|             var age = AnsiConsole.Prompt( | ||||
|                 new TextPrompt<int>("How [green]old[/] are you?") | ||||
|                     .PromptStyle("green") | ||||
|                     .ValidationErrorMessage("[red]That's not a valid age[/]") | ||||
|                     .Validate(age => | ||||
|                     { | ||||
|                         return age switch | ||||
|                         { | ||||
|                             <= 0 => ValidationResult.Error("[red]You must at least be 1 years old[/]"), | ||||
|                             >= 123 => ValidationResult.Error("[red]You must be younger than the oldest person alive[/]"), | ||||
|                             _ => ValidationResult.Success(), | ||||
|                         }; | ||||
|                     })); | ||||
|  | ||||
|             // Secret | ||||
|             AnsiConsole.WriteLine(); | ||||
|             AnsiConsole.Render(new Rule("[yellow]Secrets[/]").RuleStyle("grey").LeftAligned()); | ||||
|             var password = AnsiConsole.Prompt( | ||||
|                 new TextPrompt<string>("Enter [green]password[/]?") | ||||
|                     .PromptStyle("red") | ||||
|                     .Secret()); | ||||
|  | ||||
|             // Optional | ||||
|             AnsiConsole.WriteLine(); | ||||
|             AnsiConsole.Render(new Rule("[yellow]Optional[/]").RuleStyle("grey").LeftAligned()); | ||||
|             var color = AnsiConsole.Prompt( | ||||
|                 new TextPrompt<string>("[grey][[Optional]][/] What is your [green]favorite color[/]?") | ||||
|                     .AllowEmpty()); | ||||
|  | ||||
|             // Summary | ||||
|             AnsiConsole.WriteLine(); | ||||
|             AnsiConsole.Render(new Rule("[yellow]Results[/]").RuleStyle("grey").LeftAligned()); | ||||
|             AnsiConsole.Render(new Table().AddColumns("[grey]Question[/]", "[grey]Answer[/]") | ||||
|                 .RoundedBorder() | ||||
|                 .BorderColor(Color.Grey) | ||||
|                 .AddRow("[grey]Name[/]", name) | ||||
|                 .AddRow("[grey]Favorite fruit[/]", fruit) | ||||
|                 .AddRow("[grey]Age[/]", age.ToString()) | ||||
|                 .AddRow("[grey]Password[/]", password) | ||||
|                 .AddRow("[grey]Favorite color[/]", string.IsNullOrEmpty(color) ? "Unknown" : color)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								examples/Prompt/Prompt.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,16 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <LangVersion>9</LangVersion> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Prompt</Title> | ||||
|     <Description>Demonstrates how to get input from a user.</Description> | ||||
|   </PropertyGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
							
								
								
									
										43
									
								
								examples/Rules/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,43 @@ | ||||
| using Spectre.Console; | ||||
|  | ||||
| namespace EmojiExample | ||||
| { | ||||
|     public static class Program | ||||
|     { | ||||
|         public static void Main(string[] args) | ||||
|         { | ||||
|             // No title | ||||
|             Render( | ||||
|                 new Rule() | ||||
|                     .RuleStyle(Style.Parse("yellow")) | ||||
|                     .AsciiBorder() | ||||
|                     .LeftAligned()); | ||||
|  | ||||
|             // Left aligned title | ||||
|             Render( | ||||
|                 new Rule("[blue]Left aligned[/]") | ||||
|                     .RuleStyle(Style.Parse("red")) | ||||
|                     .DoubleBorder() | ||||
|                     .LeftAligned()); | ||||
|  | ||||
|             // Centered title | ||||
|             Render( | ||||
|                 new Rule("[green]Centered[/]") | ||||
|                     .RuleStyle(Style.Parse("green")) | ||||
|                     .HeavyBorder() | ||||
|                     .Centered()); | ||||
|  | ||||
|             // Right aligned title | ||||
|             Render( | ||||
|                 new Rule("[red]Right aligned[/]") | ||||
|                     .RuleStyle(Style.Parse("blue")) | ||||
|                     .RightAligned()); | ||||
|         } | ||||
|  | ||||
|         private static void Render(Rule rule) | ||||
|         { | ||||
|             AnsiConsole.Render(rule); | ||||
|             AnsiConsole.WriteLine(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										15
									
								
								examples/Rules/Rules.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>net5.0</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> | ||||
							
								
								
									
										70
									
								
								examples/Status/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,70 @@ | ||||
| using System.Threading; | ||||
| using Spectre.Console; | ||||
|  | ||||
| namespace ProgressExample | ||||
| { | ||||
|     public static class Program | ||||
|     { | ||||
|         public static void Main() | ||||
|         { | ||||
|             AnsiConsole.Status() | ||||
|                 .AutoRefresh(true) | ||||
|                 .Spinner(Spinner.Known.Default) | ||||
|                 .Start("[yellow]Initializing warp drive[/]", ctx => | ||||
|                 { | ||||
|                     // Initialize | ||||
|                     Thread.Sleep(3000); | ||||
|                     WriteLogMessage("Starting gravimetric field displacement manifold"); | ||||
|                     Thread.Sleep(1000); | ||||
|                     WriteLogMessage("Warming up deuterium chamber"); | ||||
|                     Thread.Sleep(2000); | ||||
|                     WriteLogMessage("Generating antideuterium"); | ||||
|  | ||||
|                     // Warp nacelles | ||||
|                     Thread.Sleep(3000); | ||||
|                     ctx.Spinner(Spinner.Known.BouncingBar); | ||||
|                     ctx.Status("[bold blue]Unfolding warp nacelles[/]"); | ||||
|                     WriteLogMessage("Unfolding left warp nacelle"); | ||||
|                     Thread.Sleep(2000); | ||||
|                     WriteLogMessage("Left warp nacelle [green]online[/]"); | ||||
|                     WriteLogMessage("Unfolding right warp nacelle"); | ||||
|                     Thread.Sleep(1000); | ||||
|                     WriteLogMessage("Right warp nacelle [green]online[/]"); | ||||
|  | ||||
|                     // Warp bubble | ||||
|                     Thread.Sleep(3000); | ||||
|                     ctx.Spinner(Spinner.Known.Star2); | ||||
|                     ctx.Status("[bold blue]Generating warp bubble[/]"); | ||||
|                     Thread.Sleep(3000); | ||||
|                     ctx.Spinner(Spinner.Known.Star); | ||||
|                     ctx.Status("[bold blue]Stabilizing warp bubble[/]"); | ||||
|  | ||||
|                     // Safety | ||||
|                     ctx.Spinner(Spinner.Known.Monkey); | ||||
|                     ctx.Status("[bold blue]Performing safety checks[/]"); | ||||
|                     WriteLogMessage("Enabling interior dampening"); | ||||
|                     Thread.Sleep(2000); | ||||
|                     WriteLogMessage("Interior dampening [green]enabled[/]"); | ||||
|  | ||||
|                     // Warp! | ||||
|                     Thread.Sleep(3000); | ||||
|                     ctx.Spinner(Spinner.Known.Moon); | ||||
|                     WriteLogMessage("Preparing for warp"); | ||||
|                     Thread.Sleep(1000); | ||||
|                     for (var warp = 1; warp < 10; warp++) | ||||
|                     { | ||||
|                         ctx.Status($"[bold blue]Warp {warp}[/]"); | ||||
|                         Thread.Sleep(500); | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|             // Done | ||||
|             AnsiConsole.MarkupLine("[bold green]Crusing at Warp 9.8[/]"); | ||||
|         } | ||||
|  | ||||
|         private static void WriteLogMessage(string message) | ||||
|         { | ||||
|             AnsiConsole.MarkupLine($"[grey]LOG:[/] {message}[grey]...[/]"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										19
									
								
								examples/Status/Status.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,19 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Status</Title> | ||||
|     <Description>Demonstrates how to show status updates.</Description> | ||||
|   </PropertyGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
| @@ -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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|     <Title>Tables</Title> | ||||
|     <Description>Demonstrates how to render tables in a console.</Description> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "projects": [ "src" ], | ||||
|   "sdk": { | ||||
|     "version": "3.1.301", | ||||
|     "version": "5.0.100", | ||||
|     "rollForward": "latestPatch" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										22
									
								
								resources/scripts/Generate-Spinners.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | ||||
| ########################################################## | ||||
| # Script that generates progress spinners. | ||||
| ########################################################## | ||||
|  | ||||
| $Output = Join-Path $PSScriptRoot "Temp" | ||||
| $Source = Join-Path $PSScriptRoot "/../../src/Spectre.Console" | ||||
|  | ||||
| if(!(Test-Path $Output -PathType Container)) { | ||||
|     New-Item -ItemType Directory -Path $Output | Out-Null | ||||
| } | ||||
|  | ||||
| # Generate the files | ||||
| Push-Location Generator | ||||
| &dotnet run -- spinners "$Output" --input $Output | ||||
| if(!$?) { | ||||
|     Pop-Location | ||||
|     Throw "An error occured when generating code." | ||||
| } | ||||
| Pop-Location | ||||
|  | ||||
| # Copy the files to the correct location | ||||
| Copy-Item  (Join-Path "$Output" "Spinner.Generated.cs") -Destination "$Source/Progress/Spinner.Generated.cs" | ||||
| @@ -7,7 +7,7 @@ using Spectre.IO; | ||||
|  | ||||
| namespace Generator.Commands | ||||
| { | ||||
|     public sealed class ColorGeneratorCommand : Command<GeneratorCommandSettings> | ||||
|     public sealed class ColorGeneratorCommand : Command<ColorGeneratorCommand.Settings> | ||||
|     { | ||||
|         private readonly IFileSystem _fileSystem; | ||||
|  | ||||
| @@ -16,7 +16,13 @@ namespace Generator.Commands | ||||
|             _fileSystem = new FileSystem(); | ||||
|         } | ||||
|  | ||||
|         public override int Execute(CommandContext context, GeneratorCommandSettings settings) | ||||
|         public sealed class Settings : GeneratorSettings | ||||
|         { | ||||
|             [CommandOption("-i|--input <PATH>")] | ||||
|             public string Input { get; set; } | ||||
|         } | ||||
|  | ||||
|         public override int Execute(CommandContext context, Settings settings) | ||||
|         { | ||||
|             var templates = new FilePath[] | ||||
|             { | ||||
| @@ -50,13 +56,4 @@ namespace Generator.Commands | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public sealed class GeneratorCommandSettings : CommandSettings | ||||
|     { | ||||
|         [CommandArgument(0, "<OUTPUT>")] | ||||
|         public string Output { get; set; } | ||||
|  | ||||
|         [CommandOption("-i|--input <PATH>")] | ||||
|         public string Input { get; set; } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -15,7 +15,7 @@ using SpectreEnvironment = Spectre.IO.Environment; | ||||
|  | ||||
| namespace Generator.Commands | ||||
| { | ||||
|     public sealed class EmojiGeneratorCommand : AsyncCommand<GeneratorCommandSettings> | ||||
|     public sealed class EmojiGeneratorCommand : AsyncCommand<EmojiGeneratorCommand.Settings> | ||||
|     { | ||||
|         private readonly IFileSystem _fileSystem; | ||||
|         private readonly IEnvironment _environment; | ||||
| @@ -24,9 +24,15 @@ namespace Generator.Commands | ||||
|         private readonly Dictionary<string, string> _templates = new Dictionary<string, string> | ||||
|         { | ||||
|             { "Templates/Emoji.Generated.template", "Emoji.Generated.cs" }, | ||||
|             { "Templates/Emoji.Json.template", "emojis.json" }, | ||||
|             { "Templates/Emoji.Json.template", "emojis.json" }, // For documentation | ||||
|         }; | ||||
|  | ||||
|         public sealed class Settings : GeneratorSettings | ||||
|         { | ||||
|             [CommandOption("-i|--input <PATH>")] | ||||
|             public string Input { get; set; } | ||||
|         } | ||||
|  | ||||
|         public EmojiGeneratorCommand() | ||||
|         { | ||||
|             _fileSystem = new FileSystem(); | ||||
| @@ -34,7 +40,7 @@ namespace Generator.Commands | ||||
|             _parser = new HtmlParser(); | ||||
|         } | ||||
|  | ||||
|         public override async Task<int> ExecuteAsync(CommandContext context, GeneratorCommandSettings settings) | ||||
|         public override async Task<int> ExecuteAsync(CommandContext context, Settings settings) | ||||
|         { | ||||
|             var output = new DirectoryPath(settings.Output); | ||||
|             if (!_fileSystem.Directory.Exists(settings.Output)) | ||||
| @@ -60,7 +66,7 @@ namespace Generator.Commands | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         private async Task<Stream> FetchEmojis(GeneratorCommandSettings settings) | ||||
|         private async Task<Stream> FetchEmojis(Settings settings) | ||||
|         { | ||||
|             var input = string.IsNullOrEmpty(settings.Input) | ||||
|                 ? _environment.WorkingDirectory | ||||
|   | ||||
							
								
								
									
										10
									
								
								resources/scripts/Generator/Commands/GeneratorSettings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,10 @@ | ||||
| using Spectre.Cli; | ||||
|  | ||||
| namespace Generator.Commands | ||||
| { | ||||
|     public class GeneratorSettings : CommandSettings | ||||
|     { | ||||
|         [CommandArgument(0, "<OUTPUT>")] | ||||
|         public string Output { get; set; } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,47 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using Generator.Models; | ||||
| using Scriban; | ||||
| using Spectre.Cli; | ||||
| using Spectre.IO; | ||||
|  | ||||
| namespace Generator.Commands | ||||
| { | ||||
|     public sealed class SpinnerGeneratorCommand : Command<GeneratorSettings> | ||||
|     { | ||||
|         private readonly IFileSystem _fileSystem; | ||||
|  | ||||
|         public SpinnerGeneratorCommand() | ||||
|         { | ||||
|             _fileSystem = new FileSystem(); | ||||
|         } | ||||
|  | ||||
|         public override int Execute(CommandContext context, GeneratorSettings settings) | ||||
|         { | ||||
|             // Read the spinner model. | ||||
|             var spinners = new List<Spinner>(); | ||||
|             spinners.AddRange(Spinner.Parse(File.ReadAllText("Data/spinners_default.json"))); | ||||
|             spinners.AddRange(Spinner.Parse(File.ReadAllText("Data/spinners_sindresorhus.json"))); | ||||
|  | ||||
|             var output = new DirectoryPath(settings.Output); | ||||
|             if (!_fileSystem.Directory.Exists(settings.Output)) | ||||
|             { | ||||
|                 _fileSystem.Directory.Create(settings.Output); | ||||
|             } | ||||
|  | ||||
|             // Parse the Scriban template. | ||||
|             var templatePath = new FilePath("Templates/Spinner.Generated.template"); | ||||
|             var template = Template.Parse(File.ReadAllText(templatePath.FullPath)); | ||||
|  | ||||
|             // Render the template with the model. | ||||
|             var result = template.Render(new { Spinners = spinners }); | ||||
|  | ||||
|             // Write output to file | ||||
|             var file = output.CombineWithFilePath(templatePath.GetFilename().ChangeExtension(".cs")); | ||||
|             File.WriteAllText(file.FullPath, result); | ||||
|  | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										30
									
								
								resources/scripts/Generator/Data/spinners_default.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,30 @@ | ||||
| { | ||||
|   "Default": { | ||||
|     "interval": 100, | ||||
|     "unicode": true, | ||||
|     "frames": [ | ||||
|       "⣷", | ||||
|       "⣯", | ||||
|       "⣟", | ||||
|       "⡿", | ||||
|       "⢿", | ||||
|       "⣻", | ||||
|       "⣽", | ||||
|       "⣾" | ||||
|     ] | ||||
|   }, | ||||
|   "Ascii": { | ||||
|     "interval": 100, | ||||
|     "unicode": true, | ||||
|     "frames": [ | ||||
|       "-", | ||||
|       "\\", | ||||
|       "|", | ||||
|       "/", | ||||
|       "-", | ||||
|       "\\", | ||||
|       "|", | ||||
|       "/" | ||||
|     ] | ||||
|   } | ||||
| } | ||||
							
								
								
									
										1368
									
								
								resources/scripts/Generator/Data/spinners_sindresorhus.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -15,6 +15,12 @@ | ||||
|     <None Update="Data\colors.json"> | ||||
|       <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
|     </None> | ||||
|     <None Update="Data\spinners_default.json"> | ||||
|       <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
|     </None> | ||||
|     <None Update="Data\spinners_sindresorhus.json"> | ||||
|       <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
|     </None> | ||||
|     <None Update="Templates\ColorTable.Generated.template"> | ||||
|       <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
|     </None> | ||||
| @@ -24,6 +30,9 @@ | ||||
|     <None Update="Templates\ColorPalette.Generated.template"> | ||||
|       <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
|     </None> | ||||
|     <None Update="Templates\Spinner.Generated.template"> | ||||
|       <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
|     </None> | ||||
|     <None Update="Templates\Emoji.Json.template"> | ||||
|       <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
|     </None> | ||||
|   | ||||
							
								
								
									
										31
									
								
								resources/scripts/Generator/Models/Spinner.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,31 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Humanizer; | ||||
| using Newtonsoft.Json; | ||||
|  | ||||
| namespace Generator.Models | ||||
| { | ||||
|     public sealed class Spinner | ||||
|     { | ||||
|         public string Name { get; set; } | ||||
|         public string NormalizedName { get; set; } | ||||
|         public int Interval { get; set; } | ||||
|         public bool Unicode { get; set; } | ||||
|         public List<string> Frames { get; set; } | ||||
|  | ||||
|         public static IEnumerable<Spinner> Parse(string json) | ||||
|         { | ||||
|             var data = JsonConvert.DeserializeObject<Dictionary<string, Spinner>>(json); | ||||
|             foreach (var item in data) | ||||
|             { | ||||
|                 item.Value.Name = item.Key; | ||||
|                 item.Value.NormalizedName = item.Value.Name.Pascalize(); | ||||
|  | ||||
|                 var frames = item.Value.Frames; | ||||
|                 item.Value.Frames = frames.Select(f => f.Replace("\\", "\\\\")).ToList(); | ||||
|             } | ||||
|  | ||||
|             return data.Values; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -12,6 +12,7 @@ namespace Generator | ||||
|             { | ||||
|                 config.AddCommand<ColorGeneratorCommand>("colors"); | ||||
|                 config.AddCommand<EmojiGeneratorCommand>("emoji"); | ||||
|                 config.AddCommand<SpinnerGeneratorCommand>("spinners"); | ||||
|             }); | ||||
|  | ||||
|             return app.Run(args); | ||||
|   | ||||
| @@ -0,0 +1,48 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| // <auto-generated> | ||||
| //     This code was generated by a tool. | ||||
| //     Generated {{ date.now | date.to_string `%F %R` }} | ||||
| // | ||||
| //     Partly generated from | ||||
| //     https://github.com/sindresorhus/cli-spinners/blob/master/spinners.json | ||||
| // | ||||
| //     Changes to this file may cause incorrect behavior and will be lost if | ||||
| //     the code is regenerated. | ||||
| // </auto-generated> | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| { | ||||
|     public abstract partial class Spinner | ||||
|     { | ||||
|         {{~ for spinner in spinners ~}} | ||||
|         private sealed class {{ spinner.normalized_name }}Spinner : Spinner | ||||
|         { | ||||
|             public override TimeSpan Interval => TimeSpan.FromMilliseconds({{ spinner.interval }}); | ||||
|             public override bool IsUnicode => {{ spinner.unicode }}; | ||||
|             public override IReadOnlyList<string> Frames => new List<string> | ||||
|             { | ||||
|                 {{~ for frame in spinner.frames ~}} | ||||
|                     "{{ frame }}", | ||||
|                 {{~ end ~}} | ||||
|             }; | ||||
|         } | ||||
|         {{~ end ~}} | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Contains all predefined spinners. | ||||
|         /// </summary> | ||||
|         public static class Known | ||||
|         { | ||||
|             {{~ for spinner in spinners ~}} | ||||
|             /// <summary> | ||||
|             /// Gets the "{{ spinner.name }}" spinner. | ||||
|             /// </summary> | ||||
|             public static Spinner {{ spinner.normalized_name }} { get; } = new {{ spinner.normalized_name }}Spinner(); | ||||
|             {{~ end ~}} | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -87,3 +87,9 @@ dotnet_diagnostic.RCS1227.severity = none | ||||
|  | ||||
| # IDE0004: Remove Unnecessary Cast | ||||
| dotnet_diagnostic.IDE0004.severity = warning | ||||
|  | ||||
| # CA1810: Initialize reference type static fields inline | ||||
| dotnet_diagnostic.CA1810.severity = none | ||||
|  | ||||
| # IDE0044: Add readonly modifier | ||||
| dotnet_diagnostic.IDE0044.severity = warning | ||||
| @@ -1,7 +1,7 @@ | ||||
| <Project> | ||||
|   <PropertyGroup Label="Settings"> | ||||
|     <Deterministic>true</Deterministic> | ||||
|     <LangVersion>8.0</LangVersion> | ||||
|     <LangVersion>9.0</LangVersion> | ||||
|     <DebugSymbols>true</DebugSymbols> | ||||
|     <DebugType>embedded</DebugType> | ||||
|     <MinVerSkip Condition="'$(Configuration)' == 'Debug'">true</MinVerSkip> | ||||
|   | ||||
							
								
								
									
										125
									
								
								src/Spectre.Console.ImageSharp/CanvasImage.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,125 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using SixLabors.ImageSharp.PixelFormats; | ||||
| using SixLabors.ImageSharp.Processing; | ||||
| using SixLabors.ImageSharp.Processing.Processors.Transforms; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a renderable image. | ||||
|     /// </summary> | ||||
|     public sealed class CanvasImage : Renderable | ||||
|     { | ||||
|         private static readonly IResampler _defaultResampler = KnownResamplers.Bicubic; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the image width. | ||||
|         /// </summary> | ||||
|         public int Width => Image.Width; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the image height. | ||||
|         /// </summary> | ||||
|         public int Height => Image.Height; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets the render width of the canvas. | ||||
|         /// </summary> | ||||
|         public int? MaxWidth { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets the render width of the canvas. | ||||
|         /// </summary> | ||||
|         public int PixelWidth { get; set; } = 2; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets the <see cref="IResampler"/> that should | ||||
|         /// be used when scaling the image. Defaults to bicubic sampling. | ||||
|         /// </summary> | ||||
|         public IResampler? Resampler { get; set; } | ||||
|  | ||||
|         internal SixLabors.ImageSharp.Image<Rgba32> Image { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="CanvasImage"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="filename">The image filename.</param> | ||||
|         public CanvasImage(string filename) | ||||
|         { | ||||
|             Image = SixLabors.ImageSharp.Image.Load<Rgba32>(filename); | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         protected override Measurement Measure(RenderContext context, int maxWidth) | ||||
|         { | ||||
|             if (PixelWidth < 0) | ||||
|             { | ||||
|                 throw new InvalidOperationException("Pixel width must be greater than zero."); | ||||
|             } | ||||
|  | ||||
|             var width = MaxWidth ?? Width; | ||||
|             if (maxWidth < width * PixelWidth) | ||||
|             { | ||||
|                 return new Measurement(maxWidth, maxWidth); | ||||
|             } | ||||
|  | ||||
|             return new Measurement(width * PixelWidth, width * PixelWidth); | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth) | ||||
|         { | ||||
|             var image = Image; | ||||
|  | ||||
|             var width = Width; | ||||
|             var height = Height; | ||||
|  | ||||
|             // Got a max width? | ||||
|             if (MaxWidth != null) | ||||
|             { | ||||
|                 height = (int)(height * ((float)MaxWidth.Value) / Width); | ||||
|                 width = MaxWidth.Value; | ||||
|             } | ||||
|  | ||||
|             // Exceed the max width when we take pixel width into account? | ||||
|             if (width * PixelWidth > maxWidth) | ||||
|             { | ||||
|                 height = (int)(height * (maxWidth / (float)(width * PixelWidth))); | ||||
|                 width = maxWidth / PixelWidth; | ||||
|             } | ||||
|  | ||||
|             // Need to rescale the pixel buffer? | ||||
|             if (width != Width || height != Height) | ||||
|             { | ||||
|                 var resampler = Resampler ?? _defaultResampler; | ||||
|                 image = image.Clone(); // Clone the original image | ||||
|                 image.Mutate(i => i.Resize(width, height, resampler)); | ||||
|             } | ||||
|  | ||||
|             var canvas = new Canvas(width, height) | ||||
|             { | ||||
|                 MaxWidth = MaxWidth, | ||||
|                 PixelWidth = PixelWidth, | ||||
|                 Scale = false, | ||||
|             }; | ||||
|  | ||||
|             for (var y = 0; y < image.Height; y++) | ||||
|             { | ||||
|                 for (var x = 0; x < image.Width; x++) | ||||
|                 { | ||||
|                     if (image[x, y].A == 0) | ||||
|                     { | ||||
|                         continue; | ||||
|                     } | ||||
|  | ||||
|                     canvas.SetPixel(x, y, new Color( | ||||
|                         image[x, y].R, image[x, y].G, image[x, y].B)); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return ((IRenderable)canvas).Render(context, maxWidth); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										135
									
								
								src/Spectre.Console.ImageSharp/CanvasImageExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,135 @@ | ||||
| using System; | ||||
| using SixLabors.ImageSharp.Processing; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Contains extension methods for <see cref="CanvasImage"/>. | ||||
|     /// </summary> | ||||
|     public static class CanvasImageExtensions | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Sets the maximum width of the rendered image. | ||||
|         /// </summary> | ||||
|         /// <param name="image">The canvas image.</param> | ||||
|         /// <param name="maxWidth">The maximum width.</param> | ||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|         public static CanvasImage MaxWidth(this CanvasImage image, int? maxWidth) | ||||
|         { | ||||
|             if (image is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(image)); | ||||
|             } | ||||
|  | ||||
|             image.MaxWidth = maxWidth; | ||||
|             return image; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Disables the maximum width of the rendered image. | ||||
|         /// </summary> | ||||
|         /// <param name="image">The canvas image.</param> | ||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|         public static CanvasImage NoMaxWidth(this CanvasImage image) | ||||
|         { | ||||
|             if (image is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(image)); | ||||
|             } | ||||
|  | ||||
|             image.MaxWidth = null; | ||||
|             return image; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets the pixel width. | ||||
|         /// </summary> | ||||
|         /// <param name="image">The canvas image.</param> | ||||
|         /// <param name="width">The pixel width.</param> | ||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|         public static CanvasImage PixelWidth(this CanvasImage image, int width) | ||||
|         { | ||||
|             if (image is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(image)); | ||||
|             } | ||||
|  | ||||
|             image.PixelWidth = width; | ||||
|             return image; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Mutates the underlying image. | ||||
|         /// </summary> | ||||
|         /// <param name="image">The canvas image.</param> | ||||
|         /// <param name="action">The action that mutates the underlying image.</param> | ||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|         public static CanvasImage Mutate(this CanvasImage image, Action<IImageProcessingContext> action) | ||||
|         { | ||||
|             if (image is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(image)); | ||||
|             } | ||||
|  | ||||
|             if (action is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(action)); | ||||
|             } | ||||
|  | ||||
|             image.Image.Mutate(action); | ||||
|             return image; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Uses a bicubic sampler that implements the bicubic kernel algorithm W(x). | ||||
|         /// </summary> | ||||
|         /// <param name="image">The canvas image.</param> | ||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|         public static CanvasImage BicubicResampler(this CanvasImage image) | ||||
|         { | ||||
|             if (image is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(image)); | ||||
|             } | ||||
|  | ||||
|             image.Resampler = KnownResamplers.Bicubic; | ||||
|             return image; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Uses a bilinear sampler. This interpolation algorithm | ||||
|         /// can be used where perfect image transformation with pixel matching is impossible, | ||||
|         /// so that one can calculate and assign appropriate intensity values to pixels. | ||||
|         /// </summary> | ||||
|         /// <param name="image">The canvas image.</param> | ||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|         public static CanvasImage BilinearResampler(this CanvasImage image) | ||||
|         { | ||||
|             if (image is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(image)); | ||||
|             } | ||||
|  | ||||
|             image.Resampler = KnownResamplers.Triangle; | ||||
|             return image; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Uses a Nearest-Neighbour sampler that implements the nearest neighbor algorithm. | ||||
|         /// This uses a very fast, unscaled filter which will select the closest pixel to | ||||
|         /// the new pixels position. | ||||
|         /// </summary> | ||||
|         /// <param name="image">The canvas image.</param> | ||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|         public static CanvasImage NearestNeighborResampler(this CanvasImage image) | ||||
|         { | ||||
|             if (image is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(image)); | ||||
|             } | ||||
|  | ||||
|             image.Resampler = KnownResamplers.NearestNeighbor; | ||||
|             return image; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,22 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <TargetFrameworks>netstandard2.0</TargetFrameworks> | ||||
|     <Nullable>enable</Nullable> | ||||
|     <Description>A library that extends Spectre.Console with ImageSharp superpowers.</Description> | ||||
|   </PropertyGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <AdditionalFiles Include="..\stylecop.json" Link="Properties/stylecop.json" /> | ||||
|     <None Include="../../resources/gfx/small-logo.png" Pack="true" PackagePath="\" Link="Properties/small-logo.png" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="SixLabors.ImageSharp" Version="1.0.2" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\Spectre.Console\Spectre.Console.csproj" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
| @@ -8,6 +8,9 @@ namespace Spectre.Console.Tests.Data | ||||
|         [SuppressMessage("Usage", "CA1801:Review unused parameters", Justification = "<Pending>")] | ||||
|         public static bool MethodThatThrows(int? number) => throw new InvalidOperationException("Throwing!"); | ||||
|  | ||||
|         [SuppressMessage("Usage", "CA1801:Review unused parameters", Justification = "<Pending>")] | ||||
|         public static bool GenericMethodThatThrows<T0, T1, TRet>(int? number) => throw new InvalidOperationException("Throwing!"); | ||||
|  | ||||
|         public static void ThrowWithInnerException() | ||||
|         { | ||||
|             try | ||||
| @@ -19,5 +22,17 @@ namespace Spectre.Console.Tests.Data | ||||
|                 throw new InvalidOperationException("Something threw!", ex); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public static void ThrowWithGenericInnerException() | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 GenericMethodThatThrows<int, float, double>(null); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 throw new InvalidOperationException("Something threw!", ex); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										719
									
								
								src/Spectre.Console.Tests/Data/starwars.flf
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,719 @@ | ||||
| flf2a$ 7 6 22 15 4 | ||||
| starwars.flf by Ryan Youck (youck@cs.uregina.ca) Dec 25/1994 | ||||
| I am not responsible for use of this font   | ||||
| Based on Big.flf by Glenn Chappell | ||||
|  | ||||
| $ $@ | ||||
| $ $@ | ||||
| $ $@ | ||||
| $ $@ | ||||
| $ $@ | ||||
| $ $@ | ||||
| $ $@@ | ||||
|  __ $@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |__|$@ | ||||
| (__)$@ | ||||
|     $@@ | ||||
|  _ _ @ | ||||
| ( | )@ | ||||
|  V V @ | ||||
|   $  @ | ||||
|   $  @ | ||||
|   $  @ | ||||
|      @@ | ||||
|    _  _   @ | ||||
|  _| || |_$@ | ||||
| |_  __  _|@ | ||||
|  _| || |_ @ | ||||
| |_  __  _|@ | ||||
|   |_||_| $@ | ||||
|           @@ | ||||
|      __,--,_.@ | ||||
|     /       |@ | ||||
|    |   (----`@ | ||||
|     \   \   $@ | ||||
| .----)   |  $@ | ||||
| |_    __/   $@ | ||||
|   '--'      $@@ | ||||
|   _     ___$ @ | ||||
|  / \   /  /$ @ | ||||
| ( o ) /  / $ @ | ||||
|  \_/ /  / _$ @ | ||||
|     /  / / \ @ | ||||
|    /  / ( o )@ | ||||
|   /__/   \_/ @@ | ||||
|         @ | ||||
|   ___   @ | ||||
|  ( _ ) $@ | ||||
|  / _ \/\@ | ||||
| | (_>  <@ | ||||
|  \___/\/@ | ||||
|        $@@ | ||||
|  __ @ | ||||
| (_ )@ | ||||
|  |/ @ | ||||
|   $ @ | ||||
|   $ @ | ||||
|   $ @ | ||||
|     @@ | ||||
|   ___@ | ||||
|  /  /@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
|  \__\@@ | ||||
| ___  @ | ||||
| \  \ @ | ||||
|  |  |@ | ||||
|  |  |@ | ||||
|  |  |@ | ||||
|  |  |@ | ||||
| /__/ @@ | ||||
|     _    @ | ||||
|  /\| |/\ @ | ||||
|  \ ` ' /$@ | ||||
| |_     _|@ | ||||
|  / , . \$@ | ||||
|  \/|_|\/ @ | ||||
|          @@ | ||||
|        @ | ||||
|    _   @ | ||||
|  _| |_$@ | ||||
| |_   _|@ | ||||
|   |_| $@ | ||||
|    $   @ | ||||
|        @@ | ||||
|     @ | ||||
|     @ | ||||
|   $ @ | ||||
|   $ @ | ||||
|  __ @ | ||||
| (_ )@ | ||||
|  |/ @@ | ||||
|         @ | ||||
|         @ | ||||
|  ______ @ | ||||
| |______|@ | ||||
|     $   @ | ||||
|     $   @ | ||||
|         @@ | ||||
|     @ | ||||
|     @ | ||||
|     @ | ||||
|   $ @ | ||||
|  __ @ | ||||
| (__)@ | ||||
|     @@ | ||||
|      ___@ | ||||
|     /  /@ | ||||
|    /  / @ | ||||
|   /  /$ @ | ||||
|  /  /$  @ | ||||
| /__/$   @ | ||||
|         @@ | ||||
|   ___  $@ | ||||
|  / _ \ $@ | ||||
| | | | |$@ | ||||
| | | | |$@ | ||||
| | |_| |$@ | ||||
|  \___/ $@ | ||||
|        $@@ | ||||
|  __ $@ | ||||
| /_ |$@ | ||||
|  | |$@ | ||||
|  | |$@ | ||||
|  | |$@ | ||||
|  |_|$@ | ||||
|     $@@ | ||||
|  ___  $@ | ||||
| |__ \ $@ | ||||
|   $) |$@ | ||||
|   / / $@ | ||||
|  / /_ $@ | ||||
| |____|$@ | ||||
|       $@@ | ||||
|  ____  $@ | ||||
| |___ \ $@ | ||||
|   __) |$@ | ||||
|  |__ < $@ | ||||
|  ___) |$@ | ||||
| |____/ $@ | ||||
|        $@@ | ||||
|  _  _   $@ | ||||
| | || |  $@ | ||||
| | || |_ $@ | ||||
| |__   _|$@ | ||||
|    | |  $@ | ||||
|    |_|  $@ | ||||
|         $@@ | ||||
|  _____ $@ | ||||
| | ____|$@ | ||||
| | |__  $@ | ||||
| |___ \ $@ | ||||
|  ___) |$@ | ||||
| |____/ $@ | ||||
|        $@@ | ||||
|    __  $@ | ||||
|   / /  $@ | ||||
|  / /_  $@ | ||||
| | '_ \ $@ | ||||
| | (_) |$@ | ||||
|  \___/ $@ | ||||
|        $@@ | ||||
|  ______ $@ | ||||
| |____  |$@ | ||||
|    $/ / $@ | ||||
|    / /  $@ | ||||
|   / /   $@ | ||||
|  /_/    $@ | ||||
|         $@@ | ||||
|   ___  $@ | ||||
|  / _ \ $@ | ||||
| | (_) |$@ | ||||
|  > _ < $@ | ||||
| | (_) |$@ | ||||
|  \___/ $@ | ||||
|        $@@ | ||||
|   ___  $@ | ||||
|  / _ \ $@ | ||||
| | (_) |$@ | ||||
|  \__, |$@ | ||||
|    / / $@ | ||||
|   /_/  $@ | ||||
|        $@@ | ||||
|    @ | ||||
|  _ @ | ||||
| (_)@ | ||||
|  $ @ | ||||
|  _ @ | ||||
| (_)@ | ||||
|    @@ | ||||
|    @ | ||||
|  _ @ | ||||
| (_)@ | ||||
|  $ @ | ||||
|  _ @ | ||||
| ( )@ | ||||
| |/ @@ | ||||
|    ___@ | ||||
|   /  /@ | ||||
|  /  /$@ | ||||
| <  <$ @ | ||||
|  \  \$@ | ||||
|   \__\@ | ||||
|       @@ | ||||
|         @ | ||||
|  ______ @ | ||||
| |______|@ | ||||
|  ______ @ | ||||
| |______|@ | ||||
|         @ | ||||
|         @@ | ||||
| ___   @ | ||||
| \  \$ @ | ||||
|  \  \ @ | ||||
|   >  >@ | ||||
|  /  / @ | ||||
| /__/$ @ | ||||
|       @@ | ||||
|  ______  $@ | ||||
| |      \ $@ | ||||
| `----)  |$@ | ||||
|     /  / $@ | ||||
|    |__|  $@ | ||||
|     __   $@ | ||||
|    (__)  $@@ | ||||
|    ____  @ | ||||
|   / __ \ @ | ||||
|  / / _` |@ | ||||
| | | (_| |@ | ||||
|  \ \__,_|@ | ||||
|   \____/ @ | ||||
|          @@ | ||||
|      ___  $   @ | ||||
|     /   \ $   @ | ||||
|    /  ^  \$   @ | ||||
|   /  /_\  \$  @ | ||||
|  /  _____  \$ @ | ||||
| /__/     \__\$@ | ||||
|              $@@ | ||||
| .______  $@ | ||||
| |   _  \ $@ | ||||
| |  |_)  |$@ | ||||
| |   _  < $@ | ||||
| |  |_)  |$@ | ||||
| |______/ $@ | ||||
|          $@@ | ||||
|   ______$@ | ||||
|  /      |@ | ||||
| |  ,----'@ | ||||
| |  |    $@ | ||||
| |  `----.@ | ||||
|  \______|@ | ||||
|         $@@ | ||||
|  _______ $@ | ||||
| |       \$@ | ||||
| |  .--.  |@ | ||||
| |  |  |  |@ | ||||
| |  '--'  |@ | ||||
| |_______/$@ | ||||
|          $@@ | ||||
|  _______ @ | ||||
| |   ____|@ | ||||
| |  |__  $@ | ||||
| |   __| $@ | ||||
| |  |____ @ | ||||
| |_______|@ | ||||
|          @@ | ||||
|  _______ @ | ||||
| |   ____|@ | ||||
| |  |__  $@ | ||||
| |   __| $@ | ||||
| |  |   $ @ | ||||
| |__|     @ | ||||
|          @@ | ||||
|   _______ @ | ||||
|  /  _____|@ | ||||
| |  |  __ $@ | ||||
| |  | |_ |$@ | ||||
| |  |__| |$@ | ||||
|  \______|$@ | ||||
|          $@@ | ||||
|  __    __ $@ | ||||
| |  |  |  |$@ | ||||
| |  |__|  |$@ | ||||
| |   __   |$@ | ||||
| |  |  |  |$@ | ||||
| |__|  |__|$@ | ||||
|           $@@ | ||||
|  __ $@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |__|$@ | ||||
|     $@@ | ||||
|        __ $@ | ||||
|       |  |$@ | ||||
|       |  |$@ | ||||
| .--.  |  |$@ | ||||
| |  `--'  |$@ | ||||
|  \______/ $@ | ||||
|           $@@ | ||||
|  __  ___$@ | ||||
| |  |/  /$@ | ||||
| |  '  / $@ | ||||
| |    <  $@ | ||||
| |  .  \ $@ | ||||
| |__|\__\$@ | ||||
|         $@@ | ||||
|  __     $@ | ||||
| |  |    $@ | ||||
| |  |    $@ | ||||
| |  |    $@ | ||||
| |  `----.@ | ||||
| |_______|@ | ||||
|         $@@ | ||||
| .___  ___.$@ | ||||
| |   \/   |$@ | ||||
| |  \  /  |$@ | ||||
| |  |\/|  |$@ | ||||
| |  |  |  |$@ | ||||
| |__|  |__|$@ | ||||
|           $@@ | ||||
| .__   __.$@ | ||||
| |  \ |  |$@ | ||||
| |   \|  |$@ | ||||
| |  . `  |$@ | ||||
| |  |\   |$@ | ||||
| |__| \__|$@ | ||||
|          $@@ | ||||
|   ______  $@ | ||||
|  /  __  \ $@ | ||||
| |  |  |  |$@ | ||||
| |  |  |  |$@ | ||||
| |  `--'  |$@ | ||||
|  \______/ $@ | ||||
|           $@@ | ||||
| .______  $@ | ||||
| |   _  \ $@ | ||||
| |  |_)  |$@ | ||||
| |   ___/ $@ | ||||
| |  |  $   @ | ||||
| | _|  $   @ | ||||
|       $   @@ | ||||
|   ______    $ @ | ||||
|  /  __  \   $ @ | ||||
| |  |  |  |  $ @ | ||||
| |  |  |  |  $ @ | ||||
| |  `--'  '--. @ | ||||
|  \_____\_____\@ | ||||
|             $ @@ | ||||
| .______    $ @ | ||||
| |   _  \   $ @ | ||||
| |  |_)  |  $ @ | ||||
| |      /   $ @ | ||||
| |  |\  \----.@ | ||||
| | _| `._____|@ | ||||
|             $@@ | ||||
|      _______.@ | ||||
|     /       |@ | ||||
|    |   (----`@ | ||||
|     \   \   $@ | ||||
| .----)   |  $@ | ||||
| |_______/   $@ | ||||
|             $@@ | ||||
| .___________.@ | ||||
| |           |@ | ||||
| `---|  |----`@ | ||||
|     |  |   $ @ | ||||
|     |  |   $ @ | ||||
|     |__|   $ @ | ||||
|            $ @@ | ||||
|  __    __ $@ | ||||
| |  |  |  |$@ | ||||
| |  |  |  |$@ | ||||
| |  |  |  |$@ | ||||
| |  `--'  |$@ | ||||
|  \______/ $@ | ||||
|           $@@ | ||||
| ____    ____$@ | ||||
| \   \  /   /$@ | ||||
|  \   \/   /$ @ | ||||
|   \      /$  @ | ||||
|    \    /$   @ | ||||
|     \__/$    @ | ||||
|         $    @@ | ||||
| ____    __    ____$@ | ||||
| \   \  /  \  /   /$@ | ||||
|  \   \/    \/   /$ @ | ||||
|   \            /$  @ | ||||
|    \    /\    /$   @ | ||||
|     \__/  \__/$    @ | ||||
|               $    @@ | ||||
| ___   ___$@ | ||||
| \  \ /  /$@ | ||||
|  \  V  / $@ | ||||
|   >   <  $@ | ||||
|  /  .  \ $@ | ||||
| /__/ \__\$@ | ||||
|          $@@ | ||||
| ____    ____$@ | ||||
| \   \  /   /$@ | ||||
|  \   \/   /$ @ | ||||
|   \_    _/$  @ | ||||
|     |  |$    @ | ||||
|     |__|$    @ | ||||
|         $    @@ | ||||
|  ________ $@ | ||||
| |       / $@ | ||||
| `---/  /  $@ | ||||
|    /  /   $@ | ||||
|   /  /----.@ | ||||
|  /________|@ | ||||
|           $@@ | ||||
|  ____ @ | ||||
| |    |@ | ||||
| |  |-`@ | ||||
| |  | $@ | ||||
| |  | $@ | ||||
| |  |-.@ | ||||
| |____|@@ | ||||
| ___     @ | ||||
| \  \ $  @ | ||||
|  \  \$  @ | ||||
|   \  \$ @ | ||||
|    \  \$@ | ||||
|     \__\@ | ||||
|         @@ | ||||
|  ____ @ | ||||
| |    |@ | ||||
| `-|  |@ | ||||
|   |  |@ | ||||
|   |  |@ | ||||
| .-|  |@ | ||||
| |____|@@ | ||||
|   ___  @ | ||||
|  /   \ @ | ||||
| /--^--\@ | ||||
|       $@ | ||||
|       $@ | ||||
|       $@ | ||||
|       $@@ | ||||
|         @ | ||||
|         @ | ||||
|         @ | ||||
|     $   @ | ||||
|     $   @ | ||||
|  ______ @ | ||||
| |______|@@ | ||||
|  __ @ | ||||
| ( _)@ | ||||
|  \| @ | ||||
|   $ @ | ||||
|   $ @ | ||||
|   $ @ | ||||
|     @@ | ||||
|      ___  $   @ | ||||
|     /   \ $   @ | ||||
|    /  ^  \$   @ | ||||
|   /  /_\  \$  @ | ||||
|  /  _____  \$ @ | ||||
| /__/     \__\$@ | ||||
|              $@@ | ||||
| .______  $@ | ||||
| |   _  \ $@ | ||||
| |  |_)  |$@ | ||||
| |   _  < $@ | ||||
| |  |_)  |$@ | ||||
| |______/ $@ | ||||
|          $@@ | ||||
|   ______$@ | ||||
|  /      |@ | ||||
| |  ,----'@ | ||||
| |  |    $@ | ||||
| |  `----.@ | ||||
|  \______|@ | ||||
|         $@@ | ||||
|  _______ $@ | ||||
| |       \$@ | ||||
| |  .--.  |@ | ||||
| |  |  |  |@ | ||||
| |  '--'  |@ | ||||
| |_______/$@ | ||||
|          $@@ | ||||
|  _______ @ | ||||
| |   ____|@ | ||||
| |  |__  $@ | ||||
| |   __| $@ | ||||
| |  |____ @ | ||||
| |_______|@ | ||||
|          @@ | ||||
|  _______ @ | ||||
| |   ____|@ | ||||
| |  |__  $@ | ||||
| |   __| $@ | ||||
| |  |   $ @ | ||||
| |__|     @ | ||||
|          @@ | ||||
|   _______ @ | ||||
|  /  _____|@ | ||||
| |  |  __ $@ | ||||
| |  | |_ |$@ | ||||
| |  |__| |$@ | ||||
|  \______|$@ | ||||
|          $@@ | ||||
|  __    __ $@ | ||||
| |  |  |  |$@ | ||||
| |  |__|  |$@ | ||||
| |   __   |$@ | ||||
| |  |  |  |$@ | ||||
| |__|  |__|$@ | ||||
|           $@@ | ||||
|  __ $@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |__|$@ | ||||
|     $@@ | ||||
|        __ $@ | ||||
|       |  |$@ | ||||
|       |  |$@ | ||||
| .--.  |  |$@ | ||||
| |  `--'  |$@ | ||||
|  \______/ $@ | ||||
|           $@@ | ||||
|  __  ___$@ | ||||
| |  |/  /$@ | ||||
| |  '  / $@ | ||||
| |    <  $@ | ||||
| |  .  \ $@ | ||||
| |__|\__\$@ | ||||
|         $@@ | ||||
|  __     $@ | ||||
| |  |    $@ | ||||
| |  |    $@ | ||||
| |  |    $@ | ||||
| |  `----.@ | ||||
| |_______|@ | ||||
|         $@@ | ||||
| .___  ___.$@ | ||||
| |   \/   |$@ | ||||
| |  \  /  |$@ | ||||
| |  |\/|  |$@ | ||||
| |  |  |  |$@ | ||||
| |__|  |__|$@ | ||||
|           $@@ | ||||
| .__   __.$@ | ||||
| |  \ |  |$@ | ||||
| |   \|  |$@ | ||||
| |  . `  |$@ | ||||
| |  |\   |$@ | ||||
| |__| \__|$@ | ||||
|          $@@ | ||||
|   ______  $@ | ||||
|  /  __  \ $@ | ||||
| |  |  |  |$@ | ||||
| |  |  |  |$@ | ||||
| |  `--'  |$@ | ||||
|  \______/ $@ | ||||
|           $@@ | ||||
| .______  $@ | ||||
| |   _  \ $@ | ||||
| |  |_)  |$@ | ||||
| |   ___/ $@ | ||||
| |  |  $   @ | ||||
| | _|  $   @ | ||||
|       $   @@ | ||||
|   ______    $ @ | ||||
|  /  __  \   $ @ | ||||
| |  |  |  |  $ @ | ||||
| |  |  |  |  $ @ | ||||
| |  `--'  '--. @ | ||||
|  \_____\_____\@ | ||||
|             $ @@ | ||||
| .______    $ @ | ||||
| |   _  \   $ @ | ||||
| |  |_)  |  $ @ | ||||
| |      /   $ @ | ||||
| |  |\  \----.@ | ||||
| | _| `._____|@ | ||||
|             $@@ | ||||
|      _______.@ | ||||
|     /       |@ | ||||
|    |   (----`@ | ||||
|     \   \   $@ | ||||
| .----)   |  $@ | ||||
| |_______/   $@ | ||||
|             $@@ | ||||
| .___________.@ | ||||
| |           |@ | ||||
| `---|  |----`@ | ||||
|     |  |   $ @ | ||||
|     |  |   $ @ | ||||
|     |__|   $ @ | ||||
|            $ @@ | ||||
|  __    __ $@ | ||||
| |  |  |  |$@ | ||||
| |  |  |  |$@ | ||||
| |  |  |  |$@ | ||||
| |  `--'  |$@ | ||||
|  \______/ $@ | ||||
|           $@@ | ||||
| ____    ____$@ | ||||
| \   \  /   /$@ | ||||
|  \   \/   /$ @ | ||||
|   \      /$  @ | ||||
|    \    /$   @ | ||||
|     \__/$    @ | ||||
|         $    @@ | ||||
| ____    __    ____$@ | ||||
| \   \  /  \  /   /$@ | ||||
|  \   \/    \/   /$ @ | ||||
|   \            /$  @ | ||||
|    \    /\    /$   @ | ||||
|     \__/  \__/$    @ | ||||
|               $    @@ | ||||
| ___   ___$@ | ||||
| \  \ /  /$@ | ||||
|  \  V  / $@ | ||||
|   >   <  $@ | ||||
|  /  .  \ $@ | ||||
| /__/ \__\$@ | ||||
|          $@@ | ||||
| ____    ____$@ | ||||
| \   \  /   /$@ | ||||
|  \   \/   /$ @ | ||||
|   \_    _/$  @ | ||||
|     |  |$    @ | ||||
|     |__|$    @ | ||||
|         $    @@ | ||||
|  ________ $@ | ||||
| |       / $@ | ||||
| `---/  /  $@ | ||||
|    /  /   $@ | ||||
|   /  /----.@ | ||||
|  /________|@ | ||||
|           $@@ | ||||
|    ___@ | ||||
|   /  /@ | ||||
|  |  |$@ | ||||
| /  /$ @ | ||||
| \  \$ @ | ||||
|  |  |$@ | ||||
|   \__\@@ | ||||
|  __ $@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |  |$@ | ||||
| |__|$@@ | ||||
| ___   @ | ||||
| \  \$ @ | ||||
|  |  | @ | ||||
|   \  \@ | ||||
|   /  /@ | ||||
|  |  | @ | ||||
| /__/$ @@ | ||||
|   __  _ @ | ||||
|  /  \/ |@ | ||||
| |_/\__/ @ | ||||
|      $  @ | ||||
|      $  @ | ||||
|      $  @ | ||||
|         @@ | ||||
|   _   _  @ | ||||
|  (_)_(_) @ | ||||
|    / \   @ | ||||
|   / _ \  @ | ||||
|  / ___ \ @ | ||||
| /_/   \_\@ | ||||
|          @@ | ||||
|  _   _ @ | ||||
| (_)_(_)@ | ||||
|  / _ \ @ | ||||
| | | | |@ | ||||
| | |_| |@ | ||||
|  \___/ @ | ||||
|        @@ | ||||
|  _   _ @ | ||||
| (_) (_)@ | ||||
| | | | |@ | ||||
| | | | |@ | ||||
| | |_| |@ | ||||
|  \___/ @ | ||||
|        @@ | ||||
|  _   _ @ | ||||
| (_) (_)@ | ||||
|   __ _ @ | ||||
|  / _` |@ | ||||
| | (_| |@ | ||||
|  \__,_|@ | ||||
|        @@ | ||||
|  _   _ @ | ||||
| (_) (_)@ | ||||
|   ___  @ | ||||
|  / _ \ @ | ||||
| | (_) |@ | ||||
|  \___/ @ | ||||
|        @@ | ||||
|  _   _ @ | ||||
| (_) (_)@ | ||||
|  _   _ @ | ||||
| | | | |@ | ||||
| | |_| |@ | ||||
|  \__,_|@ | ||||
|        @@ | ||||
|   ___  @ | ||||
|  / _ \ @ | ||||
| | | ) |@ | ||||
| | |< < @ | ||||
| | | ) |@ | ||||
| | ||_/ @ | ||||
| |_|    @@ | ||||
							
								
								
									
										46
									
								
								src/Spectre.Console.Tests/EmbeddedResourceDataAttribute.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,46 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Reflection; | ||||
| using Xunit.Sdk; | ||||
|  | ||||
| namespace Spectre.Console.Tests | ||||
| { | ||||
|     public sealed class EmbeddedResourceDataAttribute : DataAttribute | ||||
|     { | ||||
|         private readonly string _args; | ||||
|  | ||||
|         public EmbeddedResourceDataAttribute(string args) | ||||
|         { | ||||
|             _args = args ?? throw new ArgumentNullException(nameof(args)); | ||||
|         } | ||||
|  | ||||
|         public override IEnumerable<object[]> GetData(MethodInfo testMethod) | ||||
|         { | ||||
|             var result = new object[1]; | ||||
|             result[0] = ReadManifestData(_args); | ||||
|             return new[] { result }; | ||||
|         } | ||||
|  | ||||
|         public static string ReadManifestData(string resourceName) | ||||
|         { | ||||
|             if (resourceName is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(resourceName)); | ||||
|             } | ||||
|  | ||||
|             using (var stream = ResourceReader.LoadResourceStream(resourceName)) | ||||
|             { | ||||
|                 if (stream == null) | ||||
|                 { | ||||
|                     throw new InvalidOperationException("Could not load manifest resource stream."); | ||||
|                 } | ||||
|  | ||||
|                 using (var reader = new StreamReader(stream)) | ||||
|                 { | ||||
|                     return reader.ReadToEnd().NormalizeLineEndings(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,3 @@ | ||||
| +-Greeting----+ | ||||
| | Hello World | | ||||
| +-------------+ | ||||
| @@ -0,0 +1,3 @@ | ||||
| ╔═Greeting════╗ | ||||
| ║ Hello World ║ | ||||
| ╚═════════════╝ | ||||
| @@ -0,0 +1,3 @@ | ||||
| ┏━Greeting━━━━┓ | ||||
| ┃ Hello World ┃ | ||||
| ┗━━━━━━━━━━━━━┛ | ||||
| @@ -0,0 +1,3 @@ | ||||
|   Greeting      | ||||
|   Hello World   | ||||
|                 | ||||