mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 17:02:51 +08:00
Do not draw tables that can't be drawn
This is a temporary fix for undrawable tables until we've implemented a proper strategy. What this does is that it replaces an undrawable table with an ellipsis (...). This should only occur in either super big tables or deeply nested tables in a console with a small buffer width.
This commit is contained in:
parent
a2f507e58f
commit
bfffef630f
@ -19,7 +19,7 @@ namespace TableExample
|
|||||||
|
|
||||||
private static void RenderSimpleTable()
|
private static void RenderSimpleTable()
|
||||||
{
|
{
|
||||||
// Create the table.
|
// Create the table
|
||||||
var table = new Table();
|
var table = new Table();
|
||||||
table.AddColumn(new TableColumn("[u]Foo[/]"));
|
table.AddColumn(new TableColumn("[u]Foo[/]"));
|
||||||
table.AddColumn(new TableColumn("[u]Bar[/]"));
|
table.AddColumn(new TableColumn("[u]Bar[/]"));
|
||||||
@ -35,7 +35,7 @@ namespace TableExample
|
|||||||
|
|
||||||
private static void RenderBigTable()
|
private static void RenderBigTable()
|
||||||
{
|
{
|
||||||
// Create the table.
|
// Create the table
|
||||||
var table = new Table().SetBorder(TableBorder.Rounded);
|
var table = new Table().SetBorder(TableBorder.Rounded);
|
||||||
table.AddColumn("[red underline]Foo[/]");
|
table.AddColumn("[red underline]Foo[/]");
|
||||||
table.AddColumn(new TableColumn("[blue]Bar[/]") { Alignment = Justify.Right, NoWrap = true });
|
table.AddColumn(new TableColumn("[blue]Bar[/]") { Alignment = Justify.Right, NoWrap = true });
|
||||||
@ -57,16 +57,16 @@ namespace TableExample
|
|||||||
|
|
||||||
private static void RenderNestedTable()
|
private static void RenderNestedTable()
|
||||||
{
|
{
|
||||||
// Create simple table.
|
// Create simple table
|
||||||
var simple = new Table().SetBorder(TableBorder.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]CDE[/]").Centered());
|
||||||
simple.AddColumn(new TableColumn("[u]Bar[/]"));
|
simple.AddColumn(new TableColumn("[u]FED[/]"));
|
||||||
simple.AddColumn(new TableColumn("[u]Baz[/]"));
|
simple.AddColumn(new TableColumn("[u]IHG[/]"));
|
||||||
simple.AddRow("Hello", "[red]World![/]", "");
|
simple.AddRow("Hello", "[red]World![/]", "");
|
||||||
simple.AddRow("[blue]Bonjour[/]", "[white]le[/]", "[red]monde![/]");
|
simple.AddRow("[blue]Bonjour[/]", "[white]le[/]", "[red]monde![/]");
|
||||||
simple.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
|
simple.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
|
||||||
|
|
||||||
// Create other table.
|
// Create other table
|
||||||
var second = new Table().SetBorder(TableBorder.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]Foo[/]"));
|
||||||
second.AddColumn(new TableColumn("[u]Bar[/]"));
|
second.AddColumn(new TableColumn("[u]Bar[/]"));
|
||||||
@ -75,12 +75,11 @@ namespace TableExample
|
|||||||
second.AddRow(simple, new Text("Whaaat"), new Text("Lolz"));
|
second.AddRow(simple, new Text("Whaaat"), new Text("Lolz"));
|
||||||
second.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
|
second.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
|
||||||
|
|
||||||
|
// Create the outer most table
|
||||||
var table = new Table().SetBorder(TableBorder.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]ABC[/]").SetBorderColor(Color.Red)));
|
||||||
table.AddColumn(new TableColumn(new Panel("[u]Bar[/]").SetBorderColor(Color.Green)));
|
table.AddColumn(new TableColumn(new Panel("[u]DEF[/]").SetBorderColor(Color.Green)));
|
||||||
table.AddColumn(new TableColumn(new Panel("[u]Baz[/]").SetBorderColor(Color.Blue)));
|
table.AddColumn(new TableColumn(new Panel("[u]GHI[/]").SetBorderColor(Color.Blue)));
|
||||||
|
|
||||||
// Add some rows
|
|
||||||
table.AddRow(new Text("Hello").Centered(), new Markup("[red]World![/]"), Text.Empty);
|
table.AddRow(new Text("Hello").Centered(), new Markup("[red]World![/]"), Text.Empty);
|
||||||
table.AddRow(second, new Text("Whaaat"), new Text("Lol"));
|
table.AddRow(second, new Text("Whaaat"), new Text("Lol"));
|
||||||
table.AddRow(new Markup("[blue]Hej[/]").Centered(), new Markup("[yellow]Världen![/]"), Text.Empty);
|
table.AddRow(new Markup("[blue]Hej[/]").Centered(), new Markup("[yellow]Världen![/]"), Text.Empty);
|
||||||
|
@ -383,5 +383,54 @@ namespace Spectre.Console.Tests.Unit
|
|||||||
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
|
console.Lines[1].ShouldBe("│ Foo │ Bar │ Baz │");
|
||||||
console.Lines[2].ShouldBe("└─────┴─────┴────────┘");
|
console.Lines[2].ShouldBe("└─────┴─────┴────────┘");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Should_Not_Draw_Tables_That_Are_Impossible_To_Draw()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var console = new PlainConsole(width: 25);
|
||||||
|
|
||||||
|
var first = new Table().SetBorder(TableBorder.Rounded).SetBorderColor(Color.Red);
|
||||||
|
first.AddColumn(new TableColumn("[u]PS1[/]").Centered());
|
||||||
|
first.AddColumn(new TableColumn("[u]PS2[/]"));
|
||||||
|
first.AddColumn(new TableColumn("[u]PS3[/]"));
|
||||||
|
first.AddRow("Hello", "[red]World[/]", string.Empty);
|
||||||
|
first.AddRow("[blue]Bonjour[/]", "[white]le[/]", "[red]monde![/]");
|
||||||
|
first.AddRow("[blue]Hej[/]", "[yellow]Världen[/]", string.Empty);
|
||||||
|
|
||||||
|
var second = new Table().SetBorder(TableBorder.Square).SetBorderColor(Color.Green);
|
||||||
|
second.AddColumn(new TableColumn("[u]Foo[/]"));
|
||||||
|
second.AddColumn(new TableColumn("[u]Bar[/]"));
|
||||||
|
second.AddColumn(new TableColumn("[u]Baz[/]"));
|
||||||
|
second.AddRow("Hello", "[red]World[/]", string.Empty);
|
||||||
|
second.AddRow(first, new Text("Whaaat"), new Text("Lolz"));
|
||||||
|
second.AddRow("[blue]Hej[/]", "[yellow]Världen[/]", string.Empty);
|
||||||
|
|
||||||
|
var table = new Table().SetBorder(TableBorder.Rounded);
|
||||||
|
table.AddColumn(new TableColumn(new Panel("[u]ABC[/]").SetBorderColor(Color.Red)));
|
||||||
|
table.AddColumn(new TableColumn(new Panel("[u]DEF[/]").SetBorderColor(Color.Green)));
|
||||||
|
table.AddColumn(new TableColumn(new Panel("[u]GHI[/]").SetBorderColor(Color.Blue)));
|
||||||
|
table.AddRow(new Text("Hello").Centered(), new Markup("[red]World[/]"), Text.Empty);
|
||||||
|
table.AddRow(second, new Text("Whaat"), new Text("Lol").RightAligned());
|
||||||
|
table.AddRow(new Markup("[blue]Hej[/]"), new Markup("[yellow]Världen[/]"), Text.Empty);
|
||||||
|
|
||||||
|
// When
|
||||||
|
console.Render(table);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
console.Lines.Count.ShouldBe(12);
|
||||||
|
console.Lines[00].ShouldBe("╭───────┬───────┬───────╮");
|
||||||
|
console.Lines[01].ShouldBe("│ ┌───┐ │ ┌───┐ │ ┌───┐ │");
|
||||||
|
console.Lines[02].ShouldBe("│ │ A │ │ │ D │ │ │ G │ │");
|
||||||
|
console.Lines[03].ShouldBe("│ │ B │ │ │ E │ │ │ H │ │");
|
||||||
|
console.Lines[04].ShouldBe("│ │ C │ │ │ F │ │ │ I │ │");
|
||||||
|
console.Lines[05].ShouldBe("│ └───┘ │ └───┘ │ └───┘ │");
|
||||||
|
console.Lines[06].ShouldBe("├───────┼───────┼───────┤");
|
||||||
|
console.Lines[07].ShouldBe("│ Hello │ World │ │");
|
||||||
|
console.Lines[08].ShouldBe("│ … │ Whaat │ Lol │");
|
||||||
|
console.Lines[09].ShouldBe("│ Hej │ Värld │ │");
|
||||||
|
console.Lines[10].ShouldBe("│ │ en │ │");
|
||||||
|
console.Lines[11].ShouldBe("╰───────┴───────┴───────╯");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,6 +119,54 @@ namespace Spectre.Console.Rendering
|
|||||||
new Segment(Text.Substring(offset, Text.Length - offset), Style));
|
new Segment(Text.Substring(offset, Text.Length - offset), Style));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of cells that the segments occupies in the console.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The render context.</param>
|
||||||
|
/// <param name="segments">The segments to measure.</param>
|
||||||
|
/// <returns>The number of cells that the segments occupies in the console.</returns>
|
||||||
|
public static int CellLength(RenderContext context, List<Segment> segments)
|
||||||
|
{
|
||||||
|
return segments.Sum(segment => segment.CellLength(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Truncates the segments to the specified width.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The render context.</param>
|
||||||
|
/// <param name="segments">The segments to truncate.</param>
|
||||||
|
/// <param name="maxWidth">The maximum width that the segments may occupy.</param>
|
||||||
|
/// <returns>A list of segments that has been truncated.</returns>
|
||||||
|
public static List<Segment> Truncate(RenderContext context, IEnumerable<Segment> segments, int maxWidth)
|
||||||
|
{
|
||||||
|
if (context is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (segments is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(segments));
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = new List<Segment>();
|
||||||
|
|
||||||
|
var totalWidth = 0;
|
||||||
|
foreach (var segment in segments)
|
||||||
|
{
|
||||||
|
var segmentWidth = segment.CellLength(context);
|
||||||
|
if (totalWidth + segmentWidth > maxWidth)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Add(segment);
|
||||||
|
totalWidth += segmentWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Splits the provided segments into lines.
|
/// Splits the provided segments into lines.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -314,13 +362,27 @@ namespace Spectre.Console.Rendering
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (overflow == Overflow.Crop)
|
else if (overflow == Overflow.Crop)
|
||||||
|
{
|
||||||
|
if (Math.Max(0, width - 1) == 0)
|
||||||
|
{
|
||||||
|
result.Add(new Segment(string.Empty, segment.Style));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
result.Add(new Segment(segment.Text.Substring(0, width), segment.Style));
|
result.Add(new Segment(segment.Text.Substring(0, width), segment.Style));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (overflow == Overflow.Ellipsis)
|
else if (overflow == Overflow.Ellipsis)
|
||||||
|
{
|
||||||
|
if (Math.Max(0, width - 1) == 0)
|
||||||
|
{
|
||||||
|
result.Add(new Segment("…", segment.Style));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
result.Add(new Segment(segment.Text.Substring(0, width - 1) + "…", segment.Style));
|
result.Add(new Segment(segment.Text.Substring(0, width - 1) + "…", segment.Style));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -193,6 +193,12 @@ namespace Spectre.Console
|
|||||||
|
|
||||||
private List<SegmentLine> SplitLines(RenderContext context, int maxWidth)
|
private List<SegmentLine> SplitLines(RenderContext context, int maxWidth)
|
||||||
{
|
{
|
||||||
|
if (maxWidth <= 0)
|
||||||
|
{
|
||||||
|
// Nothing fits, so return an empty line.
|
||||||
|
return new List<SegmentLine>();
|
||||||
|
}
|
||||||
|
|
||||||
if (_lines.Max(x => x.CellWidth(context)) <= maxWidth)
|
if (_lines.Max(x => x.CellWidth(context)) <= maxWidth)
|
||||||
{
|
{
|
||||||
return Clone();
|
return Clone();
|
||||||
|
@ -153,6 +153,7 @@ namespace Spectre.Console
|
|||||||
var borderStyle = BorderStyle ?? Style.Plain;
|
var borderStyle = BorderStyle ?? Style.Plain;
|
||||||
|
|
||||||
var tableWidth = maxWidth;
|
var tableWidth = maxWidth;
|
||||||
|
var actualMaxWidth = maxWidth;
|
||||||
|
|
||||||
var showBorder = Border.Visible;
|
var showBorder = Border.Visible;
|
||||||
var hideBorder = !Border.Visible;
|
var hideBorder = !Border.Visible;
|
||||||
@ -170,6 +171,10 @@ namespace Spectre.Console
|
|||||||
|
|
||||||
// Update the table width.
|
// Update the table width.
|
||||||
tableWidth = columnWidths.Sum() + GetExtraWidth(includePadding: true);
|
tableWidth = columnWidths.Sum() + GetExtraWidth(includePadding: true);
|
||||||
|
if (tableWidth <= 0 || tableWidth > actualMaxWidth || columnWidths.Any(c => c <= 0))
|
||||||
|
{
|
||||||
|
return new List<Segment>(new[] { new Segment("…", BorderStyle ?? Style.Plain) });
|
||||||
|
}
|
||||||
|
|
||||||
var rows = new List<List<IRenderable>>();
|
var rows = new List<List<IRenderable>>();
|
||||||
if (ShowHeaders)
|
if (ShowHeaders)
|
||||||
@ -213,13 +218,15 @@ namespace Spectre.Console
|
|||||||
// Iterate through each cell row
|
// Iterate through each cell row
|
||||||
foreach (var cellRowIndex in Enumerable.Range(0, cellHeight))
|
foreach (var cellRowIndex in Enumerable.Range(0, cellHeight))
|
||||||
{
|
{
|
||||||
|
var rowResult = new List<Segment>();
|
||||||
|
|
||||||
foreach (var (cellIndex, firstCell, lastCell, cell) in cells.Enumerate())
|
foreach (var (cellIndex, firstCell, lastCell, cell) in cells.Enumerate())
|
||||||
{
|
{
|
||||||
if (firstCell && showBorder)
|
if (firstCell && showBorder)
|
||||||
{
|
{
|
||||||
// Show left column edge
|
// Show left column edge
|
||||||
var part = firstRow && ShowHeaders ? TableBorderPart.HeaderLeft : TableBorderPart.CellLeft;
|
var part = firstRow && ShowHeaders ? TableBorderPart.HeaderLeft : TableBorderPart.CellLeft;
|
||||||
result.Add(new Segment(border.GetPart(part), borderStyle));
|
rowResult.Add(new Segment(border.GetPart(part), borderStyle));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pad column on left side.
|
// Pad column on left side.
|
||||||
@ -228,18 +235,18 @@ namespace Spectre.Console
|
|||||||
var leftPadding = _columns[cellIndex].Padding.Left;
|
var leftPadding = _columns[cellIndex].Padding.Left;
|
||||||
if (leftPadding > 0)
|
if (leftPadding > 0)
|
||||||
{
|
{
|
||||||
result.Add(new Segment(new string(' ', leftPadding)));
|
rowResult.Add(new Segment(new string(' ', leftPadding)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add content
|
// Add content
|
||||||
result.AddRange(cell[cellRowIndex]);
|
rowResult.AddRange(cell[cellRowIndex]);
|
||||||
|
|
||||||
// Pad cell content right
|
// Pad cell content right
|
||||||
var length = cell[cellRowIndex].Sum(segment => segment.CellLength(context));
|
var length = cell[cellRowIndex].Sum(segment => segment.CellLength(context));
|
||||||
if (length < columnWidths[cellIndex])
|
if (length < columnWidths[cellIndex])
|
||||||
{
|
{
|
||||||
result.Add(new Segment(new string(' ', columnWidths[cellIndex] - length)));
|
rowResult.Add(new Segment(new string(' ', columnWidths[cellIndex] - length)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pad column on the right side
|
// Pad column on the right side
|
||||||
@ -248,7 +255,7 @@ namespace Spectre.Console
|
|||||||
var rightPadding = _columns[cellIndex].Padding.Right;
|
var rightPadding = _columns[cellIndex].Padding.Right;
|
||||||
if (rightPadding > 0)
|
if (rightPadding > 0)
|
||||||
{
|
{
|
||||||
result.Add(new Segment(new string(' ', rightPadding)));
|
rowResult.Add(new Segment(new string(' ', rightPadding)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,16 +263,26 @@ namespace Spectre.Console
|
|||||||
{
|
{
|
||||||
// Add right column edge
|
// Add right column edge
|
||||||
var part = firstRow && ShowHeaders ? TableBorderPart.HeaderRight : TableBorderPart.CellRight;
|
var part = firstRow && ShowHeaders ? TableBorderPart.HeaderRight : TableBorderPart.CellRight;
|
||||||
result.Add(new Segment(border.GetPart(part), borderStyle));
|
rowResult.Add(new Segment(border.GetPart(part), borderStyle));
|
||||||
}
|
}
|
||||||
else if (showBorder)
|
else if (showBorder)
|
||||||
{
|
{
|
||||||
// Add column separator
|
// Add column separator
|
||||||
var part = firstRow && ShowHeaders ? TableBorderPart.HeaderSeparator : TableBorderPart.CellSeparator;
|
var part = firstRow && ShowHeaders ? TableBorderPart.HeaderSeparator : TableBorderPart.CellSeparator;
|
||||||
result.Add(new Segment(border.GetPart(part), borderStyle));
|
rowResult.Add(new Segment(border.GetPart(part), borderStyle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is the row larger than the allowed max width?
|
||||||
|
if (Segment.CellLength(context, rowResult) > actualMaxWidth)
|
||||||
|
{
|
||||||
|
result.AddRange(Segment.Truncate(context, rowResult, actualMaxWidth));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.AddRange(rowResult);
|
||||||
|
}
|
||||||
|
|
||||||
result.Add(Segment.LineBreak);
|
result.Add(Segment.LineBreak);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ namespace Spectre.Console
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="text">The table column text.</param>
|
/// <param name="text">The table column text.</param>
|
||||||
public TableColumn(string text)
|
public TableColumn(string text)
|
||||||
: this(new Markup(text))
|
: this(new Markup(text).SetOverflow(Overflow.Ellipsis))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user