mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-14 16:02:50 +08:00
Add support for showing no border
This commit is contained in:
parent
a068fc68c3
commit
f9bd936254
@ -111,7 +111,7 @@ namespace Spectre.Console.Tests.Unit.Composition
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Table_With_Specified_Border()
|
||||
public void Should_Render_Table_With_Specified_Border_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
@ -132,6 +132,26 @@ namespace Spectre.Console.Tests.Unit.Composition
|
||||
console.Lines[5].ShouldBe("+-------------------------+");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Table_With_No_Border_Correctly()
|
||||
{
|
||||
// Given
|
||||
var console = new PlainConsole(width: 80);
|
||||
var table = new Table(BorderKind.None);
|
||||
table.AddColumns("Foo", "Bar", "Baz");
|
||||
table.AddRow("Qux", "Corgi", "Waldo");
|
||||
table.AddRow("Grault", "Garply", "Fred");
|
||||
|
||||
// When
|
||||
console.Render(table);
|
||||
|
||||
// Then
|
||||
console.Lines.Count.ShouldBe(3);
|
||||
console.Lines[0].ShouldBe("Foo Bar Baz ");
|
||||
console.Lines[1].ShouldBe("Qux Corgi Waldo");
|
||||
console.Lines[2].ShouldBe("Grault Garply Fred ");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Render_Table_With_Multiple_Rows_In_Cell_Correctly()
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
@ -9,10 +10,11 @@ namespace Spectre.Console.Composition
|
||||
/// </summary>
|
||||
public abstract class Border
|
||||
{
|
||||
private readonly Dictionary<BorderPart, char> _lookup;
|
||||
private readonly Dictionary<BorderPart, string> _lookup;
|
||||
|
||||
private static readonly Dictionary<BorderKind, Border> _borders = new Dictionary<BorderKind, Border>
|
||||
{
|
||||
{ BorderKind.None, new NoBorder() },
|
||||
{ BorderKind.Ascii, new AsciiBorder() },
|
||||
{ BorderKind.Square, new SquareBorder() },
|
||||
};
|
||||
@ -40,11 +42,17 @@ namespace Spectre.Console.Composition
|
||||
return border;
|
||||
}
|
||||
|
||||
private Dictionary<BorderPart, char> Initialize()
|
||||
private Dictionary<BorderPart, string> Initialize()
|
||||
{
|
||||
var lookup = new Dictionary<BorderPart, char>();
|
||||
var lookup = new Dictionary<BorderPart, string>();
|
||||
foreach (BorderPart part in Enum.GetValues(typeof(BorderPart)))
|
||||
{
|
||||
var text = GetBoxPart(part);
|
||||
if (text.Length > 1)
|
||||
{
|
||||
throw new InvalidOperationException("A box part cannot contain more than one character.");
|
||||
}
|
||||
|
||||
lookup.Add(part, GetBoxPart(part));
|
||||
}
|
||||
|
||||
@ -59,7 +67,8 @@ namespace Spectre.Console.Composition
|
||||
/// <returns>A string representation of the specified border part.</returns>
|
||||
public string GetPart(BorderPart part, int count)
|
||||
{
|
||||
return new string(GetBoxPart(part), count);
|
||||
// TODO: This need some optimization...
|
||||
return string.Join(string.Empty, Enumerable.Repeat(GetBoxPart(part)[0], count));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -77,6 +86,6 @@ namespace Spectre.Console.Composition
|
||||
/// </summary>
|
||||
/// <param name="part">The part to get the character representation for.</param>
|
||||
/// <returns>A character representation of the specified border part.</returns>
|
||||
protected abstract char GetBoxPart(BorderPart part);
|
||||
protected abstract string GetBoxPart(BorderPart part);
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,19 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
public enum BorderKind
|
||||
{
|
||||
/// <summary>
|
||||
/// No border.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// A square border.
|
||||
/// </summary>
|
||||
Square = 0,
|
||||
Square = 1,
|
||||
|
||||
/// <summary>
|
||||
/// An old school ASCII border.
|
||||
/// </summary>
|
||||
Ascii = 1,
|
||||
Ascii = 2,
|
||||
}
|
||||
}
|
||||
|
@ -8,28 +8,28 @@ namespace Spectre.Console.Composition
|
||||
public sealed class AsciiBorder : Border
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override char GetBoxPart(BorderPart part)
|
||||
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.ColumnRight => '|',
|
||||
BorderPart.FooterBottomLeft => '+',
|
||||
BorderPart.FooterBottom => '-',
|
||||
BorderPart.FooterBottomSeparator => '-',
|
||||
BorderPart.FooterBottomRight => '+',
|
||||
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.ColumnRight => "|",
|
||||
BorderPart.FooterBottomLeft => "+",
|
||||
BorderPart.FooterBottom => "-",
|
||||
BorderPart.FooterBottomSeparator => "-",
|
||||
BorderPart.FooterBottomRight => "+",
|
||||
_ => throw new InvalidOperationException("Unknown box part."),
|
||||
};
|
||||
}
|
||||
|
10
src/Spectre.Console/Composition/Borders/NoBorder.cs
Normal file
10
src/Spectre.Console/Composition/Borders/NoBorder.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Spectre.Console.Composition
|
||||
{
|
||||
internal sealed class NoBorder : Border
|
||||
{
|
||||
protected override string GetBoxPart(BorderPart part)
|
||||
{
|
||||
return " ";
|
||||
}
|
||||
}
|
||||
}
|
@ -8,28 +8,28 @@ namespace Spectre.Console.Composition
|
||||
public sealed class SquareBorder : Border
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override char GetBoxPart(BorderPart part)
|
||||
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.ColumnRight => '│',
|
||||
BorderPart.FooterBottomLeft => '└',
|
||||
BorderPart.FooterBottom => '─',
|
||||
BorderPart.FooterBottomSeparator => '┴',
|
||||
BorderPart.FooterBottomRight => '┘',
|
||||
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.ColumnRight => "│",
|
||||
BorderPart.FooterBottomLeft => "└",
|
||||
BorderPart.FooterBottom => "─",
|
||||
BorderPart.FooterBottomSeparator => "┴",
|
||||
BorderPart.FooterBottomRight => "┘",
|
||||
_ => throw new InvalidOperationException("Unknown box part."),
|
||||
};
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ namespace Spectre.Console
|
||||
private readonly List<Text> _columns;
|
||||
private readonly List<List<Text>> _rows;
|
||||
private readonly Border _border;
|
||||
private readonly BorderKind _borderKind;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Table"/> class.
|
||||
@ -25,6 +26,7 @@ namespace Spectre.Console
|
||||
_columns = new List<Text>();
|
||||
_rows = new List<List<Text>>();
|
||||
_border = Border.GetBorder(border);
|
||||
_borderKind = border;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -104,8 +106,15 @@ namespace Spectre.Console
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<Segment> Render(Encoding encoding, int width)
|
||||
{
|
||||
var showBorder = _borderKind != BorderKind.None;
|
||||
var hideBorder = _borderKind == BorderKind.None;
|
||||
|
||||
var leftRightBorderWidth = _borderKind == BorderKind.None ? 0 : 2;
|
||||
var columnPadding = _borderKind == BorderKind.None ? _columns.Count : _columns.Count * 2;
|
||||
var separatorCount = _borderKind == BorderKind.None ? 0 : _columns.Count - 1;
|
||||
|
||||
// Calculate the max width for each column.
|
||||
var maxColumnWidth = (width - (2 + (_columns.Count * 2) + (_columns.Count - 1))) / _columns.Count;
|
||||
var maxColumnWidth = (width - (leftRightBorderWidth + columnPadding + separatorCount)) / _columns.Count;
|
||||
var columnWidths = _columns.Select(c => c.Measure(encoding, maxColumnWidth)).ToArray();
|
||||
for (var rowIndex = 0; rowIndex < _rows.Count; rowIndex++)
|
||||
{
|
||||
@ -120,7 +129,7 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
// We now know the max width of each column, so let's recalculate the width.
|
||||
width = columnWidths.Sum() + 2 + (_columns.Count * 2) + (_columns.Count - 1);
|
||||
width = columnWidths.Sum() + leftRightBorderWidth + columnPadding + separatorCount;
|
||||
|
||||
// Create the rows.
|
||||
var rows = new List<List<Text>>();
|
||||
@ -133,9 +142,8 @@ namespace Spectre.Console
|
||||
{
|
||||
var cellHeight = 1;
|
||||
|
||||
// Get the list of cells for the row.
|
||||
// Get the list of cells for the row and calculate the cell height.
|
||||
var cells = new List<List<SegmentLine>>();
|
||||
|
||||
foreach (var (rowWidth, cell) in columnWidths.Zip(row, (f, s) => (f, s)))
|
||||
{
|
||||
var lines = Segment.SplitLines(cell.Render(encoding, rowWidth));
|
||||
@ -143,7 +151,8 @@ namespace Spectre.Console
|
||||
cells.Add(lines);
|
||||
}
|
||||
|
||||
if (firstRow)
|
||||
// Show top of header?
|
||||
if (firstRow && showBorder)
|
||||
{
|
||||
result.Add(new Segment(_border.GetPart(BorderPart.HeaderTopLeft)));
|
||||
foreach (var (columnIndex, _, lastColumn, columnWidth) in columnWidths.Enumerate())
|
||||
@ -171,31 +180,42 @@ namespace Spectre.Console
|
||||
var w00t = cells.Enumerate().ToArray();
|
||||
foreach (var (cellIndex, firstCell, lastCell, cell) in w00t)
|
||||
{
|
||||
if (firstCell)
|
||||
if (firstCell && showBorder)
|
||||
{
|
||||
// Show left column edge
|
||||
result.Add(new Segment(_border.GetPart(BorderPart.CellLeft)));
|
||||
}
|
||||
|
||||
result.Add(new Segment(" "));
|
||||
// Pad column on left side.
|
||||
if (showBorder)
|
||||
{
|
||||
result.Add(new Segment(" "));
|
||||
}
|
||||
|
||||
// Add content
|
||||
result.AddRange(cell[cellRowIndex]);
|
||||
|
||||
// Pad cell right
|
||||
// Pad cell content right
|
||||
var length = cell[cellRowIndex].Sum(segment => segment.CellLength(encoding));
|
||||
if (length < columnWidths[cellIndex])
|
||||
{
|
||||
result.Add(new Segment(new string(' ', columnWidths[cellIndex] - length)));
|
||||
}
|
||||
|
||||
result.Add(new Segment(" "));
|
||||
|
||||
if (lastCell)
|
||||
// Pad column on the right side
|
||||
if (showBorder || (hideBorder && !lastCell))
|
||||
{
|
||||
// Separator
|
||||
result.Add(new Segment(" "));
|
||||
}
|
||||
|
||||
if (lastCell && showBorder)
|
||||
{
|
||||
// Add right column edge
|
||||
result.Add(new Segment(_border.GetPart(BorderPart.ColumnRight)));
|
||||
}
|
||||
else
|
||||
else if (showBorder || (hideBorder && !lastCell))
|
||||
{
|
||||
// Separator
|
||||
// Add column separator
|
||||
result.Add(new Segment(_border.GetPart(BorderPart.CellSeparator)));
|
||||
}
|
||||
}
|
||||
@ -203,7 +223,8 @@ namespace Spectre.Console
|
||||
result.Add(Segment.LineBreak());
|
||||
}
|
||||
|
||||
if (firstRow)
|
||||
// Show bottom of header?
|
||||
if (firstRow && showBorder)
|
||||
{
|
||||
result.Add(new Segment(_border.GetPart(BorderPart.HeaderBottomLeft)));
|
||||
foreach (var (columnIndex, first, lastColumn, columnWidth) in columnWidths.Enumerate())
|
||||
@ -222,7 +243,8 @@ namespace Spectre.Console
|
||||
result.Add(Segment.LineBreak());
|
||||
}
|
||||
|
||||
if (lastRow)
|
||||
// Show bottom of footer?
|
||||
if (lastRow && showBorder)
|
||||
{
|
||||
result.Add(new Segment(_border.GetPart(BorderPart.FooterBottomLeft)));
|
||||
foreach (var (columnIndex, first, lastColumn, columnWidth) in columnWidths.Enumerate())
|
||||
|
Loading…
x
Reference in New Issue
Block a user