mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 08:52:50 +08:00
Add option to show separator between table rows (#1304)
* Add option to show separator between table rows * Panels should show header if borders are not shown Closes #835
This commit is contained in:
parent
037e109699
commit
c82d8c4523
@ -20,21 +20,22 @@ public static class Program
|
|||||||
{
|
{
|
||||||
static IRenderable CreatePanel(string name, BoxBorder border)
|
static IRenderable CreatePanel(string name, BoxBorder border)
|
||||||
{
|
{
|
||||||
return new Panel($"This is a panel with\nthe [yellow]{name}[/] border.")
|
return
|
||||||
.Header($" [blue]{name}[/] ", Justify.Center)
|
new Panel($"This is a panel with\nthe [yellow]{name}[/] border.")
|
||||||
.Border(border)
|
.Header($" [blue]{name}[/] ", Justify.Center)
|
||||||
.BorderStyle(Style.Parse("grey"));
|
.Border(border)
|
||||||
|
.BorderStyle(Style.Parse("grey"));
|
||||||
}
|
}
|
||||||
|
|
||||||
var items = new[]
|
var items = new[]
|
||||||
{
|
{
|
||||||
CreatePanel("Ascii", BoxBorder.Ascii),
|
CreatePanel("Ascii", BoxBorder.Ascii),
|
||||||
CreatePanel("Square", BoxBorder.Square),
|
CreatePanel("Square", BoxBorder.Square),
|
||||||
CreatePanel("Rounded", BoxBorder.Rounded),
|
CreatePanel("Rounded", BoxBorder.Rounded),
|
||||||
CreatePanel("Heavy", BoxBorder.Heavy),
|
CreatePanel("Heavy", BoxBorder.Heavy),
|
||||||
CreatePanel("Double", BoxBorder.Double),
|
CreatePanel("Double", BoxBorder.Double),
|
||||||
CreatePanel("None", BoxBorder.None),
|
CreatePanel("None", BoxBorder.None),
|
||||||
};
|
};
|
||||||
|
|
||||||
AnsiConsole.Write(
|
AnsiConsole.Write(
|
||||||
new Padder(
|
new Padder(
|
||||||
@ -47,6 +48,7 @@ public static class Program
|
|||||||
static IRenderable CreateTable(string name, TableBorder border)
|
static IRenderable CreateTable(string name, TableBorder border)
|
||||||
{
|
{
|
||||||
var table = new Table().Border(border);
|
var table = new Table().Border(border);
|
||||||
|
table.ShowRowSeparators();
|
||||||
table.AddColumn("[yellow]Header 1[/]", c => c.Footer("[grey]Footer 1[/]"));
|
table.AddColumn("[yellow]Header 1[/]", c => c.Footer("[grey]Footer 1[/]"));
|
||||||
table.AddColumn("[yellow]Header 2[/]", col => col.Footer("[grey]Footer 2[/]").RightAligned());
|
table.AddColumn("[yellow]Header 2[/]", col => col.Footer("[grey]Footer 2[/]").RightAligned());
|
||||||
table.AddRow("Cell", "Cell");
|
table.AddRow("Cell", "Cell");
|
||||||
@ -54,29 +56,23 @@ public static class Program
|
|||||||
|
|
||||||
return new Panel(table)
|
return new Panel(table)
|
||||||
.Header($" [blue]{name}[/] ", Justify.Center)
|
.Header($" [blue]{name}[/] ", Justify.Center)
|
||||||
|
.PadBottom(1)
|
||||||
.NoBorder();
|
.NoBorder();
|
||||||
}
|
}
|
||||||
|
|
||||||
var items = new[]
|
var items = new[]
|
||||||
{
|
{
|
||||||
CreateTable("Ascii", TableBorder.Ascii),
|
CreateTable("Ascii", TableBorder.Ascii), CreateTable("Ascii2", TableBorder.Ascii2),
|
||||||
CreateTable("Ascii2", TableBorder.Ascii2),
|
CreateTable("AsciiDoubleHead", TableBorder.AsciiDoubleHead),
|
||||||
CreateTable("AsciiDoubleHead", TableBorder.AsciiDoubleHead),
|
CreateTable("Horizontal", TableBorder.Horizontal), CreateTable("Simple", TableBorder.Simple),
|
||||||
CreateTable("Horizontal", TableBorder.Horizontal),
|
CreateTable("SimpleHeavy", TableBorder.SimpleHeavy), CreateTable("Minimal", TableBorder.Minimal),
|
||||||
CreateTable("Simple", TableBorder.Simple),
|
CreateTable("MinimalHeavyHead", TableBorder.MinimalHeavyHead),
|
||||||
CreateTable("SimpleHeavy", TableBorder.SimpleHeavy),
|
CreateTable("MinimalDoubleHead", TableBorder.MinimalDoubleHead),
|
||||||
CreateTable("Minimal", TableBorder.Minimal),
|
CreateTable("Square", TableBorder.Square), CreateTable("Rounded", TableBorder.Rounded),
|
||||||
CreateTable("MinimalHeavyHead", TableBorder.MinimalHeavyHead),
|
CreateTable("Heavy", TableBorder.Heavy), CreateTable("HeavyEdge", TableBorder.HeavyEdge),
|
||||||
CreateTable("MinimalDoubleHead", TableBorder.MinimalDoubleHead),
|
CreateTable("HeavyHead", TableBorder.HeavyHead), CreateTable("Double", TableBorder.Double),
|
||||||
CreateTable("Square", TableBorder.Square),
|
CreateTable("DoubleEdge", TableBorder.DoubleEdge), CreateTable("Markdown", TableBorder.Markdown),
|
||||||
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.Write(new Columns(items).Collapse());
|
AnsiConsole.Write(new Columns(items).Collapse());
|
||||||
}
|
}
|
||||||
|
@ -334,6 +334,38 @@ public static class TableExtensions
|
|||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows row separators.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The table.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static Table ShowRowSeparators(this Table table)
|
||||||
|
{
|
||||||
|
if (table is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(table));
|
||||||
|
}
|
||||||
|
|
||||||
|
table.ShowRowSeparators = true;
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hides row separators.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The table.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static Table HideRowSeparators(this Table table)
|
||||||
|
{
|
||||||
|
if (table is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(table));
|
||||||
|
}
|
||||||
|
|
||||||
|
table.ShowRowSeparators = false;
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shows table footers.
|
/// Shows table footers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -114,4 +114,24 @@ public enum TableBorderPart
|
|||||||
/// The bottom right part of a footer.
|
/// The bottom right part of a footer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FooterBottomRight,
|
FooterBottomRight,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The left part of a row.
|
||||||
|
/// </summary>
|
||||||
|
RowLeft,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The center part of a row.
|
||||||
|
/// </summary>
|
||||||
|
RowCenter,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The separator part of a row.
|
||||||
|
/// </summary>
|
||||||
|
RowSeparator,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The right part of a row.
|
||||||
|
/// </summary>
|
||||||
|
RowRight,
|
||||||
}
|
}
|
@ -32,6 +32,10 @@ public sealed class Ascii2TableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => "-",
|
TableBorderPart.FooterBottom => "-",
|
||||||
TableBorderPart.FooterBottomSeparator => "+",
|
TableBorderPart.FooterBottomSeparator => "+",
|
||||||
TableBorderPart.FooterBottomRight => "+",
|
TableBorderPart.FooterBottomRight => "+",
|
||||||
|
TableBorderPart.RowLeft => "|",
|
||||||
|
TableBorderPart.RowCenter => "-",
|
||||||
|
TableBorderPart.RowSeparator => "+",
|
||||||
|
TableBorderPart.RowRight => "|",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,10 @@ public sealed class AsciiDoubleHeadTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => "-",
|
TableBorderPart.FooterBottom => "-",
|
||||||
TableBorderPart.FooterBottomSeparator => "+",
|
TableBorderPart.FooterBottomSeparator => "+",
|
||||||
TableBorderPart.FooterBottomRight => "+",
|
TableBorderPart.FooterBottomRight => "+",
|
||||||
|
TableBorderPart.RowLeft => "|",
|
||||||
|
TableBorderPart.RowCenter => "-",
|
||||||
|
TableBorderPart.RowSeparator => "+",
|
||||||
|
TableBorderPart.RowRight => "|",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,10 @@ public sealed class AsciiTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => "-",
|
TableBorderPart.FooterBottom => "-",
|
||||||
TableBorderPart.FooterBottomSeparator => "-",
|
TableBorderPart.FooterBottomSeparator => "-",
|
||||||
TableBorderPart.FooterBottomRight => "+",
|
TableBorderPart.FooterBottomRight => "+",
|
||||||
|
TableBorderPart.RowLeft => "|",
|
||||||
|
TableBorderPart.RowCenter => "-",
|
||||||
|
TableBorderPart.RowSeparator => "+",
|
||||||
|
TableBorderPart.RowRight => "|",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,10 @@ public sealed class DoubleEdgeTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => "═",
|
TableBorderPart.FooterBottom => "═",
|
||||||
TableBorderPart.FooterBottomSeparator => "╧",
|
TableBorderPart.FooterBottomSeparator => "╧",
|
||||||
TableBorderPart.FooterBottomRight => "╝",
|
TableBorderPart.FooterBottomRight => "╝",
|
||||||
|
TableBorderPart.RowLeft => "╟",
|
||||||
|
TableBorderPart.RowCenter => "─",
|
||||||
|
TableBorderPart.RowSeparator => "┼",
|
||||||
|
TableBorderPart.RowRight => "╢",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,10 @@ public sealed class DoubleTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => "═",
|
TableBorderPart.FooterBottom => "═",
|
||||||
TableBorderPart.FooterBottomSeparator => "╩",
|
TableBorderPart.FooterBottomSeparator => "╩",
|
||||||
TableBorderPart.FooterBottomRight => "╝",
|
TableBorderPart.FooterBottomRight => "╝",
|
||||||
|
TableBorderPart.RowLeft => "╠",
|
||||||
|
TableBorderPart.RowCenter => "═",
|
||||||
|
TableBorderPart.RowSeparator => "╬",
|
||||||
|
TableBorderPart.RowRight => "╣",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,10 @@ public sealed class HeavyEdgeTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => "━",
|
TableBorderPart.FooterBottom => "━",
|
||||||
TableBorderPart.FooterBottomSeparator => "┷",
|
TableBorderPart.FooterBottomSeparator => "┷",
|
||||||
TableBorderPart.FooterBottomRight => "┛",
|
TableBorderPart.FooterBottomRight => "┛",
|
||||||
|
TableBorderPart.RowLeft => "┠",
|
||||||
|
TableBorderPart.RowCenter => "─",
|
||||||
|
TableBorderPart.RowSeparator => "┼",
|
||||||
|
TableBorderPart.RowRight => "┨",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,10 @@ public sealed class HeavyHeadTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => "─",
|
TableBorderPart.FooterBottom => "─",
|
||||||
TableBorderPart.FooterBottomSeparator => "┴",
|
TableBorderPart.FooterBottomSeparator => "┴",
|
||||||
TableBorderPart.FooterBottomRight => "┘",
|
TableBorderPart.FooterBottomRight => "┘",
|
||||||
|
TableBorderPart.RowLeft => "├",
|
||||||
|
TableBorderPart.RowCenter => "─",
|
||||||
|
TableBorderPart.RowSeparator => "┼",
|
||||||
|
TableBorderPart.RowRight => "┤",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,10 @@ public sealed class HeavyTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => "━",
|
TableBorderPart.FooterBottom => "━",
|
||||||
TableBorderPart.FooterBottomSeparator => "┻",
|
TableBorderPart.FooterBottomSeparator => "┻",
|
||||||
TableBorderPart.FooterBottomRight => "┛",
|
TableBorderPart.FooterBottomRight => "┛",
|
||||||
|
TableBorderPart.RowLeft => "┣",
|
||||||
|
TableBorderPart.RowCenter => "━",
|
||||||
|
TableBorderPart.RowSeparator => "╋",
|
||||||
|
TableBorderPart.RowRight => "┫",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,10 @@ public sealed class HorizontalTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => "─",
|
TableBorderPart.FooterBottom => "─",
|
||||||
TableBorderPart.FooterBottomSeparator => "─",
|
TableBorderPart.FooterBottomSeparator => "─",
|
||||||
TableBorderPart.FooterBottomRight => "─",
|
TableBorderPart.FooterBottomRight => "─",
|
||||||
|
TableBorderPart.RowLeft => "─",
|
||||||
|
TableBorderPart.RowCenter => "─",
|
||||||
|
TableBorderPart.RowSeparator => "─",
|
||||||
|
TableBorderPart.RowRight => "─",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,9 @@ namespace Spectre.Console.Rendering;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class MarkdownTableBorder : TableBorder
|
public sealed class MarkdownTableBorder : TableBorder
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool SupportsRowSeparator => false;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override string GetPart(TableBorderPart part)
|
public override string GetPart(TableBorderPart part)
|
||||||
{
|
{
|
||||||
@ -32,6 +35,10 @@ public sealed class MarkdownTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => " ",
|
TableBorderPart.FooterBottom => " ",
|
||||||
TableBorderPart.FooterBottomSeparator => " ",
|
TableBorderPart.FooterBottomSeparator => " ",
|
||||||
TableBorderPart.FooterBottomRight => " ",
|
TableBorderPart.FooterBottomRight => " ",
|
||||||
|
TableBorderPart.RowLeft => " ",
|
||||||
|
TableBorderPart.RowCenter => " ",
|
||||||
|
TableBorderPart.RowSeparator => " ",
|
||||||
|
TableBorderPart.RowRight => " ",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,10 @@ public sealed class MinimalDoubleHeadTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => " ",
|
TableBorderPart.FooterBottom => " ",
|
||||||
TableBorderPart.FooterBottomSeparator => " ",
|
TableBorderPart.FooterBottomSeparator => " ",
|
||||||
TableBorderPart.FooterBottomRight => " ",
|
TableBorderPart.FooterBottomRight => " ",
|
||||||
|
TableBorderPart.RowLeft => " ",
|
||||||
|
TableBorderPart.RowCenter => "─",
|
||||||
|
TableBorderPart.RowSeparator => "┼",
|
||||||
|
TableBorderPart.RowRight => " ",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,10 @@ public sealed class MinimalHeavyHeadTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => " ",
|
TableBorderPart.FooterBottom => " ",
|
||||||
TableBorderPart.FooterBottomSeparator => " ",
|
TableBorderPart.FooterBottomSeparator => " ",
|
||||||
TableBorderPart.FooterBottomRight => " ",
|
TableBorderPart.FooterBottomRight => " ",
|
||||||
|
TableBorderPart.RowLeft => " ",
|
||||||
|
TableBorderPart.RowCenter => "─",
|
||||||
|
TableBorderPart.RowSeparator => "┼",
|
||||||
|
TableBorderPart.RowRight => " ",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,10 @@ public sealed class MinimalTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => " ",
|
TableBorderPart.FooterBottom => " ",
|
||||||
TableBorderPart.FooterBottomSeparator => " ",
|
TableBorderPart.FooterBottomSeparator => " ",
|
||||||
TableBorderPart.FooterBottomRight => " ",
|
TableBorderPart.FooterBottomRight => " ",
|
||||||
|
TableBorderPart.RowLeft => " ",
|
||||||
|
TableBorderPart.RowCenter => "─",
|
||||||
|
TableBorderPart.RowSeparator => "┼",
|
||||||
|
TableBorderPart.RowRight => " ",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,9 @@ public sealed class NoTableBorder : TableBorder
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override bool Visible => false;
|
public override bool Visible => false;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool SupportsRowSeparator => false;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override string GetPart(TableBorderPart part)
|
public override string GetPart(TableBorderPart part)
|
||||||
{
|
{
|
||||||
|
@ -35,6 +35,10 @@ public sealed class RoundedTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => "─",
|
TableBorderPart.FooterBottom => "─",
|
||||||
TableBorderPart.FooterBottomSeparator => "┴",
|
TableBorderPart.FooterBottomSeparator => "┴",
|
||||||
TableBorderPart.FooterBottomRight => "╯",
|
TableBorderPart.FooterBottomRight => "╯",
|
||||||
|
TableBorderPart.RowLeft => "├",
|
||||||
|
TableBorderPart.RowCenter => "─",
|
||||||
|
TableBorderPart.RowSeparator => "┼",
|
||||||
|
TableBorderPart.RowRight => "┤",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,10 @@ public sealed class SimpleHeavyTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => " ",
|
TableBorderPart.FooterBottom => " ",
|
||||||
TableBorderPart.FooterBottomSeparator => " ",
|
TableBorderPart.FooterBottomSeparator => " ",
|
||||||
TableBorderPart.FooterBottomRight => " ",
|
TableBorderPart.FooterBottomRight => " ",
|
||||||
|
TableBorderPart.RowLeft => "─",
|
||||||
|
TableBorderPart.RowCenter => "─",
|
||||||
|
TableBorderPart.RowSeparator => "─",
|
||||||
|
TableBorderPart.RowRight => "─",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,10 @@ public sealed class SimpleTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => " ",
|
TableBorderPart.FooterBottom => " ",
|
||||||
TableBorderPart.FooterBottomSeparator => " ",
|
TableBorderPart.FooterBottomSeparator => " ",
|
||||||
TableBorderPart.FooterBottomRight => " ",
|
TableBorderPart.FooterBottomRight => " ",
|
||||||
|
TableBorderPart.RowLeft => "─",
|
||||||
|
TableBorderPart.RowCenter => "─",
|
||||||
|
TableBorderPart.RowSeparator => "─",
|
||||||
|
TableBorderPart.RowRight => "─",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,10 @@ public sealed class SquareTableBorder : TableBorder
|
|||||||
TableBorderPart.FooterBottom => "─",
|
TableBorderPart.FooterBottom => "─",
|
||||||
TableBorderPart.FooterBottomSeparator => "┴",
|
TableBorderPart.FooterBottomSeparator => "┴",
|
||||||
TableBorderPart.FooterBottomRight => "┘",
|
TableBorderPart.FooterBottomRight => "┘",
|
||||||
|
TableBorderPart.RowLeft => "├",
|
||||||
|
TableBorderPart.RowCenter => "─",
|
||||||
|
TableBorderPart.RowSeparator => "┼",
|
||||||
|
TableBorderPart.RowRight => "┤",
|
||||||
_ => throw new InvalidOperationException("Unknown border part."),
|
_ => throw new InvalidOperationException("Unknown border part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,11 @@ public enum TablePart
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
HeaderSeparator,
|
HeaderSeparator,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The separator between the rows.
|
||||||
|
/// </summary>
|
||||||
|
RowSeparator,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The separator between the footer and the cells.
|
/// The separator between the footer and the cells.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -36,9 +36,6 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Widgets\Json\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<DefineConstants>$(DefineConstants)TRACE;WCWIDTH_VISIBILITY_INTERNAL</DefineConstants>
|
<DefineConstants>$(DefineConstants)TRACE;WCWIDTH_VISIBILITY_INTERNAL</DefineConstants>
|
||||||
|
@ -13,7 +13,12 @@ public abstract partial class TableBorder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the safe border for this border or <c>null</c> if none exist.
|
/// Gets the safe border for this border or <c>null</c> if none exist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual TableBorder? SafeBorder { get; }
|
public virtual TableBorder? SafeBorder { get; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the border supports row separators or not.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool SupportsRowSeparator { get; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the string representation of a specified table border part.
|
/// Gets the string representation of a specified table border part.
|
||||||
@ -81,6 +86,11 @@ public abstract partial class TableBorder
|
|||||||
(GetPart(TableBorderPart.HeaderBottomLeft), GetPart(TableBorderPart.HeaderBottom),
|
(GetPart(TableBorderPart.HeaderBottomLeft), GetPart(TableBorderPart.HeaderBottom),
|
||||||
GetPart(TableBorderPart.HeaderBottomSeparator), GetPart(TableBorderPart.HeaderBottomRight)),
|
GetPart(TableBorderPart.HeaderBottomSeparator), GetPart(TableBorderPart.HeaderBottomRight)),
|
||||||
|
|
||||||
|
// Separator between header and cells
|
||||||
|
TablePart.RowSeparator =>
|
||||||
|
(GetPart(TableBorderPart.RowLeft), GetPart(TableBorderPart.RowCenter),
|
||||||
|
GetPart(TableBorderPart.RowSeparator), GetPart(TableBorderPart.RowRight)),
|
||||||
|
|
||||||
// Separator between footer and cells
|
// Separator between footer and cells
|
||||||
TablePart.FooterSeparator =>
|
TablePart.FooterSeparator =>
|
||||||
(GetPart(TableBorderPart.FooterTopLeft), GetPart(TableBorderPart.FooterTop),
|
(GetPart(TableBorderPart.FooterTopLeft), GetPart(TableBorderPart.FooterTop),
|
||||||
|
@ -132,6 +132,15 @@ public sealed class Panel : Renderable, IHasBoxBorder, IHasBorder, IExpandable,
|
|||||||
{
|
{
|
||||||
AddTopBorder(result, options, border, borderStyle, panelWidth);
|
AddTopBorder(result, options, border, borderStyle, panelWidth);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not showing border, but we have a header text?
|
||||||
|
// Use a invisible border to draw the top border
|
||||||
|
if (Header?.Text != null)
|
||||||
|
{
|
||||||
|
AddTopBorder(result, options, BoxBorder.None, borderStyle, panelWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Split the child segments into lines.
|
// Split the child segments into lines.
|
||||||
var childSegments = ((IRenderable)child).Render(options with { Height = height }, innerWidth);
|
var childSegments = ((IRenderable)child).Render(options with { Height = height }, innerWidth);
|
||||||
|
@ -31,6 +31,11 @@ public sealed class Table : Renderable, IHasTableBorder, IExpandable, IAlignable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ShowHeaders { get; set; } = true;
|
public bool ShowHeaders { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether or not row separators should be shown.
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowRowSeparators { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether or not table footers should be shown.
|
/// Gets or sets a value indicating whether or not table footers should be shown.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -36,7 +36,9 @@ internal static class TableRenderer
|
|||||||
// Show top of header?
|
// Show top of header?
|
||||||
if (isFirstRow && context.ShowBorder)
|
if (isFirstRow && context.ShowBorder)
|
||||||
{
|
{
|
||||||
var separator = Aligner.Align(context.Border.GetColumnRow(TablePart.Top, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
|
var separator = Aligner.Align(
|
||||||
|
context.Border.GetColumnRow(TablePart.Top, columnWidths, context.Columns),
|
||||||
|
context.Alignment, context.MaxWidth);
|
||||||
result.Add(new Segment(separator, context.BorderStyle));
|
result.Add(new Segment(separator, context.BorderStyle));
|
||||||
result.Add(Segment.LineBreak);
|
result.Add(Segment.LineBreak);
|
||||||
}
|
}
|
||||||
@ -66,7 +68,9 @@ internal static class TableRenderer
|
|||||||
if (isFirstCell && context.ShowBorder)
|
if (isFirstCell && context.ShowBorder)
|
||||||
{
|
{
|
||||||
// Show left column edge
|
// Show left column edge
|
||||||
var part = isFirstRow && context.ShowHeaders ? TableBorderPart.HeaderLeft : TableBorderPart.CellLeft;
|
var part = isFirstRow && context.ShowHeaders
|
||||||
|
? TableBorderPart.HeaderLeft
|
||||||
|
: TableBorderPart.CellLeft;
|
||||||
rowResult.Add(new Segment(context.Border.GetPart(part), context.BorderStyle));
|
rowResult.Add(new Segment(context.Border.GetPart(part), context.BorderStyle));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +95,8 @@ internal static class TableRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pad column on the right side
|
// Pad column on the right side
|
||||||
if (context.ShowBorder || (context.HideBorder && !isLastCell) || (context.HideBorder && isLastCell && context.IsGrid && context.PadRightCell))
|
if (context.ShowBorder || (context.HideBorder && !isLastCell) ||
|
||||||
|
(context.HideBorder && isLastCell && context.IsGrid && context.PadRightCell))
|
||||||
{
|
{
|
||||||
var rightPadding = context.Columns[cellIndex].Padding.GetRightSafe();
|
var rightPadding = context.Columns[cellIndex].Padding.GetRightSafe();
|
||||||
if (rightPadding > 0)
|
if (rightPadding > 0)
|
||||||
@ -103,13 +108,17 @@ internal static class TableRenderer
|
|||||||
if (isLastCell && context.ShowBorder)
|
if (isLastCell && context.ShowBorder)
|
||||||
{
|
{
|
||||||
// Add right column edge
|
// Add right column edge
|
||||||
var part = isFirstRow && context.ShowHeaders ? TableBorderPart.HeaderRight : TableBorderPart.CellRight;
|
var part = isFirstRow && context.ShowHeaders
|
||||||
|
? TableBorderPart.HeaderRight
|
||||||
|
: TableBorderPart.CellRight;
|
||||||
rowResult.Add(new Segment(context.Border.GetPart(part), context.BorderStyle));
|
rowResult.Add(new Segment(context.Border.GetPart(part), context.BorderStyle));
|
||||||
}
|
}
|
||||||
else if (context.ShowBorder)
|
else if (context.ShowBorder)
|
||||||
{
|
{
|
||||||
// Add column separator
|
// Add column separator
|
||||||
var part = isFirstRow && context.ShowHeaders ? TableBorderPart.HeaderSeparator : TableBorderPart.CellSeparator;
|
var part = isFirstRow && context.ShowHeaders
|
||||||
|
? TableBorderPart.HeaderSeparator
|
||||||
|
: TableBorderPart.CellSeparator;
|
||||||
rowResult.Add(new Segment(context.Border.GetPart(part), context.BorderStyle));
|
rowResult.Add(new Segment(context.Border.GetPart(part), context.BorderStyle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,15 +142,40 @@ internal static class TableRenderer
|
|||||||
// Show header separator?
|
// Show header separator?
|
||||||
if (isFirstRow && context.ShowBorder && context.ShowHeaders && context.HasRows)
|
if (isFirstRow && context.ShowBorder && context.ShowHeaders && context.HasRows)
|
||||||
{
|
{
|
||||||
var separator = Aligner.Align(context.Border.GetColumnRow(TablePart.HeaderSeparator, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
|
var separator =
|
||||||
|
Aligner.Align(
|
||||||
|
context.Border.GetColumnRow(TablePart.HeaderSeparator, columnWidths, context.Columns),
|
||||||
|
context.Alignment, context.MaxWidth);
|
||||||
result.Add(new Segment(separator, context.BorderStyle));
|
result.Add(new Segment(separator, context.BorderStyle));
|
||||||
result.Add(Segment.LineBreak);
|
result.Add(Segment.LineBreak);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show row separator?
|
||||||
|
if (context.Border.SupportsRowSeparator && context.ShowRowSeparators
|
||||||
|
&& !isFirstRow && !isLastRow)
|
||||||
|
{
|
||||||
|
var hasVisibleFootes = context is { ShowFooters: true, HasFooters: true };
|
||||||
|
var isNextLastLine = index == context.Rows.Count - 2;
|
||||||
|
|
||||||
|
var isRenderingFooter = hasVisibleFootes && isNextLastLine;
|
||||||
|
if (!isRenderingFooter)
|
||||||
|
{
|
||||||
|
var separator =
|
||||||
|
Aligner.Align(
|
||||||
|
context.Border.GetColumnRow(TablePart.RowSeparator, columnWidths, context.Columns),
|
||||||
|
context.Alignment, context.MaxWidth);
|
||||||
|
result.Add(new Segment(separator, context.BorderStyle));
|
||||||
|
result.Add(Segment.LineBreak);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Show bottom of footer?
|
// Show bottom of footer?
|
||||||
if (isLastRow && context.ShowBorder)
|
if (isLastRow && context.ShowBorder)
|
||||||
{
|
{
|
||||||
var separator = Aligner.Align(context.Border.GetColumnRow(TablePart.Bottom, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
|
var separator =
|
||||||
|
Aligner.Align(
|
||||||
|
context.Border.GetColumnRow(TablePart.Bottom, columnWidths, context.Columns),
|
||||||
|
context.Alignment, context.MaxWidth);
|
||||||
result.Add(new Segment(separator, context.BorderStyle));
|
result.Add(new Segment(separator, context.BorderStyle));
|
||||||
result.Add(Segment.LineBreak);
|
result.Add(Segment.LineBreak);
|
||||||
}
|
}
|
||||||
@ -151,7 +185,8 @@ internal static class TableRenderer
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<Segment> RenderAnnotation(TableRendererContext context, TableTitle? header, Style defaultStyle)
|
private static IEnumerable<Segment> RenderAnnotation(TableRendererContext context, TableTitle? header,
|
||||||
|
Style defaultStyle)
|
||||||
{
|
{
|
||||||
if (header == null)
|
if (header == null)
|
||||||
{
|
{
|
||||||
|
@ -10,6 +10,7 @@ internal sealed class TableRendererContext : TableAccessor
|
|||||||
public TableBorder Border { get; }
|
public TableBorder Border { get; }
|
||||||
public Style BorderStyle { get; }
|
public Style BorderStyle { get; }
|
||||||
public bool ShowBorder { get; }
|
public bool ShowBorder { get; }
|
||||||
|
public bool ShowRowSeparators { get; }
|
||||||
public bool HasRows { get; }
|
public bool HasRows { get; }
|
||||||
public bool HasFooters { get; }
|
public bool HasFooters { get; }
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ internal sealed class TableRendererContext : TableAccessor
|
|||||||
HasFooters = Rows.Any(column => column.IsFooter);
|
HasFooters = Rows.Any(column => column.IsFooter);
|
||||||
Border = table.Border.GetSafeBorder(!options.Unicode && table.UseSafeBorder);
|
Border = table.Border.GetSafeBorder(!options.Unicode && table.UseSafeBorder);
|
||||||
BorderStyle = table.BorderStyle ?? Style.Plain;
|
BorderStyle = table.BorderStyle ?? Style.Plain;
|
||||||
|
ShowRowSeparators = table.ShowRowSeparators;
|
||||||
|
|
||||||
TableWidth = tableWidth;
|
TableWidth = tableWidth;
|
||||||
MaxWidth = maxWidth;
|
MaxWidth = maxWidth;
|
||||||
|
@ -1 +1 @@
|
|||||||
Hello World
|
Hello World
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
Greeting
|
||||||
|
Hello World
|
@ -0,0 +1,7 @@
|
|||||||
|
┌────────┬────────┬───────┐
|
||||||
|
│ Foo │ Bar │ Baz │
|
||||||
|
├────────┼────────┼───────┤
|
||||||
|
│ Qux │ Corgi │ Waldo │
|
||||||
|
├────────┼────────┼───────┤
|
||||||
|
│ Grault │ Garply │ Fred │
|
||||||
|
└────────┴────────┴───────┘
|
@ -23,6 +23,22 @@ public sealed class BoxBorderTests
|
|||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("NoBorder")]
|
[Expectation("NoBorder")]
|
||||||
public Task Should_Render_As_Expected()
|
public Task Should_Render_As_Expected()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var console = new TestConsole();
|
||||||
|
var panel = Fixture.GetPanel().NoBorder();
|
||||||
|
panel.Header = null;
|
||||||
|
|
||||||
|
// When
|
||||||
|
console.Write(panel);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
return Verifier.Verify(console.Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Expectation("NoBorder_With_Header")]
|
||||||
|
public Task Should_Render_NoBorder_With_Header_As_Expected()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var console = new TestConsole();
|
var console = new TestConsole();
|
||||||
|
@ -142,6 +142,25 @@ public sealed class TableTests
|
|||||||
return Verifier.Verify(console.Output);
|
return Verifier.Verify(console.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Expectation("Render_Row_Separators")]
|
||||||
|
public Task Should_Render_Table_With_Row_Separators_Correctly()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var console = new TestConsole();
|
||||||
|
var table = new Table();
|
||||||
|
table.ShowRowSeparators();
|
||||||
|
table.AddColumns("Foo", "Bar", "Baz");
|
||||||
|
table.AddRow("Qux", "Corgi", "Waldo");
|
||||||
|
table.AddRow("Grault", "Garply", "Fred");
|
||||||
|
|
||||||
|
// When
|
||||||
|
console.Write(table);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
return Verifier.Verify(console.Output);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Expectation("Render_EA_Character")]
|
[Expectation("Render_EA_Character")]
|
||||||
public Task Should_Render_Table_With_EA_Character_Correctly()
|
public Task Should_Render_Table_With_EA_Character_Correctly()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user