diff --git a/docs/input/appendix/borders.md b/docs/input/appendix/borders.md index f2308bf..80aee4a 100644 --- a/docs/input/appendix/borders.md +++ b/docs/input/appendix/borders.md @@ -4,16 +4,30 @@ Order: 2 There is different built-in borders you can use for tables and panels. -# Built-in borders +# Table borders - + -# Usage +## Example -To create a table and set it's border to `SimpleHeavy` as seen in the -image above: +To set a table border to `SimpleHeavy`: ```csharp var table = new Table(); -table.Border = Border.SimpleHeavy; +table.Border = TableBorder.SimpleHeavy; +``` + +--- + +# Panel borders + + + +## Example + +To set a panel border to `Rounded`: + +```csharp +var panel = new Panel("Hello World"); +panel.Border = BoxBorder.Rounded; ``` \ No newline at end of file diff --git a/docs/input/assets/images/borders.png b/docs/input/assets/images/borders.png deleted file mode 100644 index dc28d77..0000000 Binary files a/docs/input/assets/images/borders.png and /dev/null differ diff --git a/docs/input/assets/images/borders/panel.png b/docs/input/assets/images/borders/panel.png new file mode 100644 index 0000000..be3776f Binary files /dev/null and b/docs/input/assets/images/borders/panel.png differ diff --git a/docs/input/assets/images/borders/table.png b/docs/input/assets/images/borders/table.png new file mode 100644 index 0000000..ebcf041 Binary files /dev/null and b/docs/input/assets/images/borders/table.png differ diff --git a/examples/Borders/Program.cs b/examples/Borders/Program.cs index 054f8e0..526d833 100644 --- a/examples/Borders/Program.cs +++ b/examples/Borders/Program.cs @@ -7,41 +7,83 @@ namespace Borders { public static void Main() { - var items = new[] - { - Create("Ascii", Border.Ascii), - Create("Ascii2", Border.Ascii2), - Create("AsciiDoubleHead", Border.AsciiDoubleHead), - Create("Horizontal", Border.Horizontal), - Create("Simple", Border.Simple), - Create("SimpleHeavy", Border.SimpleHeavy), - Create("Minimal", Border.Minimal), - Create("MinimalHeavyHead", Border.MinimalHeavyHead), - Create("MinimalDoubleHead", Border.MinimalDoubleHead), - Create("Square", Border.Square), - Create("Rounded", Border.Rounded), - Create("Heavy", Border.Heavy), - Create("HeavyEdge", Border.HeavyEdge), - Create("HeavyHead", Border.HeavyHead), - Create("Double", Border.Double), - Create("DoubleEdge", Border.DoubleEdge), - }; - + // Render panel borders AnsiConsole.WriteLine(); - AnsiConsole.Render(new Columns(items).Collapse()); + AnsiConsole.MarkupLine("[white bold underline]PANEL BORDERS[/]"); + AnsiConsole.WriteLine(); + RenderPanelBorders(); + + // Render table borders + AnsiConsole.WriteLine(); + AnsiConsole.MarkupLine("[white bold underline]TABLE BORDERS[/]"); + AnsiConsole.WriteLine(); + RenderTableBorders(); } - private static IRenderable Create(string name, Border border) + private static void RenderPanelBorders() { - var table = new Table().SetBorder(border); - table.AddColumns("[yellow]Header 1[/]", "[yellow]Header 2[/]"); - table.AddRow("Cell", "Cell"); - table.AddRow("Cell", "Cell"); + 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); + } - return new Panel(table) - .SetHeader($" {name} ", Style.Parse("blue"), Justify.Center) - .SetBorderStyle(Style.Parse("grey")) - .NoBorder(); + var items = new[] + { + CreatePanel("Ascii", BoxBorder.Ascii), + CreatePanel("Square", BoxBorder.Square), + CreatePanel("Rounded", BoxBorder.Rounded), + CreatePanel("Heavy", BoxBorder.Heavy), + CreatePanel("Double", BoxBorder.Double), + CreatePanel("None", BoxBorder.None), + }; + + AnsiConsole.Render( + new Padder( + new Columns(items).PadRight(2), + new Padding(2,0,0,0))); + } + + private static void RenderTableBorders() + { + static IRenderable CreateTable(string name, TableBorder border) + { + var table = new Table().SetBorder(border); + table.AddColumn("[yellow]Header 1[/]"); + table.AddColumn("[yellow]Header 2[/]", col => col.RightAligned()); + table.AddRow("Cell", "Cell"); + table.AddRow("Cell", "Cell"); + + return new Panel(table) + .SetHeader($" {name} ", Style.Parse("blue"), Justify.Center) + .SetBorderStyle(Style.Parse("grey")) + .NoBorder(); + } + + var items = new[] + { + CreateTable("Ascii", TableBorder.Ascii), + CreateTable("Ascii2", TableBorder.Ascii2), + CreateTable("AsciiDoubleHead", TableBorder.AsciiDoubleHead), + CreateTable("Horizontal", TableBorder.Horizontal), + CreateTable("Simple", TableBorder.Simple), + CreateTable("SimpleHeavy", TableBorder.SimpleHeavy), + CreateTable("Minimal", TableBorder.Minimal), + CreateTable("MinimalHeavyHead", TableBorder.MinimalHeavyHead), + CreateTable("MinimalDoubleHead", TableBorder.MinimalDoubleHead), + CreateTable("Square", TableBorder.Square), + CreateTable("Rounded", TableBorder.Rounded), + CreateTable("Heavy", TableBorder.Heavy), + CreateTable("HeavyEdge", TableBorder.HeavyEdge), + CreateTable("HeavyHead", TableBorder.HeavyHead), + CreateTable("Double", TableBorder.Double), + CreateTable("DoubleEdge", TableBorder.DoubleEdge), + CreateTable("Markdown", TableBorder.Markdown), + }; + + AnsiConsole.Render(new Columns(items).Collapse()); } } } diff --git a/examples/Emojis/Program.cs b/examples/Emojis/Program.cs index 87b0166..85ab75f 100644 --- a/examples/Emojis/Program.cs +++ b/examples/Emojis/Program.cs @@ -1,4 +1,3 @@ -using System; using Spectre.Console; namespace Emojis diff --git a/examples/Panel/Program.cs b/examples/Panel/Program.cs index 3c4e112..3cd22b4 100644 --- a/examples/Panel/Program.cs +++ b/examples/Panel/Program.cs @@ -13,7 +13,7 @@ namespace PanelExample AnsiConsole.Render( new Panel( new Panel(content) - .SetBorder(Border.Rounded))); + .SetBorder(BoxBorder.Rounded))); // Left adjusted panel with text AnsiConsole.Render( diff --git a/examples/Table/Program.cs b/examples/Table/Program.cs index 27549ff..a16f0a9 100644 --- a/examples/Table/Program.cs +++ b/examples/Table/Program.cs @@ -35,7 +35,7 @@ namespace TableExample private static void RenderBigTable() { // Create the table. - var table = new Table().SetBorder(Border.Rounded); + var table = new Table().SetBorder(TableBorder.Rounded); table.AddColumn("[red underline]Foo[/]"); table.AddColumn(new TableColumn("[blue]Bar[/]") { Alignment = Justify.Right, NoWrap = true }); @@ -57,7 +57,7 @@ namespace TableExample private static void RenderNestedTable() { // Create simple table. - var simple = new Table().SetBorder(Border.Rounded).SetBorderColor(Color.Red); + var simple = new Table().SetBorder(TableBorder.Rounded).SetBorderColor(Color.Red); simple.AddColumn(new TableColumn("[u]Foo[/]").Centered()); simple.AddColumn(new TableColumn("[u]Bar[/]")); simple.AddColumn(new TableColumn("[u]Baz[/]")); @@ -66,7 +66,7 @@ namespace TableExample simple.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", ""); // Create other table. - var second = new Table().SetBorder(Border.Square).SetBorderColor(Color.Green); + var second = new Table().SetBorder(TableBorder.Square).SetBorderColor(Color.Green); second.AddColumn(new TableColumn("[u]Foo[/]")); second.AddColumn(new TableColumn("[u]Bar[/]")); second.AddColumn(new TableColumn("[u]Baz[/]")); @@ -74,7 +74,7 @@ namespace TableExample second.AddRow(simple, new Text("Whaaat"), new Text("Lolz")); second.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", ""); - var table = new Table().SetBorder(Border.Rounded); + var table = new Table().SetBorder(TableBorder.Rounded); table.AddColumn(new TableColumn(new Panel("[u]Foo[/]").SetBorderColor(Color.Red))); table.AddColumn(new TableColumn(new Panel("[u]Bar[/]").SetBorderColor(Color.Green))); table.AddColumn(new TableColumn(new Panel("[u]Baz[/]").SetBorderColor(Color.Blue))); diff --git a/global.json b/global.json index 7c77738..54ed6bc 100644 --- a/global.json +++ b/global.json @@ -2,6 +2,6 @@ "projects": [ "src" ], "sdk": { "version": "3.1.301", - "rollForward": "latestMajor" + "rollForward": "latestPatch" } } \ No newline at end of file diff --git a/src/Spectre.Console.Tests/Unit/BoxBorderTests.cs b/src/Spectre.Console.Tests/Unit/BoxBorderTests.cs new file mode 100644 index 0000000..4c8c218 --- /dev/null +++ b/src/Spectre.Console.Tests/Unit/BoxBorderTests.cs @@ -0,0 +1,210 @@ +using Shouldly; +using Spectre.Console.Rendering; +using Xunit; + +namespace Spectre.Console.Tests.Unit +{ + public sealed class BoxBorderTests + { + public sealed class NoBorder + { + public sealed class TheSafeGetBorderMethod + { + [Fact] + public void Should_Return_Safe_Border() + { + // Given, When + var border = BoxBorder.None.GetSafeBorder(safe: true); + + // Then + border.ShouldBeSameAs(BoxBorder.None); + } + } + + [Fact] + public void Should_Render_As_Expected() + { + // Given + var console = new PlainConsole(); + var panel = Fixture.GetPanel().NoBorder(); + + // When + console.Render(panel); + + // Then + console.Lines.Count.ShouldBe(3); + console.Lines[0].ShouldBe(" Greeting "); + console.Lines[1].ShouldBe(" Hello World "); + console.Lines[2].ShouldBe(" "); + } + } + + public sealed class AsciiBorder + { + public sealed class TheSafeGetBorderMethod + { + [Fact] + public void Should_Return_Safe_Border() + { + // Given, When + var border = BoxBorder.Ascii.GetSafeBorder(safe: true); + + // Then + border.ShouldBeSameAs(BoxBorder.Ascii); + } + } + + [Fact] + public void Should_Render_As_Expected() + { + // Given + var console = new PlainConsole(); + var panel = Fixture.GetPanel().AsciiBorder(); + + // When + console.Render(panel); + + // Then + console.Lines.Count.ShouldBe(3); + console.Lines[0].ShouldBe("+-Greeting----+"); + console.Lines[1].ShouldBe("| Hello World |"); + console.Lines[2].ShouldBe("+-------------+"); + } + } + + public sealed class DoubleBorder + { + public sealed class TheSafeGetBorderMethod + { + [Fact] + public void Should_Return_Safe_Border() + { + // Given, When + var border = BoxBorder.Double.GetSafeBorder(safe: true); + + // Then + border.ShouldBeSameAs(BoxBorder.Double); + } + } + + [Fact] + public void Should_Render_As_Expected() + { + // Given + var console = new PlainConsole(); + var panel = Fixture.GetPanel().DoubleBorder(); + + // When + console.Render(panel); + + // Then + console.Lines.Count.ShouldBe(3); + console.Lines[0].ShouldBe("╔═Greeting════╗"); + console.Lines[1].ShouldBe("║ Hello World ║"); + console.Lines[2].ShouldBe("╚═════════════╝"); + } + } + + public sealed class HeavyBorder + { + public sealed class TheSafeGetBorderMethod + { + [Fact] + public void Should_Return_Safe_Border() + { + // Given, When + var border = BoxBorder.Heavy.GetSafeBorder(safe: true); + + // Then + border.ShouldBeSameAs(BoxBorder.Square); + } + } + + [Fact] + public void Should_Render_As_Expected() + { + // Given + var console = new PlainConsole(); + var panel = Fixture.GetPanel().HeavyBorder(); + + // When + console.Render(panel); + + // Then + console.Lines.Count.ShouldBe(3); + console.Lines[0].ShouldBe("┏━Greeting━━━━┓"); + console.Lines[1].ShouldBe("┃ Hello World ┃"); + console.Lines[2].ShouldBe("┗━━━━━━━━━━━━━┛"); + } + } + + public sealed class RoundedBorder + { + [Fact] + public void Should_Return_Safe_Border() + { + // Given, When + var border = BoxBorder.Rounded.GetSafeBorder(safe: true); + + // Then + border.ShouldBeSameAs(BoxBorder.Square); + } + + [Fact] + public void Should_Render_As_Expected() + { + // Given + var console = new PlainConsole(); + var panel = Fixture.GetPanel().RoundedBorder(); + + // When + console.Render(panel); + + // Then + console.Lines.Count.ShouldBe(3); + console.Lines[0].ShouldBe("╭─Greeting────╮"); + console.Lines[1].ShouldBe("│ Hello World │"); + console.Lines[2].ShouldBe("╰─────────────╯"); + } + } + + public sealed class SquareBorder + { + [Fact] + public void Should_Return_Safe_Border() + { + // Given, When + var border = BoxBorder.Square.GetSafeBorder(safe: true); + + // Then + border.ShouldBeSameAs(BoxBorder.Square); + } + + [Fact] + public void Should_Render_As_Expected() + { + // Given + var console = new PlainConsole(); + var panel = Fixture.GetPanel().SquareBorder(); + + // When + console.Render(panel); + + // Then + console.Lines.Count.ShouldBe(3); + console.Lines[0].ShouldBe("┌─Greeting────┐"); + console.Lines[1].ShouldBe("│ Hello World │"); + console.Lines[2].ShouldBe("└─────────────┘"); + } + } + + private static class Fixture + { + public static Panel GetPanel() + { + return new Panel("Hello World") + .SetHeader("Greeting"); + } + } + } +} diff --git a/src/Spectre.Console.Tests/Unit/BorderTests.cs b/src/Spectre.Console.Tests/Unit/TableBorderTests.cs similarity index 75% rename from src/Spectre.Console.Tests/Unit/BorderTests.cs rename to src/Spectre.Console.Tests/Unit/TableBorderTests.cs index fdcd369..72fe572 100644 --- a/src/Spectre.Console.Tests/Unit/BorderTests.cs +++ b/src/Spectre.Console.Tests/Unit/TableBorderTests.cs @@ -4,7 +4,7 @@ using Xunit; namespace Spectre.Console.Tests.Unit { - public sealed class BorderTests + public sealed class TableBorderTests { public sealed class NoBorder { @@ -12,7 +12,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.None.Visible; + var visibility = TableBorder.None.Visible; // Then visibility.ShouldBeFalse(); @@ -24,10 +24,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.None.GetSafeBorder(safe: true); + var border = TableBorder.None.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.None); + border.ShouldBeSameAs(TableBorder.None); } } @@ -55,7 +55,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.Ascii.Visible; + var visibility = TableBorder.Ascii.Visible; // Then visibility.ShouldBeTrue(); @@ -67,10 +67,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.Ascii.GetSafeBorder(safe: true); + var border = TableBorder.Ascii.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Ascii); + border.ShouldBeSameAs(TableBorder.Ascii); } } @@ -101,7 +101,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.Ascii2.Visible; + var visibility = TableBorder.Ascii2.Visible; // Then visibility.ShouldBeTrue(); @@ -113,10 +113,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.Ascii2.GetSafeBorder(safe: true); + var border = TableBorder.Ascii2.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Ascii2); + border.ShouldBeSameAs(TableBorder.Ascii2); } } @@ -147,7 +147,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.AsciiDoubleHead.Visible; + var visibility = TableBorder.AsciiDoubleHead.Visible; // Then visibility.ShouldBeTrue(); @@ -159,10 +159,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.AsciiDoubleHead.GetSafeBorder(safe: true); + var border = TableBorder.AsciiDoubleHead.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.AsciiDoubleHead); + border.ShouldBeSameAs(TableBorder.AsciiDoubleHead); } } @@ -193,7 +193,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.Square.Visible; + var visibility = TableBorder.Square.Visible; // Then visibility.ShouldBeTrue(); @@ -205,10 +205,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.Square.GetSafeBorder(safe: true); + var border = TableBorder.Square.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Square); + border.ShouldBeSameAs(TableBorder.Square); } } @@ -239,7 +239,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.Rounded.Visible; + var visibility = TableBorder.Rounded.Visible; // Then visibility.ShouldBeTrue(); @@ -251,10 +251,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.Rounded.GetSafeBorder(safe: true); + var border = TableBorder.Rounded.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Square); + border.ShouldBeSameAs(TableBorder.Square); } } @@ -285,7 +285,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.Minimal.Visible; + var visibility = TableBorder.Minimal.Visible; // Then visibility.ShouldBeTrue(); @@ -297,10 +297,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.Minimal.GetSafeBorder(safe: true); + var border = TableBorder.Minimal.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Minimal); + border.ShouldBeSameAs(TableBorder.Minimal); } } @@ -331,7 +331,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.MinimalHeavyHead.Visible; + var visibility = TableBorder.MinimalHeavyHead.Visible; // Then visibility.ShouldBeTrue(); @@ -343,10 +343,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.MinimalHeavyHead.GetSafeBorder(safe: true); + var border = TableBorder.MinimalHeavyHead.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Minimal); + border.ShouldBeSameAs(TableBorder.Minimal); } } @@ -377,7 +377,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.MinimalDoubleHead.Visible; + var visibility = TableBorder.MinimalDoubleHead.Visible; // Then visibility.ShouldBeTrue(); @@ -389,10 +389,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.MinimalDoubleHead.GetSafeBorder(safe: true); + var border = TableBorder.MinimalDoubleHead.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.MinimalDoubleHead); + border.ShouldBeSameAs(TableBorder.MinimalDoubleHead); } } @@ -423,7 +423,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.Simple.Visible; + var visibility = TableBorder.Simple.Visible; // Then visibility.ShouldBeTrue(); @@ -435,10 +435,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.Simple.GetSafeBorder(safe: true); + var border = TableBorder.Simple.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Simple); + border.ShouldBeSameAs(TableBorder.Simple); } } @@ -469,7 +469,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.Horizontal.Visible; + var visibility = TableBorder.Horizontal.Visible; // Then visibility.ShouldBeTrue(); @@ -481,10 +481,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.Horizontal.GetSafeBorder(safe: true); + var border = TableBorder.Horizontal.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Horizontal); + border.ShouldBeSameAs(TableBorder.Horizontal); } } @@ -515,7 +515,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.SimpleHeavy.Visible; + var visibility = TableBorder.SimpleHeavy.Visible; // Then visibility.ShouldBeTrue(); @@ -527,10 +527,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.SimpleHeavy.GetSafeBorder(safe: true); + var border = TableBorder.SimpleHeavy.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Simple); + border.ShouldBeSameAs(TableBorder.Simple); } } @@ -561,7 +561,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.Heavy.Visible; + var visibility = TableBorder.Heavy.Visible; // Then visibility.ShouldBeTrue(); @@ -573,10 +573,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.Heavy.GetSafeBorder(safe: true); + var border = TableBorder.Heavy.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Square); + border.ShouldBeSameAs(TableBorder.Square); } } @@ -607,7 +607,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.HeavyEdge.Visible; + var visibility = TableBorder.HeavyEdge.Visible; // Then visibility.ShouldBeTrue(); @@ -619,10 +619,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.HeavyEdge.GetSafeBorder(safe: true); + var border = TableBorder.HeavyEdge.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Square); + border.ShouldBeSameAs(TableBorder.Square); } } @@ -653,7 +653,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.HeavyHead.Visible; + var visibility = TableBorder.HeavyHead.Visible; // Then visibility.ShouldBeTrue(); @@ -665,10 +665,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.HeavyHead.GetSafeBorder(safe: true); + var border = TableBorder.HeavyHead.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Square); + border.ShouldBeSameAs(TableBorder.Square); } } @@ -699,7 +699,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.Double.Visible; + var visibility = TableBorder.Double.Visible; // Then visibility.ShouldBeTrue(); @@ -711,10 +711,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.Double.GetSafeBorder(safe: true); + var border = TableBorder.Double.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.Double); + border.ShouldBeSameAs(TableBorder.Double); } } @@ -745,7 +745,7 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Correct_Visibility() { // Given, When - var visibility = Border.DoubleEdge.Visible; + var visibility = TableBorder.DoubleEdge.Visible; // Then visibility.ShouldBeTrue(); @@ -757,10 +757,10 @@ namespace Spectre.Console.Tests.Unit public void Should_Return_Safe_Border() { // Given, When - var border = Border.DoubleEdge.GetSafeBorder(safe: true); + var border = TableBorder.DoubleEdge.GetSafeBorder(safe: true); // Then - border.ShouldBeSameAs(Border.DoubleEdge); + border.ShouldBeSameAs(TableBorder.DoubleEdge); } } @@ -785,12 +785,119 @@ namespace Spectre.Console.Tests.Unit } } + public sealed class MarkdownBorder + { + [Fact] + public void Should_Return_Correct_Visibility() + { + // Given, When + var visibility = TableBorder.Markdown.Visible; + + // Then + visibility.ShouldBeTrue(); + } + + public sealed class TheSafeGetBorderMethod + { + [Fact] + public void Should_Return_Safe_Border() + { + // Given, When + var border = TableBorder.Markdown.GetSafeBorder(safe: true); + + // Then + border.ShouldBeSameAs(TableBorder.Markdown); + } + } + + [Fact] + public void Should_Render_As_Expected() + { + // Given + var console = new PlainConsole(); + var table = Fixture.GetTable().MarkdownBorder(); + + // When + console.Render(table); + + // Then + console.Lines.Count.ShouldBe(6); + console.Lines[0].ShouldBe(" "); + console.Lines[1].ShouldBe("| Header 1 | Header 2 |"); + console.Lines[2].ShouldBe("| -------- | -------- |"); + console.Lines[3].ShouldBe("| Cell | Cell |"); + console.Lines[4].ShouldBe("| Cell | Cell |"); + console.Lines[5].ShouldBe(" "); + } + + [Fact] + public void Should_Render_Left_Aligned_Table_Columns_As_Expected() + { + // Given + var console = new PlainConsole(); + var table = Fixture.GetTable(header2: Justify.Left).MarkdownBorder(); + + // When + console.Render(table); + + // Then + console.Lines.Count.ShouldBe(6); + console.Lines[0].ShouldBe(" "); + console.Lines[1].ShouldBe("| Header 1 | Header 2 |"); + console.Lines[2].ShouldBe("| -------- | :------- |"); + console.Lines[3].ShouldBe("| Cell | Cell |"); + console.Lines[4].ShouldBe("| Cell | Cell |"); + console.Lines[5].ShouldBe(" "); + } + + [Fact] + public void Should_Render_Center_Aligned_Table_Columns_As_Expected() + { + // Given + var console = new PlainConsole(); + var table = Fixture.GetTable(header2: Justify.Center).MarkdownBorder(); + + // When + console.Render(table); + + // Then + console.Lines.Count.ShouldBe(6); + console.Lines[0].ShouldBe(" "); + console.Lines[1].ShouldBe("| Header 1 | Header 2 |"); + console.Lines[2].ShouldBe("| -------- | :------: |"); + console.Lines[3].ShouldBe("| Cell | Cell |"); + console.Lines[4].ShouldBe("| Cell | Cell |"); + console.Lines[5].ShouldBe(" "); + } + + [Fact] + public void Should_Render_Right_Aligned_Table_Columns_As_Expected() + { + // Given + var console = new PlainConsole(); + var table = Fixture.GetTable(header2: Justify.Right).MarkdownBorder(); + + // When + console.Render(table); + + // Then + console.Lines.Count.ShouldBe(6); + console.Lines[0].ShouldBe(" "); + console.Lines[1].ShouldBe("| Header 1 | Header 2 |"); + console.Lines[2].ShouldBe("| -------- | -------: |"); + console.Lines[3].ShouldBe("| Cell | Cell |"); + console.Lines[4].ShouldBe("| Cell | Cell |"); + console.Lines[5].ShouldBe(" "); + } + } + private static class Fixture { - public static Table GetTable() + public static Table GetTable(Justify? header1 = null, Justify? header2 = null) { var table = new Table(); - table.AddColumns("Header 1", "Header 2"); + table.AddColumn("Header 1", c => c.Alignment = header1); + table.AddColumn("Header 2", c => c.Alignment = header2); table.AddRow("Cell", "Cell"); table.AddRow("Cell", "Cell"); return table; diff --git a/src/Spectre.Console.Tests/Unit/TableTests.cs b/src/Spectre.Console.Tests/Unit/TableTests.cs index d761ec4..fa3cca2 100644 --- a/src/Spectre.Console.Tests/Unit/TableTests.cs +++ b/src/Spectre.Console.Tests/Unit/TableTests.cs @@ -173,7 +173,7 @@ namespace Spectre.Console.Tests.Unit { // A simple table var console = new PlainConsole(width: 80); - var table = new Table() { Border = Border.Rounded }; + var table = new Table() { Border = TableBorder.Rounded }; table.AddColumn("Foo"); table.AddColumn("Bar"); table.AddColumn(new TableColumn("Baz") { Alignment = Justify.Right }); @@ -183,7 +183,7 @@ namespace Spectre.Console.Tests.Unit // Render a table in some panels. console.Render(new Panel(new Panel(table) { - Border = Border.Ascii, + Border = BoxBorder.Ascii, })); // Then @@ -255,7 +255,7 @@ namespace Spectre.Console.Tests.Unit { // Given var console = new PlainConsole(width: 80); - var table = new Table { Border = Border.Ascii }; + var table = new Table { Border = TableBorder.Ascii }; table.AddColumns("Foo", "Bar", "Baz"); table.AddRow("Qux", "Corgi", "Waldo"); table.AddRow("Grault", "Garply", "Fred"); @@ -278,7 +278,7 @@ namespace Spectre.Console.Tests.Unit { // Given var console = new PlainConsole(width: 80); - var table = new Table { Border = Border.Rounded }; + var table = new Table { Border = TableBorder.Rounded }; table.AddColumns("Foo", "Bar", "Baz"); table.AddRow("Qux", "Corgi", "Waldo"); table.AddRow("Grault", "Garply", "Fred"); @@ -301,7 +301,7 @@ namespace Spectre.Console.Tests.Unit { // Given var console = new PlainConsole(width: 80); - var table = new Table { Border = Border.None }; + var table = new Table { Border = TableBorder.None }; table.AddColumns("Foo", "Bar", "Baz"); table.AddRow("Qux", "Corgi", "Waldo"); table.AddRow("Grault", "Garply", "Fred"); diff --git a/src/Spectre.Console/Borders/Ascii2Border.cs b/src/Spectre.Console/Borders/Ascii2Border.cs deleted file mode 100644 index 84e45a2..0000000 --- a/src/Spectre.Console/Borders/Ascii2Border.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents another old school ASCII border. - /// - public sealed class Ascii2Border : Border - { - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => "+", - BorderPart.HeaderTop => "-", - BorderPart.HeaderTopSeparator => "+", - BorderPart.HeaderTopRight => "+", - BorderPart.HeaderLeft => "|", - BorderPart.HeaderSeparator => "|", - BorderPart.HeaderRight => "|", - BorderPart.HeaderBottomLeft => "|", - BorderPart.HeaderBottom => "-", - BorderPart.HeaderBottomSeparator => "+", - BorderPart.HeaderBottomRight => "|", - BorderPart.CellLeft => "|", - BorderPart.CellSeparator => "|", - BorderPart.CellRight => "|", - BorderPart.FooterBottomLeft => "+", - BorderPart.FooterBottom => "-", - BorderPart.FooterBottomSeparator => "+", - BorderPart.FooterBottomRight => "+", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/AsciiBorder.cs b/src/Spectre.Console/Borders/AsciiBorder.cs deleted file mode 100644 index 0c8575f..0000000 --- a/src/Spectre.Console/Borders/AsciiBorder.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents an old school ASCII border. - /// - public sealed class AsciiBorder : Border - { - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => "+", - BorderPart.HeaderTop => "-", - BorderPart.HeaderTopSeparator => "-", - BorderPart.HeaderTopRight => "+", - BorderPart.HeaderLeft => "|", - BorderPart.HeaderSeparator => "|", - BorderPart.HeaderRight => "|", - BorderPart.HeaderBottomLeft => "|", - BorderPart.HeaderBottom => "-", - BorderPart.HeaderBottomSeparator => "+", - BorderPart.HeaderBottomRight => "|", - BorderPart.CellLeft => "|", - BorderPart.CellSeparator => "|", - BorderPart.CellRight => "|", - BorderPart.FooterBottomLeft => "+", - BorderPart.FooterBottom => "-", - BorderPart.FooterBottomSeparator => "-", - BorderPart.FooterBottomRight => "+", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/AsciiDoubleHeadBorder.cs b/src/Spectre.Console/Borders/AsciiDoubleHeadBorder.cs deleted file mode 100644 index 78116a5..0000000 --- a/src/Spectre.Console/Borders/AsciiDoubleHeadBorder.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents an old school ASCII border with a double header border. - /// - public sealed class AsciiDoubleHeadBorder : Border - { - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => "+", - BorderPart.HeaderTop => "-", - BorderPart.HeaderTopSeparator => "+", - BorderPart.HeaderTopRight => "+", - BorderPart.HeaderLeft => "|", - BorderPart.HeaderSeparator => "|", - BorderPart.HeaderRight => "|", - BorderPart.HeaderBottomLeft => "|", - BorderPart.HeaderBottom => "=", - BorderPart.HeaderBottomSeparator => "+", - BorderPart.HeaderBottomRight => "|", - BorderPart.CellLeft => "|", - BorderPart.CellSeparator => "|", - BorderPart.CellRight => "|", - BorderPart.FooterBottomLeft => "+", - BorderPart.FooterBottom => "-", - BorderPart.FooterBottomSeparator => "+", - BorderPart.FooterBottomRight => "+", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/DoubleBorder.cs b/src/Spectre.Console/Borders/DoubleBorder.cs deleted file mode 100644 index b0084c9..0000000 --- a/src/Spectre.Console/Borders/DoubleBorder.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a double border. - /// - public sealed class DoubleBorder : Border - { - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => "╔", - BorderPart.HeaderTop => "═", - BorderPart.HeaderTopSeparator => "╦", - BorderPart.HeaderTopRight => "╗", - BorderPart.HeaderLeft => "║", - BorderPart.HeaderSeparator => "║", - BorderPart.HeaderRight => "║", - BorderPart.HeaderBottomLeft => "╠", - BorderPart.HeaderBottom => "═", - BorderPart.HeaderBottomSeparator => "╬", - BorderPart.HeaderBottomRight => "╣", - BorderPart.CellLeft => "║", - BorderPart.CellSeparator => "║", - BorderPart.CellRight => "║", - BorderPart.FooterBottomLeft => "╚", - BorderPart.FooterBottom => "═", - BorderPart.FooterBottomSeparator => "╩", - BorderPart.FooterBottomRight => "╝", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/DoubleEdgeBorder.cs b/src/Spectre.Console/Borders/DoubleEdgeBorder.cs deleted file mode 100644 index b450681..0000000 --- a/src/Spectre.Console/Borders/DoubleEdgeBorder.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a border with a double edge. - /// - public sealed class DoubleEdgeBorder : Border - { - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => "╔", - BorderPart.HeaderTop => "═", - BorderPart.HeaderTopSeparator => "╤", - BorderPart.HeaderTopRight => "╗", - BorderPart.HeaderLeft => "║", - BorderPart.HeaderSeparator => "│", - BorderPart.HeaderRight => "║", - BorderPart.HeaderBottomLeft => "╟", - BorderPart.HeaderBottom => "─", - BorderPart.HeaderBottomSeparator => "┼", - BorderPart.HeaderBottomRight => "╢", - BorderPart.CellLeft => "║", - BorderPart.CellSeparator => "│", - BorderPart.CellRight => "║", - BorderPart.FooterBottomLeft => "╚", - BorderPart.FooterBottom => "═", - BorderPart.FooterBottomSeparator => "╧", - BorderPart.FooterBottomRight => "╝", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/HeavyBorder.cs b/src/Spectre.Console/Borders/HeavyBorder.cs deleted file mode 100644 index 5a2f537..0000000 --- a/src/Spectre.Console/Borders/HeavyBorder.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a heavy border. - /// - public sealed class HeavyBorder : Border - { - /// - public override Border? SafeBorder => Border.Square; - - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => "┏", - BorderPart.HeaderTop => "━", - BorderPart.HeaderTopSeparator => "┳", - BorderPart.HeaderTopRight => "┓", - BorderPart.HeaderLeft => "┃", - BorderPart.HeaderSeparator => "┃", - BorderPart.HeaderRight => "┃", - BorderPart.HeaderBottomLeft => "┣", - BorderPart.HeaderBottom => "━", - BorderPart.HeaderBottomSeparator => "╋", - BorderPart.HeaderBottomRight => "┫", - BorderPart.CellLeft => "┃", - BorderPart.CellSeparator => "┃", - BorderPart.CellRight => "┃", - BorderPart.FooterBottomLeft => "┗", - BorderPart.FooterBottom => "━", - BorderPart.FooterBottomSeparator => "┻", - BorderPart.FooterBottomRight => "┛", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/HeavyEdgeBorder.cs b/src/Spectre.Console/Borders/HeavyEdgeBorder.cs deleted file mode 100644 index c01b503..0000000 --- a/src/Spectre.Console/Borders/HeavyEdgeBorder.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a border with a heavy edge. - /// - public sealed class HeavyEdgeBorder : Border - { - /// - public override Border? SafeBorder => Border.Square; - - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => "┏", - BorderPart.HeaderTop => "━", - BorderPart.HeaderTopSeparator => "┯", - BorderPart.HeaderTopRight => "┓", - BorderPart.HeaderLeft => "┃", - BorderPart.HeaderSeparator => "│", - BorderPart.HeaderRight => "┃", - BorderPart.HeaderBottomLeft => "┠", - BorderPart.HeaderBottom => "─", - BorderPart.HeaderBottomSeparator => "┼", - BorderPart.HeaderBottomRight => "┨", - BorderPart.CellLeft => "┃", - BorderPart.CellSeparator => "│", - BorderPart.CellRight => "┃", - BorderPart.FooterBottomLeft => "┗", - BorderPart.FooterBottom => "━", - BorderPart.FooterBottomSeparator => "┷", - BorderPart.FooterBottomRight => "┛", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/HeavyHeadBorder.cs b/src/Spectre.Console/Borders/HeavyHeadBorder.cs deleted file mode 100644 index 7ba6538..0000000 --- a/src/Spectre.Console/Borders/HeavyHeadBorder.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a border with a heavy header. - /// - public sealed class HeavyHeadBorder : Border - { - /// - public override Border? SafeBorder => Border.Square; - - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => "┏", - BorderPart.HeaderTop => "━", - BorderPart.HeaderTopSeparator => "┳", - BorderPart.HeaderTopRight => "┓", - BorderPart.HeaderLeft => "┃", - BorderPart.HeaderSeparator => "┃", - BorderPart.HeaderRight => "┃", - BorderPart.HeaderBottomLeft => "┡", - BorderPart.HeaderBottom => "━", - BorderPart.HeaderBottomSeparator => "╇", - BorderPart.HeaderBottomRight => "┩", - BorderPart.CellLeft => "│", - BorderPart.CellSeparator => "│", - BorderPart.CellRight => "│", - BorderPart.FooterBottomLeft => "└", - BorderPart.FooterBottom => "─", - BorderPart.FooterBottomSeparator => "┴", - BorderPart.FooterBottomRight => "┘", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/HorizontalBorder.cs b/src/Spectre.Console/Borders/HorizontalBorder.cs deleted file mode 100644 index 4ba3209..0000000 --- a/src/Spectre.Console/Borders/HorizontalBorder.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a horizontal border. - /// - public sealed class HorizontalBorder : Border - { - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => "─", - BorderPart.HeaderTop => "─", - BorderPart.HeaderTopSeparator => "─", - BorderPart.HeaderTopRight => "─", - BorderPart.HeaderLeft => " ", - BorderPart.HeaderSeparator => " ", - BorderPart.HeaderRight => " ", - BorderPart.HeaderBottomLeft => "─", - BorderPart.HeaderBottom => "─", - BorderPart.HeaderBottomSeparator => "─", - BorderPart.HeaderBottomRight => "─", - BorderPart.CellLeft => " ", - BorderPart.CellSeparator => " ", - BorderPart.CellRight => " ", - BorderPart.FooterBottomLeft => "─", - BorderPart.FooterBottom => "─", - BorderPart.FooterBottomSeparator => "─", - BorderPart.FooterBottomRight => "─", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/MinimalBorder.cs b/src/Spectre.Console/Borders/MinimalBorder.cs deleted file mode 100644 index 056d28d..0000000 --- a/src/Spectre.Console/Borders/MinimalBorder.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a minimal border. - /// - public sealed class MinimalBorder : Border - { - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => " ", - BorderPart.HeaderTop => " ", - BorderPart.HeaderTopSeparator => " ", - BorderPart.HeaderTopRight => " ", - BorderPart.HeaderLeft => " ", - BorderPart.HeaderSeparator => "│", - BorderPart.HeaderRight => " ", - BorderPart.HeaderBottomLeft => " ", - BorderPart.HeaderBottom => "─", - BorderPart.HeaderBottomSeparator => "┼", - BorderPart.HeaderBottomRight => " ", - BorderPart.CellLeft => " ", - BorderPart.CellSeparator => "│", - BorderPart.CellRight => " ", - BorderPart.FooterBottomLeft => " ", - BorderPart.FooterBottom => " ", - BorderPart.FooterBottomSeparator => " ", - BorderPart.FooterBottomRight => " ", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/MinimalDoubleHeadBorder.cs b/src/Spectre.Console/Borders/MinimalDoubleHeadBorder.cs deleted file mode 100644 index 06c9353..0000000 --- a/src/Spectre.Console/Borders/MinimalDoubleHeadBorder.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a minimal border with a double header border. - /// - public sealed class MinimalDoubleHeadBorder : Border - { - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => " ", - BorderPart.HeaderTop => " ", - BorderPart.HeaderTopSeparator => " ", - BorderPart.HeaderTopRight => " ", - BorderPart.HeaderLeft => " ", - BorderPart.HeaderSeparator => "│", - BorderPart.HeaderRight => " ", - BorderPart.HeaderBottomLeft => " ", - BorderPart.HeaderBottom => "═", - BorderPart.HeaderBottomSeparator => "╪", - BorderPart.HeaderBottomRight => " ", - BorderPart.CellLeft => " ", - BorderPart.CellSeparator => "│", - BorderPart.CellRight => " ", - BorderPart.FooterBottomLeft => " ", - BorderPart.FooterBottom => " ", - BorderPart.FooterBottomSeparator => " ", - BorderPart.FooterBottomRight => " ", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/MinimalHeavyHeadBorder.cs b/src/Spectre.Console/Borders/MinimalHeavyHeadBorder.cs deleted file mode 100644 index 6233449..0000000 --- a/src/Spectre.Console/Borders/MinimalHeavyHeadBorder.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a minimal border with a heavy header. - /// - public sealed class MinimalHeavyHeadBorder : Border - { - /// - public override Border? SafeBorder => Border.Minimal; - - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => " ", - BorderPart.HeaderTop => " ", - BorderPart.HeaderTopSeparator => " ", - BorderPart.HeaderTopRight => " ", - BorderPart.HeaderLeft => " ", - BorderPart.HeaderSeparator => "│", - BorderPart.HeaderRight => " ", - BorderPart.HeaderBottomLeft => " ", - BorderPart.HeaderBottom => "━", - BorderPart.HeaderBottomSeparator => "┿", - BorderPart.HeaderBottomRight => " ", - BorderPart.CellLeft => " ", - BorderPart.CellSeparator => "│", - BorderPart.CellRight => " ", - BorderPart.FooterBottomLeft => " ", - BorderPart.FooterBottom => " ", - BorderPart.FooterBottomSeparator => " ", - BorderPart.FooterBottomRight => " ", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/RoundedBorder.cs b/src/Spectre.Console/Borders/RoundedBorder.cs deleted file mode 100644 index 33aa634..0000000 --- a/src/Spectre.Console/Borders/RoundedBorder.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a rounded border. - /// - public sealed class RoundedBorder : Border - { - /// - public override Border? SafeBorder { get; } = Border.Square; - - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => "╭", - BorderPart.HeaderTop => "─", - BorderPart.HeaderTopSeparator => "┬", - BorderPart.HeaderTopRight => "╮", - BorderPart.HeaderLeft => "│", - BorderPart.HeaderSeparator => "│", - BorderPart.HeaderRight => "│", - BorderPart.HeaderBottomLeft => "├", - BorderPart.HeaderBottom => "─", - BorderPart.HeaderBottomSeparator => "┼", - BorderPart.HeaderBottomRight => "┤", - BorderPart.CellLeft => "│", - BorderPart.CellSeparator => "│", - BorderPart.CellRight => "│", - BorderPart.FooterBottomLeft => "╰", - BorderPart.FooterBottom => "─", - BorderPart.FooterBottomSeparator => "┴", - BorderPart.FooterBottomRight => "╯", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/SimpleBorder.cs b/src/Spectre.Console/Borders/SimpleBorder.cs deleted file mode 100644 index 481c6c4..0000000 --- a/src/Spectre.Console/Borders/SimpleBorder.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a simple border. - /// - public sealed class SimpleBorder : Border - { - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => " ", - BorderPart.HeaderTop => " ", - BorderPart.HeaderTopSeparator => " ", - BorderPart.HeaderTopRight => " ", - BorderPart.HeaderLeft => " ", - BorderPart.HeaderSeparator => " ", - BorderPart.HeaderRight => " ", - BorderPart.HeaderBottomLeft => "─", - BorderPart.HeaderBottom => "─", - BorderPart.HeaderBottomSeparator => "─", - BorderPart.HeaderBottomRight => "─", - BorderPart.CellLeft => " ", - BorderPart.CellSeparator => " ", - BorderPart.CellRight => " ", - BorderPart.FooterBottomLeft => " ", - BorderPart.FooterBottom => " ", - BorderPart.FooterBottomSeparator => " ", - BorderPart.FooterBottomRight => " ", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/SimpleHeavyBorder.cs b/src/Spectre.Console/Borders/SimpleHeavyBorder.cs deleted file mode 100644 index 20d47d4..0000000 --- a/src/Spectre.Console/Borders/SimpleHeavyBorder.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a simple border with heavy lines. - /// - public sealed class SimpleHeavyBorder : Border - { - /// - public override Border? SafeBorder => Border.Simple; - - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => " ", - BorderPart.HeaderTop => " ", - BorderPart.HeaderTopSeparator => " ", - BorderPart.HeaderTopRight => " ", - BorderPart.HeaderLeft => " ", - BorderPart.HeaderSeparator => " ", - BorderPart.HeaderRight => " ", - BorderPart.HeaderBottomLeft => "━", - BorderPart.HeaderBottom => "━", - BorderPart.HeaderBottomSeparator => "━", - BorderPart.HeaderBottomRight => "━", - BorderPart.CellLeft => " ", - BorderPart.CellSeparator => " ", - BorderPart.CellRight => " ", - BorderPart.FooterBottomLeft => " ", - BorderPart.FooterBottom => " ", - BorderPart.FooterBottomSeparator => " ", - BorderPart.FooterBottomRight => " ", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/Borders/SquareBorder.cs b/src/Spectre.Console/Borders/SquareBorder.cs deleted file mode 100644 index 1ba058e..0000000 --- a/src/Spectre.Console/Borders/SquareBorder.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace Spectre.Console.Rendering -{ - /// - /// Represents a square border. - /// - public sealed class SquareBorder : Border - { - /// - protected override string GetBoxPart(BorderPart part) - { - return part switch - { - BorderPart.HeaderTopLeft => "┌", - BorderPart.HeaderTop => "─", - BorderPart.HeaderTopSeparator => "┬", - BorderPart.HeaderTopRight => "┐", - BorderPart.HeaderLeft => "│", - BorderPart.HeaderSeparator => "│", - BorderPart.HeaderRight => "│", - BorderPart.HeaderBottomLeft => "├", - BorderPart.HeaderBottom => "─", - BorderPart.HeaderBottomSeparator => "┼", - BorderPart.HeaderBottomRight => "┤", - BorderPart.CellLeft => "│", - BorderPart.CellSeparator => "│", - BorderPart.CellRight => "│", - BorderPart.FooterBottomLeft => "└", - BorderPart.FooterBottom => "─", - BorderPart.FooterBottomSeparator => "┴", - BorderPart.FooterBottomRight => "┘", - _ => throw new InvalidOperationException("Unknown box part."), - }; - } - } -} diff --git a/src/Spectre.Console/BoxBorder.Known.cs b/src/Spectre.Console/BoxBorder.Known.cs new file mode 100644 index 0000000..192648c --- /dev/null +++ b/src/Spectre.Console/BoxBorder.Known.cs @@ -0,0 +1,42 @@ +using System.Diagnostics.CodeAnalysis; +using Spectre.Console.Rendering; + +namespace Spectre.Console +{ + /// + /// Represents a border. + /// + public abstract partial class BoxBorder + { + /// + /// Gets an invisible border. + /// + public static BoxBorder None { get; } = new NoBoxBorder(); + + /// + /// Gets an ASCII border. + /// + public static BoxBorder Ascii { get; } = new AsciiBoxBorder(); + + /// + /// Gets a double border. + /// + [SuppressMessage("Naming", "CA1720:Identifier contains type name")] + public static BoxBorder Double { get; } = new DoubleBoxBorder(); + + /// + /// Gets a heavy border. + /// + public static BoxBorder Heavy { get; } = new HeavyBoxBorder(); + + /// + /// Gets a rounded border. + /// + public static BoxBorder Rounded { get; } = new RoundedBoxBorder(); + + /// + /// Gets a square border. + /// + public static BoxBorder Square { get; } = new SquareBoxBorder(); + } +} diff --git a/src/Spectre.Console/Border.cs b/src/Spectre.Console/BoxBorder.cs similarity index 67% rename from src/Spectre.Console/Border.cs rename to src/Spectre.Console/BoxBorder.cs index 45355ea..d40f75e 100644 --- a/src/Spectre.Console/Border.cs +++ b/src/Spectre.Console/BoxBorder.cs @@ -9,45 +9,40 @@ namespace Spectre.Console /// /// Represents a border. /// - public abstract partial class Border + public abstract partial class BoxBorder { - private readonly Dictionary _lookup; - - /// - /// Gets a value indicating whether or not the border is visible. - /// - public virtual bool Visible { get; } = true; + private readonly Dictionary _lookup; /// /// Gets the safe border for this border or null if none exist. /// - public virtual Border? SafeBorder { get; } + public virtual BoxBorder? SafeBorder { get; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - protected Border() + protected BoxBorder() { _lookup = Initialize(); } - private Dictionary Initialize() + private Dictionary Initialize() { - var lookup = new Dictionary(); - foreach (BorderPart? part in Enum.GetValues(typeof(BorderPart))) + var lookup = new Dictionary(); + foreach (BoxBorderPart? part in Enum.GetValues(typeof(BoxBorderPart))) { if (part == null) { continue; } - var text = GetBoxPart(part.Value); + var text = GetBorderPart(part.Value); if (text.Length > 1) { throw new InvalidOperationException("A box part cannot contain more than one character."); } - lookup.Add(part.Value, GetBoxPart(part.Value)); + lookup.Add(part.Value, GetBorderPart(part.Value)); } return lookup; @@ -59,10 +54,10 @@ namespace Spectre.Console /// The part to get a string representation for. /// The number of repetitions. /// A string representation of the specified border part. - public string GetPart(BorderPart part, int count) + public string GetPart(BoxBorderPart part, int count) { // TODO: This need some optimization... - return string.Join(string.Empty, Enumerable.Repeat(GetBoxPart(part)[0], count)); + return string.Join(string.Empty, Enumerable.Repeat(GetBorderPart(part)[0], count)); } /// @@ -70,7 +65,7 @@ namespace Spectre.Console /// /// The part to get a string representation for. /// A string representation of the specified border part. - public string GetPart(BorderPart part) + public string GetPart(BoxBorderPart part) { return _lookup[part].ToString(CultureInfo.InvariantCulture); } @@ -80,6 +75,6 @@ namespace Spectre.Console /// /// The part to get the character representation for. /// A character representation of the specified border part. - protected abstract string GetBoxPart(BorderPart part); + protected abstract string GetBorderPart(BoxBorderPart part); } } diff --git a/src/Spectre.Console/Color.cs b/src/Spectre.Console/Color.cs index 12a990a..b58da6c 100644 --- a/src/Spectre.Console/Color.cs +++ b/src/Spectre.Console/Color.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics; using System.Globalization; -using System.Security.Cryptography; using Spectre.Console.Internal; namespace Spectre.Console diff --git a/src/Spectre.Console/Extensions/BorderExtensions.cs b/src/Spectre.Console/Extensions/BorderExtensions.cs index 6357044..b32374c 100644 --- a/src/Spectre.Console/Extensions/BorderExtensions.cs +++ b/src/Spectre.Console/Extensions/BorderExtensions.cs @@ -3,7 +3,7 @@ using System; namespace Spectre.Console.Rendering { /// - /// Contains extension methods for . + /// Contains extension methods for . /// public static class BorderExtensions { @@ -13,7 +13,7 @@ namespace Spectre.Console.Rendering /// The border to get the safe border for. /// Whether or not to return the safe border. /// The safe border if one exist, otherwise the original border. - public static Border GetSafeBorder(this Border border, bool safe) + public static TableBorder GetSafeBorder(this TableBorder border, bool safe) { if (border is null) { diff --git a/src/Spectre.Console/Extensions/BoxExtensions.cs b/src/Spectre.Console/Extensions/BoxExtensions.cs new file mode 100644 index 0000000..9dd5501 --- /dev/null +++ b/src/Spectre.Console/Extensions/BoxExtensions.cs @@ -0,0 +1,31 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Contains extension methods for . + /// + public static class BoxExtensions + { + /// + /// Gets the safe border for a border. + /// + /// The border to get the safe border for. + /// Whether or not to return the safe border. + /// The safe border if one exist, otherwise the original border. + public static BoxBorder GetSafeBorder(this BoxBorder border, bool safe) + { + if (border is null) + { + throw new ArgumentNullException(nameof(border)); + } + + if (safe && border.SafeBorder != null) + { + border = border.SafeBorder; + } + + return border; + } + } +} diff --git a/src/Spectre.Console/Extensions/HasBorderExtensions.cs b/src/Spectre.Console/Extensions/HasBorderExtensions.cs index a417176..107b8d0 100644 --- a/src/Spectre.Console/Extensions/HasBorderExtensions.cs +++ b/src/Spectre.Console/Extensions/HasBorderExtensions.cs @@ -7,229 +7,6 @@ namespace Spectre.Console /// public static class HasBorderExtensions { - /// - /// Do not display a border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T NoBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.None); - } - - /// - /// Display a square border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T SquareBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.Square); - } - - /// - /// Display an ASCII border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T AsciiBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.Ascii); - } - - /// - /// Display another ASCII border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T Ascii2Border(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.Ascii2); - } - - /// - /// Display an ASCII border with a double header border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T AsciiDoubleHeadBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.AsciiDoubleHead); - } - - /// - /// Display a rounded border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T RoundedBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.Rounded); - } - - /// - /// Display a minimal border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T MinimalBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.Minimal); - } - - /// - /// Display a minimal border with a heavy head. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T MinimalHeavyHeadBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.MinimalHeavyHead); - } - - /// - /// Display a minimal border with a double header border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T MinimalDoubleHeadBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.MinimalDoubleHead); - } - - /// - /// Display a simple border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T SimpleBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.Simple); - } - - /// - /// Display a simple border with heavy lines. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T SimpleHeavyBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.SimpleHeavy); - } - - /// - /// Display a simple border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T HorizontalBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.Horizontal); - } - - /// - /// Display a heavy border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T HeavyBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.Heavy); - } - - /// - /// Display a border with a heavy edge. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T HeavyEdgeBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.HeavyEdge); - } - - /// - /// Display a border with a heavy header. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T HeavyHeadBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.HeavyHead); - } - - /// - /// Display a double border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T DoubleBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.Double); - } - - /// - /// Display a border with a double edge. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T DoubleEdgeBorder(this T obj) - where T : class, IHasBorder - { - return SetBorder(obj, Border.DoubleEdge); - } - - /// - /// Sets the border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The border to use. - /// The same instance so that multiple calls can be chained. - public static T SetBorder(this T obj, Border border) - where T : class, IHasBorder - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.Border = border; - return obj; - } - /// /// Disables the safe border. /// diff --git a/src/Spectre.Console/Extensions/HasBoxBorderExtensions.cs b/src/Spectre.Console/Extensions/HasBoxBorderExtensions.cs new file mode 100644 index 0000000..a183b41 --- /dev/null +++ b/src/Spectre.Console/Extensions/HasBoxBorderExtensions.cs @@ -0,0 +1,101 @@ +using System; + +namespace Spectre.Console +{ + /// + /// Contains extension methods for . + /// + public static class HasBoxBorderExtensions + { + /// + /// Do not display a border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T NoBorder(this T obj) + where T : class, IHasBoxBorder + { + return SetBorder(obj, BoxBorder.None); + } + + /// + /// Display a square border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T SquareBorder(this T obj) + where T : class, IHasBoxBorder + { + return SetBorder(obj, BoxBorder.Square); + } + + /// + /// Display an ASCII border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T AsciiBorder(this T obj) + where T : class, IHasBoxBorder + { + return SetBorder(obj, BoxBorder.Ascii); + } + + /// + /// Display a rounded border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T RoundedBorder(this T obj) + where T : class, IHasBoxBorder + { + return SetBorder(obj, BoxBorder.Rounded); + } + + /// + /// Display a heavy border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HeavyBorder(this T obj) + where T : class, IHasBoxBorder + { + return SetBorder(obj, BoxBorder.Heavy); + } + + /// + /// Display a double border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T DoubleBorder(this T obj) + where T : class, IHasBoxBorder + { + return SetBorder(obj, BoxBorder.Double); + } + + /// + /// Sets the border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The border to use. + /// The same instance so that multiple calls can be chained. + public static T SetBorder(this T obj, BoxBorder border) + where T : class, IHasBoxBorder + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Border = border; + return obj; + } + } +} diff --git a/src/Spectre.Console/Extensions/HasTableBorderExtensions.cs b/src/Spectre.Console/Extensions/HasTableBorderExtensions.cs new file mode 100644 index 0000000..9cba8b1 --- /dev/null +++ b/src/Spectre.Console/Extensions/HasTableBorderExtensions.cs @@ -0,0 +1,245 @@ +using System; + +namespace Spectre.Console +{ + /// + /// Contains extension methods for . + /// + public static class HasTableBorderExtensions + { + /// + /// Do not display a border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T NoBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.None); + } + + /// + /// Display a square border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T SquareBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.Square); + } + + /// + /// Display an ASCII border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T AsciiBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.Ascii); + } + + /// + /// Display another ASCII border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T Ascii2Border(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.Ascii2); + } + + /// + /// Display an ASCII border with a double header border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T AsciiDoubleHeadBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.AsciiDoubleHead); + } + + /// + /// Display a rounded border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T RoundedBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.Rounded); + } + + /// + /// Display a minimal border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T MinimalBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.Minimal); + } + + /// + /// Display a minimal border with a heavy head. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T MinimalHeavyHeadBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.MinimalHeavyHead); + } + + /// + /// Display a minimal border with a double header border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T MinimalDoubleHeadBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.MinimalDoubleHead); + } + + /// + /// Display a simple border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T SimpleBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.Simple); + } + + /// + /// Display a simple border with heavy lines. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T SimpleHeavyBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.SimpleHeavy); + } + + /// + /// Display a simple border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HorizontalBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.Horizontal); + } + + /// + /// Display a heavy border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HeavyBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.Heavy); + } + + /// + /// Display a border with a heavy edge. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HeavyEdgeBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.HeavyEdge); + } + + /// + /// Display a border with a heavy header. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HeavyHeadBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.HeavyHead); + } + + /// + /// Display a double border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T DoubleBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.Double); + } + + /// + /// Display a border with a double edge. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T DoubleEdgeBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.DoubleEdge); + } + + /// + /// Display a markdown border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T MarkdownBorder(this T obj) + where T : class, IHasTableBorder + { + return SetBorder(obj, TableBorder.Markdown); + } + + /// + /// Sets the border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The border to use. + /// The same instance so that multiple calls can be chained. + public static T SetBorder(this T obj, TableBorder border) + where T : class, IHasTableBorder + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Border = border; + return obj; + } + } +} diff --git a/src/Spectre.Console/IHasBorder.cs b/src/Spectre.Console/IHasBorder.cs index cde0c95..9a4f0de 100644 --- a/src/Spectre.Console/IHasBorder.cs +++ b/src/Spectre.Console/IHasBorder.cs @@ -13,12 +13,7 @@ namespace Spectre.Console bool UseSafeBorder { get; set; } /// - /// Gets or sets the border. - /// - public Border Border { get; set; } - - /// - /// Gets or sets the border style. + /// Gets or sets the box style. /// public Style? BorderStyle { get; set; } } diff --git a/src/Spectre.Console/IHasBoxBorder.cs b/src/Spectre.Console/IHasBoxBorder.cs new file mode 100644 index 0000000..bb5f97b --- /dev/null +++ b/src/Spectre.Console/IHasBoxBorder.cs @@ -0,0 +1,13 @@ +namespace Spectre.Console +{ + /// + /// Represents something that has a box border. + /// + public interface IHasBoxBorder : IHasBorder + { + /// + /// Gets or sets the box. + /// + public BoxBorder Border { get; set; } + } +} diff --git a/src/Spectre.Console/IHasTableBorder.cs b/src/Spectre.Console/IHasTableBorder.cs new file mode 100644 index 0000000..0cbe19f --- /dev/null +++ b/src/Spectre.Console/IHasTableBorder.cs @@ -0,0 +1,13 @@ +namespace Spectre.Console +{ + /// + /// Represents something that has a border. + /// + public interface IHasTableBorder : IHasBorder + { + /// + /// Gets or sets the border. + /// + public TableBorder Border { get; set; } + } +} diff --git a/src/Spectre.Console/Internal/Extensions/StringExtensions.cs b/src/Spectre.Console/Internal/Extensions/StringExtensions.cs index 1c79d0a..00e91d4 100644 --- a/src/Spectre.Console/Internal/Extensions/StringExtensions.cs +++ b/src/Spectre.Console/Internal/Extensions/StringExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; using Spectre.Console.Rendering; @@ -80,27 +81,24 @@ namespace Spectre.Console.Internal return result.ToArray(); } - // https://andrewlock.net/why-is-string-gethashcode-different-each-time-i-run-my-program-in-net-core/ - public static int GetDeterministicHashCode(this string str) + public static string Multiply(this string text, int count) { - unchecked + if (text is null) { - var hash1 = (5381 << 16) + 5381; - var hash2 = hash1; - - for (var i = 0; i < str.Length; i += 2) - { - hash1 = ((hash1 << 5) + hash1) ^ str[i]; - if (i == str.Length - 1) - { - break; - } - - hash2 = ((hash2 << 5) + hash2) ^ str[i + 1]; - } - - return hash1 + (hash2 * 1566083941); + throw new ArgumentNullException(nameof(text)); } + + if (count <= 0) + { + return string.Empty; + } + + if (count == 1) + { + return text; + } + + return string.Concat(Enumerable.Repeat(text, count)); } } } diff --git a/src/Spectre.Console/Rendering/Borders/BoxBorderPart.cs b/src/Spectre.Console/Rendering/Borders/BoxBorderPart.cs new file mode 100644 index 0000000..10f79a5 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/BoxBorderPart.cs @@ -0,0 +1,48 @@ +namespace Spectre.Console.Rendering +{ + /// + /// Represents the different parts of a box border. + /// + public enum BoxBorderPart + { + /// + /// The top left part of a box. + /// + TopLeft, + + /// + /// The top part of a box. + /// + Top, + + /// + /// The top right part of a box. + /// + TopRight, + + /// + /// The left part of a box. + /// + Left, + + /// + /// The right part of a box. + /// + Right, + + /// + /// The bottom left part of a box. + /// + BottomLeft, + + /// + /// The bottom part of a box. + /// + Bottom, + + /// + /// The bottom right part of a box. + /// + BottomRight, + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Boxes/AsciiBoxBorder.cs b/src/Spectre.Console/Rendering/Borders/Boxes/AsciiBoxBorder.cs new file mode 100644 index 0000000..4d883e9 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Boxes/AsciiBoxBorder.cs @@ -0,0 +1,27 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents an old school ASCII border. + /// + public sealed class AsciiBoxBorder : BoxBorder + { + /// + protected override string GetBorderPart(BoxBorderPart part) + { + return part switch + { + BoxBorderPart.TopLeft => "+", + BoxBorderPart.Top => "-", + BoxBorderPart.TopRight => "+", + BoxBorderPart.Left => "|", + BoxBorderPart.Right => "|", + BoxBorderPart.BottomLeft => "+", + BoxBorderPart.Bottom => "-", + BoxBorderPart.BottomRight => "+", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Boxes/DoubleBoxBorder.cs b/src/Spectre.Console/Rendering/Borders/Boxes/DoubleBoxBorder.cs new file mode 100644 index 0000000..010ff4c --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Boxes/DoubleBoxBorder.cs @@ -0,0 +1,27 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a double border. + /// + public sealed class DoubleBoxBorder : BoxBorder + { + /// + protected override string GetBorderPart(BoxBorderPart part) + { + return part switch + { + BoxBorderPart.TopLeft => "╔", + BoxBorderPart.Top => "═", + BoxBorderPart.TopRight => "╗", + BoxBorderPart.Left => "║", + BoxBorderPart.Right => "║", + BoxBorderPart.BottomLeft => "╚", + BoxBorderPart.Bottom => "═", + BoxBorderPart.BottomRight => "╝", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Boxes/HeavyBoxBorder.cs b/src/Spectre.Console/Rendering/Borders/Boxes/HeavyBoxBorder.cs new file mode 100644 index 0000000..3b13f67 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Boxes/HeavyBoxBorder.cs @@ -0,0 +1,30 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a heavy border. + /// + public sealed class HeavyBoxBorder : BoxBorder + { + /// + public override BoxBorder? SafeBorder => BoxBorder.Square; + + /// + protected override string GetBorderPart(BoxBorderPart part) + { + return part switch + { + BoxBorderPart.TopLeft => "┏", + BoxBorderPart.Top => "━", + BoxBorderPart.TopRight => "┓", + BoxBorderPart.Left => "┃", + BoxBorderPart.Right => "┃", + BoxBorderPart.BottomLeft => "┗", + BoxBorderPart.Bottom => "━", + BoxBorderPart.BottomRight => "┛", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Boxes/NoBoxBorder.cs b/src/Spectre.Console/Rendering/Borders/Boxes/NoBoxBorder.cs new file mode 100644 index 0000000..504e754 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Boxes/NoBoxBorder.cs @@ -0,0 +1,14 @@ +namespace Spectre.Console.Rendering +{ + /// + /// Represents an invisible border. + /// + public sealed class NoBoxBorder : BoxBorder + { + /// + protected override string GetBorderPart(BoxBorderPart part) + { + return " "; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Boxes/RoundedBoxBorder.cs b/src/Spectre.Console/Rendering/Borders/Boxes/RoundedBoxBorder.cs new file mode 100644 index 0000000..c4ffaeb --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Boxes/RoundedBoxBorder.cs @@ -0,0 +1,30 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a rounded border. + /// + public sealed class RoundedBoxBorder : BoxBorder + { + /// + public override BoxBorder? SafeBorder => BoxBorder.Square; + + /// + protected override string GetBorderPart(BoxBorderPart part) + { + return part switch + { + BoxBorderPart.TopLeft => "╭", + BoxBorderPart.Top => "─", + BoxBorderPart.TopRight => "╮", + BoxBorderPart.Left => "│", + BoxBorderPart.Right => "│", + BoxBorderPart.BottomLeft => "╰", + BoxBorderPart.Bottom => "─", + BoxBorderPart.BottomRight => "╯", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Boxes/SquareBoxBorder.cs b/src/Spectre.Console/Rendering/Borders/Boxes/SquareBoxBorder.cs new file mode 100644 index 0000000..2374b93 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Boxes/SquareBoxBorder.cs @@ -0,0 +1,27 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a square border. + /// + public sealed class SquareBoxBorder : BoxBorder + { + /// + protected override string GetBorderPart(BoxBorderPart part) + { + return part switch + { + BoxBorderPart.TopLeft => "┌", + BoxBorderPart.Top => "─", + BoxBorderPart.TopRight => "┐", + BoxBorderPart.Left => "│", + BoxBorderPart.Right => "│", + BoxBorderPart.BottomLeft => "└", + BoxBorderPart.Bottom => "─", + BoxBorderPart.BottomRight => "┘", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/BorderPart.cs b/src/Spectre.Console/Rendering/Borders/TableBorderPart.cs similarity index 95% rename from src/Spectre.Console/Rendering/BorderPart.cs rename to src/Spectre.Console/Rendering/Borders/TableBorderPart.cs index 0f23ca3..370ad20 100644 --- a/src/Spectre.Console/Rendering/BorderPart.cs +++ b/src/Spectre.Console/Rendering/Borders/TableBorderPart.cs @@ -1,9 +1,9 @@ namespace Spectre.Console.Rendering { /// - /// Represents the different border parts. + /// Represents the different parts of a table border. /// - public enum BorderPart + public enum TableBorderPart { /// /// The top left part of a header. diff --git a/src/Spectre.Console/Rendering/Borders/Tables/Ascii2TableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/Ascii2TableBorder.cs new file mode 100644 index 0000000..b3f2cd7 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/Ascii2TableBorder.cs @@ -0,0 +1,37 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents another old school ASCII border. + /// + public sealed class Ascii2TableBorder : TableBorder + { + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => "+", + TableBorderPart.HeaderTop => "-", + TableBorderPart.HeaderTopSeparator => "+", + TableBorderPart.HeaderTopRight => "+", + TableBorderPart.HeaderLeft => "|", + TableBorderPart.HeaderSeparator => "|", + TableBorderPart.HeaderRight => "|", + TableBorderPart.HeaderBottomLeft => "|", + TableBorderPart.HeaderBottom => "-", + TableBorderPart.HeaderBottomSeparator => "+", + TableBorderPart.HeaderBottomRight => "|", + TableBorderPart.CellLeft => "|", + TableBorderPart.CellSeparator => "|", + TableBorderPart.CellRight => "|", + TableBorderPart.FooterBottomLeft => "+", + TableBorderPart.FooterBottom => "-", + TableBorderPart.FooterBottomSeparator => "+", + TableBorderPart.FooterBottomRight => "+", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/AsciiDoubleHeadTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/AsciiDoubleHeadTableBorder.cs new file mode 100644 index 0000000..1e36b14 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/AsciiDoubleHeadTableBorder.cs @@ -0,0 +1,37 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents an old school ASCII border with a double header border. + /// + public sealed class AsciiDoubleHeadTableBorder : TableBorder + { + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => "+", + TableBorderPart.HeaderTop => "-", + TableBorderPart.HeaderTopSeparator => "+", + TableBorderPart.HeaderTopRight => "+", + TableBorderPart.HeaderLeft => "|", + TableBorderPart.HeaderSeparator => "|", + TableBorderPart.HeaderRight => "|", + TableBorderPart.HeaderBottomLeft => "|", + TableBorderPart.HeaderBottom => "=", + TableBorderPart.HeaderBottomSeparator => "+", + TableBorderPart.HeaderBottomRight => "|", + TableBorderPart.CellLeft => "|", + TableBorderPart.CellSeparator => "|", + TableBorderPart.CellRight => "|", + TableBorderPart.FooterBottomLeft => "+", + TableBorderPart.FooterBottom => "-", + TableBorderPart.FooterBottomSeparator => "+", + TableBorderPart.FooterBottomRight => "+", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/AsciiTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/AsciiTableBorder.cs new file mode 100644 index 0000000..cc1ea2d --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/AsciiTableBorder.cs @@ -0,0 +1,37 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents an old school ASCII border. + /// + public sealed class AsciiTableBorder : TableBorder + { + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => "+", + TableBorderPart.HeaderTop => "-", + TableBorderPart.HeaderTopSeparator => "-", + TableBorderPart.HeaderTopRight => "+", + TableBorderPart.HeaderLeft => "|", + TableBorderPart.HeaderSeparator => "|", + TableBorderPart.HeaderRight => "|", + TableBorderPart.HeaderBottomLeft => "|", + TableBorderPart.HeaderBottom => "-", + TableBorderPart.HeaderBottomSeparator => "+", + TableBorderPart.HeaderBottomRight => "|", + TableBorderPart.CellLeft => "|", + TableBorderPart.CellSeparator => "|", + TableBorderPart.CellRight => "|", + TableBorderPart.FooterBottomLeft => "+", + TableBorderPart.FooterBottom => "-", + TableBorderPart.FooterBottomSeparator => "-", + TableBorderPart.FooterBottomRight => "+", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/DoubleEdgeTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/DoubleEdgeTableBorder.cs new file mode 100644 index 0000000..fe0e8d7 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/DoubleEdgeTableBorder.cs @@ -0,0 +1,37 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a border with a double edge. + /// + public sealed class DoubleEdgeTableBorder : TableBorder + { + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => "╔", + TableBorderPart.HeaderTop => "═", + TableBorderPart.HeaderTopSeparator => "╤", + TableBorderPart.HeaderTopRight => "╗", + TableBorderPart.HeaderLeft => "║", + TableBorderPart.HeaderSeparator => "│", + TableBorderPart.HeaderRight => "║", + TableBorderPart.HeaderBottomLeft => "╟", + TableBorderPart.HeaderBottom => "─", + TableBorderPart.HeaderBottomSeparator => "┼", + TableBorderPart.HeaderBottomRight => "╢", + TableBorderPart.CellLeft => "║", + TableBorderPart.CellSeparator => "│", + TableBorderPart.CellRight => "║", + TableBorderPart.FooterBottomLeft => "╚", + TableBorderPart.FooterBottom => "═", + TableBorderPart.FooterBottomSeparator => "╧", + TableBorderPart.FooterBottomRight => "╝", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/DoubleTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/DoubleTableBorder.cs new file mode 100644 index 0000000..7fdf06b --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/DoubleTableBorder.cs @@ -0,0 +1,37 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a double border. + /// + public sealed class DoubleTableBorder : TableBorder + { + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => "╔", + TableBorderPart.HeaderTop => "═", + TableBorderPart.HeaderTopSeparator => "╦", + TableBorderPart.HeaderTopRight => "╗", + TableBorderPart.HeaderLeft => "║", + TableBorderPart.HeaderSeparator => "║", + TableBorderPart.HeaderRight => "║", + TableBorderPart.HeaderBottomLeft => "╠", + TableBorderPart.HeaderBottom => "═", + TableBorderPart.HeaderBottomSeparator => "╬", + TableBorderPart.HeaderBottomRight => "╣", + TableBorderPart.CellLeft => "║", + TableBorderPart.CellSeparator => "║", + TableBorderPart.CellRight => "║", + TableBorderPart.FooterBottomLeft => "╚", + TableBorderPart.FooterBottom => "═", + TableBorderPart.FooterBottomSeparator => "╩", + TableBorderPart.FooterBottomRight => "╝", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/HeavyEdgeTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/HeavyEdgeTableBorder.cs new file mode 100644 index 0000000..9aa3c92 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/HeavyEdgeTableBorder.cs @@ -0,0 +1,40 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a border with a heavy edge. + /// + public sealed class HeavyEdgeTableBorder : TableBorder + { + /// + public override TableBorder? SafeBorder => TableBorder.Square; + + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => "┏", + TableBorderPart.HeaderTop => "━", + TableBorderPart.HeaderTopSeparator => "┯", + TableBorderPart.HeaderTopRight => "┓", + TableBorderPart.HeaderLeft => "┃", + TableBorderPart.HeaderSeparator => "│", + TableBorderPart.HeaderRight => "┃", + TableBorderPart.HeaderBottomLeft => "┠", + TableBorderPart.HeaderBottom => "─", + TableBorderPart.HeaderBottomSeparator => "┼", + TableBorderPart.HeaderBottomRight => "┨", + TableBorderPart.CellLeft => "┃", + TableBorderPart.CellSeparator => "│", + TableBorderPart.CellRight => "┃", + TableBorderPart.FooterBottomLeft => "┗", + TableBorderPart.FooterBottom => "━", + TableBorderPart.FooterBottomSeparator => "┷", + TableBorderPart.FooterBottomRight => "┛", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/HeavyHeadTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/HeavyHeadTableBorder.cs new file mode 100644 index 0000000..d51401f --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/HeavyHeadTableBorder.cs @@ -0,0 +1,40 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a border with a heavy header. + /// + public sealed class HeavyHeadTableBorder : TableBorder + { + /// + public override TableBorder? SafeBorder => TableBorder.Square; + + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => "┏", + TableBorderPart.HeaderTop => "━", + TableBorderPart.HeaderTopSeparator => "┳", + TableBorderPart.HeaderTopRight => "┓", + TableBorderPart.HeaderLeft => "┃", + TableBorderPart.HeaderSeparator => "┃", + TableBorderPart.HeaderRight => "┃", + TableBorderPart.HeaderBottomLeft => "┡", + TableBorderPart.HeaderBottom => "━", + TableBorderPart.HeaderBottomSeparator => "╇", + TableBorderPart.HeaderBottomRight => "┩", + TableBorderPart.CellLeft => "│", + TableBorderPart.CellSeparator => "│", + TableBorderPart.CellRight => "│", + TableBorderPart.FooterBottomLeft => "└", + TableBorderPart.FooterBottom => "─", + TableBorderPart.FooterBottomSeparator => "┴", + TableBorderPart.FooterBottomRight => "┘", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/HeavyTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/HeavyTableBorder.cs new file mode 100644 index 0000000..e7c6d90 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/HeavyTableBorder.cs @@ -0,0 +1,40 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a heavy border. + /// + public sealed class HeavyTableBorder : TableBorder + { + /// + public override TableBorder? SafeBorder => TableBorder.Square; + + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => "┏", + TableBorderPart.HeaderTop => "━", + TableBorderPart.HeaderTopSeparator => "┳", + TableBorderPart.HeaderTopRight => "┓", + TableBorderPart.HeaderLeft => "┃", + TableBorderPart.HeaderSeparator => "┃", + TableBorderPart.HeaderRight => "┃", + TableBorderPart.HeaderBottomLeft => "┣", + TableBorderPart.HeaderBottom => "━", + TableBorderPart.HeaderBottomSeparator => "╋", + TableBorderPart.HeaderBottomRight => "┫", + TableBorderPart.CellLeft => "┃", + TableBorderPart.CellSeparator => "┃", + TableBorderPart.CellRight => "┃", + TableBorderPart.FooterBottomLeft => "┗", + TableBorderPart.FooterBottom => "━", + TableBorderPart.FooterBottomSeparator => "┻", + TableBorderPart.FooterBottomRight => "┛", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/HorizontalTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/HorizontalTableBorder.cs new file mode 100644 index 0000000..e8cb667 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/HorizontalTableBorder.cs @@ -0,0 +1,37 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a horizontal border. + /// + public sealed class HorizontalTableBorder : TableBorder + { + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => "─", + TableBorderPart.HeaderTop => "─", + TableBorderPart.HeaderTopSeparator => "─", + TableBorderPart.HeaderTopRight => "─", + TableBorderPart.HeaderLeft => " ", + TableBorderPart.HeaderSeparator => " ", + TableBorderPart.HeaderRight => " ", + TableBorderPart.HeaderBottomLeft => "─", + TableBorderPart.HeaderBottom => "─", + TableBorderPart.HeaderBottomSeparator => "─", + TableBorderPart.HeaderBottomRight => "─", + TableBorderPart.CellLeft => " ", + TableBorderPart.CellSeparator => " ", + TableBorderPart.CellRight => " ", + TableBorderPart.FooterBottomLeft => "─", + TableBorderPart.FooterBottom => "─", + TableBorderPart.FooterBottomSeparator => "─", + TableBorderPart.FooterBottomRight => "─", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/MarkdownTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/MarkdownTableBorder.cs new file mode 100644 index 0000000..4e734f2 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/MarkdownTableBorder.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Spectre.Console.Internal; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a Markdown border. + /// + public sealed class MarkdownTableBorder : TableBorder + { + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => " ", + TableBorderPart.HeaderTop => " ", + TableBorderPart.HeaderTopSeparator => " ", + TableBorderPart.HeaderTopRight => " ", + TableBorderPart.HeaderLeft => "|", + TableBorderPart.HeaderSeparator => "|", + TableBorderPart.HeaderRight => "|", + TableBorderPart.HeaderBottomLeft => "|", + TableBorderPart.HeaderBottom => "-", + TableBorderPart.HeaderBottomSeparator => "|", + TableBorderPart.HeaderBottomRight => "|", + TableBorderPart.CellLeft => "|", + TableBorderPart.CellSeparator => "|", + TableBorderPart.CellRight => "|", + TableBorderPart.FooterBottomLeft => " ", + TableBorderPart.FooterBottom => " ", + TableBorderPart.FooterBottomSeparator => " ", + TableBorderPart.FooterBottomRight => " ", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + + /// + public override string GetColumnRow(TablePart part, IReadOnlyList widths, IReadOnlyList columns) + { + if (part != TablePart.Separator) + { + return base.GetColumnRow(part, widths, columns); + } + + var (left, center, separator, right) = GetTableParts(part); + + var builder = new StringBuilder(); + builder.Append(left); + + foreach (var (columnIndex, _, lastColumn, columnWidth) in widths.Enumerate()) + { + var padding = columns[columnIndex].Padding; + + if (padding.Left > 0) + { + // Left padding + builder.Append(" ".Multiply(padding.Left)); + } + + var justification = columns[columnIndex].Alignment; + if (justification == null) + { + // No alignment + builder.Append(center.Multiply(columnWidth)); + } + else if (justification.Value == Justify.Left) + { + // Left + builder.Append(':'); + builder.Append(center.Multiply(columnWidth - 1)); + } + else if (justification.Value == Justify.Center) + { + // Centered + builder.Append(':'); + builder.Append(center.Multiply(columnWidth - 2)); + builder.Append(':'); + } + else if (justification.Value == Justify.Right) + { + // Right + builder.Append(center.Multiply(columnWidth - 1)); + builder.Append(':'); + } + + // Right padding + if (padding.Right > 0) + { + builder.Append(" ".Multiply(padding.Right)); + } + + if (!lastColumn) + { + builder.Append(separator); + } + } + + builder.Append(right); + return builder.ToString(); + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/MinimalDoubleHeadTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/MinimalDoubleHeadTableBorder.cs new file mode 100644 index 0000000..86b5872 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/MinimalDoubleHeadTableBorder.cs @@ -0,0 +1,37 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a minimal border with a double header border. + /// + public sealed class MinimalDoubleHeadTableBorder : TableBorder + { + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => " ", + TableBorderPart.HeaderTop => " ", + TableBorderPart.HeaderTopSeparator => " ", + TableBorderPart.HeaderTopRight => " ", + TableBorderPart.HeaderLeft => " ", + TableBorderPart.HeaderSeparator => "│", + TableBorderPart.HeaderRight => " ", + TableBorderPart.HeaderBottomLeft => " ", + TableBorderPart.HeaderBottom => "═", + TableBorderPart.HeaderBottomSeparator => "╪", + TableBorderPart.HeaderBottomRight => " ", + TableBorderPart.CellLeft => " ", + TableBorderPart.CellSeparator => "│", + TableBorderPart.CellRight => " ", + TableBorderPart.FooterBottomLeft => " ", + TableBorderPart.FooterBottom => " ", + TableBorderPart.FooterBottomSeparator => " ", + TableBorderPart.FooterBottomRight => " ", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/MinimalHeavyHeadTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/MinimalHeavyHeadTableBorder.cs new file mode 100644 index 0000000..a6da029 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/MinimalHeavyHeadTableBorder.cs @@ -0,0 +1,40 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a minimal border with a heavy header. + /// + public sealed class MinimalHeavyHeadTableBorder : TableBorder + { + /// + public override TableBorder? SafeBorder => TableBorder.Minimal; + + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => " ", + TableBorderPart.HeaderTop => " ", + TableBorderPart.HeaderTopSeparator => " ", + TableBorderPart.HeaderTopRight => " ", + TableBorderPart.HeaderLeft => " ", + TableBorderPart.HeaderSeparator => "│", + TableBorderPart.HeaderRight => " ", + TableBorderPart.HeaderBottomLeft => " ", + TableBorderPart.HeaderBottom => "━", + TableBorderPart.HeaderBottomSeparator => "┿", + TableBorderPart.HeaderBottomRight => " ", + TableBorderPart.CellLeft => " ", + TableBorderPart.CellSeparator => "│", + TableBorderPart.CellRight => " ", + TableBorderPart.FooterBottomLeft => " ", + TableBorderPart.FooterBottom => " ", + TableBorderPart.FooterBottomSeparator => " ", + TableBorderPart.FooterBottomRight => " ", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/MinimalTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/MinimalTableBorder.cs new file mode 100644 index 0000000..48741a9 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/MinimalTableBorder.cs @@ -0,0 +1,37 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a minimal border. + /// + public sealed class MinimalTableBorder : TableBorder + { + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => " ", + TableBorderPart.HeaderTop => " ", + TableBorderPart.HeaderTopSeparator => " ", + TableBorderPart.HeaderTopRight => " ", + TableBorderPart.HeaderLeft => " ", + TableBorderPart.HeaderSeparator => "│", + TableBorderPart.HeaderRight => " ", + TableBorderPart.HeaderBottomLeft => " ", + TableBorderPart.HeaderBottom => "─", + TableBorderPart.HeaderBottomSeparator => "┼", + TableBorderPart.HeaderBottomRight => " ", + TableBorderPart.CellLeft => " ", + TableBorderPart.CellSeparator => "│", + TableBorderPart.CellRight => " ", + TableBorderPart.FooterBottomLeft => " ", + TableBorderPart.FooterBottom => " ", + TableBorderPart.FooterBottomSeparator => " ", + TableBorderPart.FooterBottomRight => " ", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Borders/NoBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/NoTableBorder.cs similarity index 69% rename from src/Spectre.Console/Borders/NoBorder.cs rename to src/Spectre.Console/Rendering/Borders/Tables/NoTableBorder.cs index 2350e7d..4153553 100644 --- a/src/Spectre.Console/Borders/NoBorder.cs +++ b/src/Spectre.Console/Rendering/Borders/Tables/NoTableBorder.cs @@ -3,13 +3,13 @@ namespace Spectre.Console.Rendering /// /// Represents an invisible border. /// - public sealed class NoBorder : Border + public sealed class NoTableBorder : TableBorder { /// public override bool Visible => false; /// - protected override string GetBoxPart(BorderPart part) + protected override string GetBorderPart(TableBorderPart part) { return " "; } diff --git a/src/Spectre.Console/Rendering/Borders/Tables/RoundedTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/RoundedTableBorder.cs new file mode 100644 index 0000000..dbdff51 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/RoundedTableBorder.cs @@ -0,0 +1,40 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a rounded border. + /// + public sealed class RoundedTableBorder : TableBorder + { + /// + public override TableBorder? SafeBorder => TableBorder.Square; + + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => "╭", + TableBorderPart.HeaderTop => "─", + TableBorderPart.HeaderTopSeparator => "┬", + TableBorderPart.HeaderTopRight => "╮", + TableBorderPart.HeaderLeft => "│", + TableBorderPart.HeaderSeparator => "│", + TableBorderPart.HeaderRight => "│", + TableBorderPart.HeaderBottomLeft => "├", + TableBorderPart.HeaderBottom => "─", + TableBorderPart.HeaderBottomSeparator => "┼", + TableBorderPart.HeaderBottomRight => "┤", + TableBorderPart.CellLeft => "│", + TableBorderPart.CellSeparator => "│", + TableBorderPart.CellRight => "│", + TableBorderPart.FooterBottomLeft => "╰", + TableBorderPart.FooterBottom => "─", + TableBorderPart.FooterBottomSeparator => "┴", + TableBorderPart.FooterBottomRight => "╯", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/SimpleHeavyTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/SimpleHeavyTableBorder.cs new file mode 100644 index 0000000..dbe2a93 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/SimpleHeavyTableBorder.cs @@ -0,0 +1,40 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a simple border with heavy lines. + /// + public sealed class SimpleHeavyTableBorder : TableBorder + { + /// + public override TableBorder? SafeBorder => TableBorder.Simple; + + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => " ", + TableBorderPart.HeaderTop => " ", + TableBorderPart.HeaderTopSeparator => " ", + TableBorderPart.HeaderTopRight => " ", + TableBorderPart.HeaderLeft => " ", + TableBorderPart.HeaderSeparator => " ", + TableBorderPart.HeaderRight => " ", + TableBorderPart.HeaderBottomLeft => "━", + TableBorderPart.HeaderBottom => "━", + TableBorderPart.HeaderBottomSeparator => "━", + TableBorderPart.HeaderBottomRight => "━", + TableBorderPart.CellLeft => " ", + TableBorderPart.CellSeparator => " ", + TableBorderPart.CellRight => " ", + TableBorderPart.FooterBottomLeft => " ", + TableBorderPart.FooterBottom => " ", + TableBorderPart.FooterBottomSeparator => " ", + TableBorderPart.FooterBottomRight => " ", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/SimpleTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/SimpleTableBorder.cs new file mode 100644 index 0000000..5ca7711 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/SimpleTableBorder.cs @@ -0,0 +1,37 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a simple border. + /// + public sealed class SimpleTableBorder : TableBorder + { + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => " ", + TableBorderPart.HeaderTop => " ", + TableBorderPart.HeaderTopSeparator => " ", + TableBorderPart.HeaderTopRight => " ", + TableBorderPart.HeaderLeft => " ", + TableBorderPart.HeaderSeparator => " ", + TableBorderPart.HeaderRight => " ", + TableBorderPart.HeaderBottomLeft => "─", + TableBorderPart.HeaderBottom => "─", + TableBorderPart.HeaderBottomSeparator => "─", + TableBorderPart.HeaderBottomRight => "─", + TableBorderPart.CellLeft => " ", + TableBorderPart.CellSeparator => " ", + TableBorderPart.CellRight => " ", + TableBorderPart.FooterBottomLeft => " ", + TableBorderPart.FooterBottom => " ", + TableBorderPart.FooterBottomSeparator => " ", + TableBorderPart.FooterBottomRight => " ", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/Borders/Tables/SquareTableBorder.cs b/src/Spectre.Console/Rendering/Borders/Tables/SquareTableBorder.cs new file mode 100644 index 0000000..e6582b0 --- /dev/null +++ b/src/Spectre.Console/Rendering/Borders/Tables/SquareTableBorder.cs @@ -0,0 +1,37 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a square border. + /// + public sealed class SquareTableBorder : TableBorder + { + /// + protected override string GetBorderPart(TableBorderPart part) + { + return part switch + { + TableBorderPart.HeaderTopLeft => "┌", + TableBorderPart.HeaderTop => "─", + TableBorderPart.HeaderTopSeparator => "┬", + TableBorderPart.HeaderTopRight => "┐", + TableBorderPart.HeaderLeft => "│", + TableBorderPart.HeaderSeparator => "│", + TableBorderPart.HeaderRight => "│", + TableBorderPart.HeaderBottomLeft => "├", + TableBorderPart.HeaderBottom => "─", + TableBorderPart.HeaderBottomSeparator => "┼", + TableBorderPart.HeaderBottomRight => "┤", + TableBorderPart.CellLeft => "│", + TableBorderPart.CellSeparator => "│", + TableBorderPart.CellRight => "│", + TableBorderPart.FooterBottomLeft => "└", + TableBorderPart.FooterBottom => "─", + TableBorderPart.FooterBottomSeparator => "┴", + TableBorderPart.FooterBottomRight => "┘", + _ => throw new InvalidOperationException("Unknown border part."), + }; + } + } +} diff --git a/src/Spectre.Console/Rendering/TablePart.cs b/src/Spectre.Console/Rendering/TablePart.cs new file mode 100644 index 0000000..6c86d01 --- /dev/null +++ b/src/Spectre.Console/Rendering/TablePart.cs @@ -0,0 +1,23 @@ +namespace Spectre.Console.Rendering +{ + /// + /// Represents different parts of a table. + /// + public enum TablePart + { + /// + /// The top of a table. + /// + Top, + + /// + /// The separator between the header and the cells. + /// + Separator, + + /// + /// The bottom of a table. + /// + Bottom, + } +} diff --git a/src/Spectre.Console/Spectre.Console.csproj b/src/Spectre.Console/Spectre.Console.csproj index cdb627d..aa72927 100644 --- a/src/Spectre.Console/Spectre.Console.csproj +++ b/src/Spectre.Console/Spectre.Console.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -14,12 +14,15 @@ AnsiConsole.cs - - Color.cs - Border.cs + + BoxBorder.cs + + + Color.cs + Emoji.cs @@ -39,6 +42,12 @@ + + BoxBorder.cs + + + TableBorder.cs + AnsiConsoleExtensions.cs diff --git a/src/Spectre.Console/Border.Known.cs b/src/Spectre.Console/TableBorder.Known.cs similarity index 51% rename from src/Spectre.Console/Border.Known.cs rename to src/Spectre.Console/TableBorder.Known.cs index 4bbf125..248d93c 100644 --- a/src/Spectre.Console/Border.Known.cs +++ b/src/Spectre.Console/TableBorder.Known.cs @@ -6,92 +6,97 @@ namespace Spectre.Console /// /// Represents a border. /// - public abstract partial class Border + public abstract partial class TableBorder { /// /// Gets an invisible border. /// - public static Border None { get; } = new NoBorder(); + public static TableBorder None { get; } = new NoTableBorder(); /// /// Gets an ASCII border. /// - public static Border Ascii { get; } = new AsciiBorder(); + public static TableBorder Ascii { get; } = new AsciiTableBorder(); /// - /// Gets another ASCII border. + /// Gets an ASCII border. /// - public static Border Ascii2 { get; } = new Ascii2Border(); + public static TableBorder Ascii2 { get; } = new Ascii2TableBorder(); /// /// Gets an ASCII border with a double header border. /// - public static Border AsciiDoubleHead { get; } = new AsciiDoubleHeadBorder(); + public static TableBorder AsciiDoubleHead { get; } = new AsciiDoubleHeadTableBorder(); /// /// Gets a square border. /// - public static Border Square { get; } = new SquareBorder(); + public static TableBorder Square { get; } = new SquareTableBorder(); /// /// Gets a rounded border. /// - public static Border Rounded { get; } = new RoundedBorder(); + public static TableBorder Rounded { get; } = new RoundedTableBorder(); /// /// Gets a minimal border. /// - public static Border Minimal { get; } = new MinimalBorder(); + public static TableBorder Minimal { get; } = new MinimalTableBorder(); /// /// Gets a minimal border with a heavy head. /// - public static Border MinimalHeavyHead { get; } = new MinimalHeavyHeadBorder(); + public static TableBorder MinimalHeavyHead { get; } = new MinimalHeavyHeadTableBorder(); /// /// Gets a minimal border with a double header border. /// - public static Border MinimalDoubleHead { get; } = new MinimalDoubleHeadBorder(); + public static TableBorder MinimalDoubleHead { get; } = new MinimalDoubleHeadTableBorder(); /// /// Gets a simple border. /// - public static Border Simple { get; } = new SimpleBorder(); + public static TableBorder Simple { get; } = new SimpleTableBorder(); /// /// Gets a simple border with heavy lines. /// - public static Border SimpleHeavy { get; } = new SimpleHeavyBorder(); + public static TableBorder SimpleHeavy { get; } = new SimpleHeavyTableBorder(); /// /// Gets a horizontal border. /// - public static Border Horizontal { get; } = new HorizontalBorder(); + public static TableBorder Horizontal { get; } = new HorizontalTableBorder(); /// /// Gets a heavy border. /// - public static Border Heavy { get; } = new HeavyBorder(); + public static TableBorder Heavy { get; } = new HeavyTableBorder(); /// /// Gets a border with a heavy edge. /// - public static Border HeavyEdge { get; } = new HeavyEdgeBorder(); + public static TableBorder HeavyEdge { get; } = new HeavyEdgeTableBorder(); /// /// Gets a border with a heavy header. /// - public static Border HeavyHead { get; } = new HeavyHeadBorder(); + public static TableBorder HeavyHead { get; } = new HeavyHeadTableBorder(); /// /// Gets a double border. /// [SuppressMessage("Naming", "CA1720:Identifier contains type name")] - public static Border Double { get; } = new DoubleBorder(); + public static TableBorder Double { get; } = new DoubleTableBorder(); /// /// Gets a border with a double edge. /// - public static Border DoubleEdge { get; } = new DoubleEdgeBorder(); + public static TableBorder DoubleEdge { get; } = new DoubleEdgeTableBorder(); + + /// + /// Gets a markdown border. + /// + public static TableBorder Markdown { get; } = new MarkdownTableBorder(); } } diff --git a/src/Spectre.Console/TableBorder.cs b/src/Spectre.Console/TableBorder.cs new file mode 100644 index 0000000..cb2c21b --- /dev/null +++ b/src/Spectre.Console/TableBorder.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using Spectre.Console.Internal; +using Spectre.Console.Rendering; + +namespace Spectre.Console +{ + /// + /// Represents a border. + /// + public abstract partial class TableBorder + { + private readonly Dictionary _lookup; + + /// + /// Gets a value indicating whether or not the border is visible. + /// + public virtual bool Visible { get; } = true; + + /// + /// Gets the safe border for this border or null if none exist. + /// + public virtual TableBorder? SafeBorder { get; } + + /// + /// Initializes a new instance of the class. + /// + protected TableBorder() + { + _lookup = Initialize(); + } + + private Dictionary Initialize() + { + var lookup = new Dictionary(); + foreach (TableBorderPart? part in Enum.GetValues(typeof(TableBorderPart))) + { + if (part == null) + { + continue; + } + + var text = GetBorderPart(part.Value); + if (text.Length > 1) + { + throw new InvalidOperationException("A box part cannot contain more than one character."); + } + + lookup.Add(part.Value, GetBorderPart(part.Value)); + } + + return lookup; + } + + /// + /// Gets the string representation of a specific border part. + /// + /// The part to get a string representation for. + /// The number of repetitions. + /// A string representation of the specified border part. + public string GetPart(TableBorderPart part, int count) + { + // TODO: This need some optimization... + return string.Join(string.Empty, Enumerable.Repeat(GetBorderPart(part)[0], count)); + } + + /// + /// Gets a whole column row for the specific column row part. + /// + /// The column row part. + /// The column widths. + /// The columns. + /// A string representing the column row. + public virtual string GetColumnRow(TablePart part, IReadOnlyList widths, IReadOnlyList columns) + { + if (widths is null) + { + throw new ArgumentNullException(nameof(widths)); + } + + if (columns is null) + { + throw new ArgumentNullException(nameof(columns)); + } + + var (left, center, separator, right) = GetTableParts(part); + + var builder = new StringBuilder(); + builder.Append(left); + + foreach (var (columnIndex, _, lastColumn, columnWidth) in widths.Enumerate()) + { + var padding = columns[columnIndex].Padding; + var centerWidth = padding.Left + columnWidth + padding.Right; + builder.Append(center.Multiply(centerWidth)); + + if (!lastColumn) + { + builder.Append(separator); + } + } + + builder.Append(right); + return builder.ToString(); + } + + /// + /// Gets the string representation of a specific border part. + /// + /// The part to get a string representation for. + /// A string representation of the specified border part. + public string GetPart(TableBorderPart part) + { + return _lookup[part].ToString(CultureInfo.InvariantCulture); + } + + /// + /// Gets the character representing the specified border part. + /// + /// The part to get the character representation for. + /// A character representation of the specified border part. + protected abstract string GetBorderPart(TableBorderPart part); + + /// + /// Gets the table parts used to render a specific table row. + /// + /// The table part. + /// The table parts used to render the specific table row. + protected (string Left, string Center, string Separator, string Right) + GetTableParts(TablePart part) + { + return part switch + { + // Top part + TablePart.Top => + (GetPart(TableBorderPart.HeaderTopLeft), GetPart(TableBorderPart.HeaderTop), + GetPart(TableBorderPart.HeaderTopSeparator), GetPart(TableBorderPart.HeaderTopRight)), + + // Separator between header and cells + TablePart.Separator => + (GetPart(TableBorderPart.HeaderBottomLeft), GetPart(TableBorderPart.HeaderBottom), + GetPart(TableBorderPart.HeaderBottomSeparator), GetPart(TableBorderPart.HeaderBottomRight)), + + // Bottom part + TablePart.Bottom => + (GetPart(TableBorderPart.FooterBottomLeft), GetPart(TableBorderPart.FooterBottom), + GetPart(TableBorderPart.FooterBottomSeparator), GetPart(TableBorderPart.FooterBottomRight)), + + // Unknown + _ => throw new NotSupportedException("Unknown column row part"), + }; + } + } +} diff --git a/src/Spectre.Console/Widgets/Grid.cs b/src/Spectre.Console/Widgets/Grid.cs index 3a7d1a1..4fe9181 100644 --- a/src/Spectre.Console/Widgets/Grid.cs +++ b/src/Spectre.Console/Widgets/Grid.cs @@ -35,7 +35,7 @@ namespace Spectre.Console { _table = new Table { - Border = Border.None, + Border = TableBorder.None, ShowHeaders = false, IsGrid = true, PadRightCell = false, diff --git a/src/Spectre.Console/Widgets/Panel.cs b/src/Spectre.Console/Widgets/Panel.cs index c4ae217..efe4c88 100644 --- a/src/Spectre.Console/Widgets/Panel.cs +++ b/src/Spectre.Console/Widgets/Panel.cs @@ -8,14 +8,14 @@ namespace Spectre.Console /// /// A renderable panel. /// - public sealed class Panel : Renderable, IHasBorder, IExpandable, IPaddable + public sealed class Panel : Renderable, IHasBoxBorder, IExpandable, IPaddable { private const int EdgeWidth = 2; private readonly IRenderable _child; /// - public Border Border { get; set; } = Border.Square; + public BoxBorder Border { get; set; } = BoxBorder.Square; /// public bool UseSafeBorder { get; set; } = true; @@ -95,7 +95,7 @@ namespace Spectre.Console var childSegments = ((IRenderable)child).Render(context, childWidth); foreach (var line in Segment.SplitLines(childSegments, panelWidth)) { - result.Add(new Segment(border.GetPart(BorderPart.CellLeft), borderStyle)); + result.Add(new Segment(border.GetPart(BoxBorderPart.Left), borderStyle)); var content = new List(); content.AddRange(line); @@ -110,7 +110,7 @@ namespace Spectre.Console result.AddRange(content); - result.Add(new Segment(border.GetPart(BorderPart.CellRight), borderStyle)); + result.Add(new Segment(border.GetPart(BoxBorderPart.Right), borderStyle)); result.Add(Segment.LineBreak); } @@ -120,17 +120,17 @@ namespace Spectre.Console return result; } - private static void AddBottomBorder(List result, Border border, Style borderStyle, int panelWidth) + private static void AddBottomBorder(List result, BoxBorder border, Style borderStyle, int panelWidth) { - result.Add(new Segment(border.GetPart(BorderPart.FooterBottomLeft), borderStyle)); - result.Add(new Segment(border.GetPart(BorderPart.FooterBottom, panelWidth - EdgeWidth), borderStyle)); - result.Add(new Segment(border.GetPart(BorderPart.FooterBottomRight), borderStyle)); + result.Add(new Segment(border.GetPart(BoxBorderPart.BottomLeft), borderStyle)); + result.Add(new Segment(border.GetPart(BoxBorderPart.Bottom, panelWidth - EdgeWidth), borderStyle)); + result.Add(new Segment(border.GetPart(BoxBorderPart.BottomRight), borderStyle)); result.Add(Segment.LineBreak); } - private void AddTopBorder(List segments, RenderContext context, Border border, Style borderStyle, int panelWidth) + private void AddTopBorder(List segments, RenderContext context, BoxBorder border, Style borderStyle, int panelWidth) { - segments.Add(new Segment(border.GetPart(BorderPart.HeaderTopLeft), borderStyle)); + segments.Add(new Segment(border.GetPart(BoxBorderPart.TopLeft), borderStyle)); if (Header != null) { @@ -160,16 +160,16 @@ namespace Spectre.Console } } - segments.Add(new Segment(border.GetPart(BorderPart.HeaderTop, leftSpacing + 1), borderStyle)); + segments.Add(new Segment(border.GetPart(BoxBorderPart.Top, leftSpacing + 1), borderStyle)); segments.Add(header); - segments.Add(new Segment(border.GetPart(BorderPart.HeaderTop, rightSpacing + 1), borderStyle)); + segments.Add(new Segment(border.GetPart(BoxBorderPart.Top, rightSpacing + 1), borderStyle)); } else { - segments.Add(new Segment(border.GetPart(BorderPart.HeaderTop, panelWidth - EdgeWidth), borderStyle)); + segments.Add(new Segment(border.GetPart(BoxBorderPart.Top, panelWidth - EdgeWidth), borderStyle)); } - segments.Add(new Segment(border.GetPart(BorderPart.HeaderTopRight), borderStyle)); + segments.Add(new Segment(border.GetPart(BoxBorderPart.TopRight), borderStyle)); segments.Add(Segment.LineBreak); } } diff --git a/src/Spectre.Console/Widgets/Table.cs b/src/Spectre.Console/Widgets/Table.cs index 827a440..f6d723d 100644 --- a/src/Spectre.Console/Widgets/Table.cs +++ b/src/Spectre.Console/Widgets/Table.cs @@ -9,7 +9,7 @@ namespace Spectre.Console /// /// A renderable table. /// - public sealed class Table : Renderable, IHasBorder, IExpandable + public sealed class Table : Renderable, IHasTableBorder, IExpandable { private const int EdgeCount = 2; @@ -27,7 +27,7 @@ namespace Spectre.Console public int RowCount => _rows.Count; /// - public Border Border { get; set; } = Border.Square; + public TableBorder Border { get; set; } = TableBorder.Square; /// public Style? BorderStyle { get; set; } @@ -202,22 +202,8 @@ namespace Spectre.Console // Show top of header? if (firstRow && showBorder) { - result.Add(new Segment(border.GetPart(BorderPart.HeaderTopLeft), borderStyle)); - foreach (var (columnIndex, _, lastColumn, columnWidth) in columnWidths.Enumerate()) - { - var padding = _columns[columnIndex].Padding; - - result.Add(new Segment(border.GetPart(BorderPart.HeaderTop, padding.Left), borderStyle)); // Left padding - result.Add(new Segment(border.GetPart(BorderPart.HeaderTop, columnWidth), borderStyle)); - result.Add(new Segment(border.GetPart(BorderPart.HeaderTop, padding.Right), borderStyle)); // Right padding - - if (!lastColumn) - { - result.Add(new Segment(border.GetPart(BorderPart.HeaderTopSeparator), borderStyle)); - } - } - - result.Add(new Segment(border.GetPart(BorderPart.HeaderTopRight), borderStyle)); + var separator = border.GetColumnRow(TablePart.Top, columnWidths, _columns); + result.Add(new Segment(separator, borderStyle)); result.Add(Segment.LineBreak); } @@ -232,7 +218,7 @@ namespace Spectre.Console if (firstCell && showBorder) { // Show left column edge - var part = firstRow && ShowHeaders ? BorderPart.HeaderLeft : BorderPart.CellLeft; + var part = firstRow && ShowHeaders ? TableBorderPart.HeaderLeft : TableBorderPart.CellLeft; result.Add(new Segment(border.GetPart(part), borderStyle)); } @@ -269,13 +255,13 @@ namespace Spectre.Console if (lastCell && showBorder) { // Add right column edge - var part = firstRow && ShowHeaders ? BorderPart.HeaderRight : BorderPart.CellRight; + var part = firstRow && ShowHeaders ? TableBorderPart.HeaderRight : TableBorderPart.CellRight; result.Add(new Segment(border.GetPart(part), borderStyle)); } else if (showBorder) { // Add column separator - var part = firstRow && ShowHeaders ? BorderPart.HeaderSeparator : BorderPart.CellSeparator; + var part = firstRow && ShowHeaders ? TableBorderPart.HeaderSeparator : TableBorderPart.CellSeparator; result.Add(new Segment(border.GetPart(part), borderStyle)); } } @@ -286,44 +272,16 @@ namespace Spectre.Console // Show header separator? if (firstRow && showBorder && ShowHeaders && hasRows) { - result.Add(new Segment(border.GetPart(BorderPart.HeaderBottomLeft), borderStyle)); - foreach (var (columnIndex, first, lastColumn, columnWidth) in columnWidths.Enumerate()) - { - var padding = _columns[columnIndex].Padding; - - result.Add(new Segment(border.GetPart(BorderPart.HeaderBottom, padding.Left), borderStyle)); // Left padding - result.Add(new Segment(border.GetPart(BorderPart.HeaderBottom, columnWidth), borderStyle)); - result.Add(new Segment(border.GetPart(BorderPart.HeaderBottom, padding.Right), borderStyle)); // Right padding - - if (!lastColumn) - { - result.Add(new Segment(border.GetPart(BorderPart.HeaderBottomSeparator), borderStyle)); - } - } - - result.Add(new Segment(border.GetPart(BorderPart.HeaderBottomRight), borderStyle)); + var separator = border.GetColumnRow(TablePart.Separator, columnWidths, _columns); + result.Add(new Segment(separator, borderStyle)); result.Add(Segment.LineBreak); } // Show bottom of footer? if (lastRow && showBorder) { - result.Add(new Segment(border.GetPart(BorderPart.FooterBottomLeft), borderStyle)); - foreach (var (columnIndex, first, lastColumn, columnWidth) in columnWidths.Enumerate()) - { - var padding = _columns[columnIndex].Padding; - - result.Add(new Segment(border.GetPart(BorderPart.FooterBottom, padding.Left), borderStyle)); // Left padding - result.Add(new Segment(border.GetPart(BorderPart.FooterBottom, columnWidth), borderStyle)); - result.Add(new Segment(border.GetPart(BorderPart.FooterBottom, padding.Right), borderStyle)); // Right padding - - if (!lastColumn) - { - result.Add(new Segment(border.GetPart(BorderPart.FooterBottomSeparator), borderStyle)); - } - } - - result.Add(new Segment(border.GetPart(BorderPart.FooterBottomRight), borderStyle)); + var separator = border.GetColumnRow(TablePart.Bottom, columnWidths, _columns); + result.Add(new Segment(separator, borderStyle)); result.Add(Segment.LineBreak); } }