mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 08:52: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]
|
[Fact]
|
||||||
public void Should_Render_Table_With_Specified_Border()
|
public void Should_Render_Table_With_Specified_Border_Correctly()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var console = new PlainConsole(width: 80);
|
var console = new PlainConsole(width: 80);
|
||||||
@ -132,6 +132,26 @@ namespace Spectre.Console.Tests.Unit.Composition
|
|||||||
console.Lines[5].ShouldBe("+-------------------------+");
|
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]
|
[Fact]
|
||||||
public void Should_Render_Table_With_Multiple_Rows_In_Cell_Correctly()
|
public void Should_Render_Table_With_Multiple_Rows_In_Cell_Correctly()
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Spectre.Console.Composition
|
namespace Spectre.Console.Composition
|
||||||
{
|
{
|
||||||
@ -9,10 +10,11 @@ namespace Spectre.Console.Composition
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class Border
|
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>
|
private static readonly Dictionary<BorderKind, Border> _borders = new Dictionary<BorderKind, Border>
|
||||||
{
|
{
|
||||||
|
{ BorderKind.None, new NoBorder() },
|
||||||
{ BorderKind.Ascii, new AsciiBorder() },
|
{ BorderKind.Ascii, new AsciiBorder() },
|
||||||
{ BorderKind.Square, new SquareBorder() },
|
{ BorderKind.Square, new SquareBorder() },
|
||||||
};
|
};
|
||||||
@ -40,11 +42,17 @@ namespace Spectre.Console.Composition
|
|||||||
return border;
|
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)))
|
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));
|
lookup.Add(part, GetBoxPart(part));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +67,8 @@ namespace Spectre.Console.Composition
|
|||||||
/// <returns>A string representation of the specified border part.</returns>
|
/// <returns>A string representation of the specified border part.</returns>
|
||||||
public string GetPart(BorderPart part, int count)
|
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>
|
/// <summary>
|
||||||
@ -77,6 +86,6 @@ namespace Spectre.Console.Composition
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="part">The part to get the character representation for.</param>
|
/// <param name="part">The part to get the character representation for.</param>
|
||||||
/// <returns>A character representation of the specified border part.</returns>
|
/// <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>
|
/// </summary>
|
||||||
public enum BorderKind
|
public enum BorderKind
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// No border.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A square border.
|
/// A square border.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Square = 0,
|
Square = 1,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An old school ASCII border.
|
/// An old school ASCII border.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Ascii = 1,
|
Ascii = 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,28 +8,28 @@ namespace Spectre.Console.Composition
|
|||||||
public sealed class AsciiBorder : Border
|
public sealed class AsciiBorder : Border
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override char GetBoxPart(BorderPart part)
|
protected override string GetBoxPart(BorderPart part)
|
||||||
{
|
{
|
||||||
return part switch
|
return part switch
|
||||||
{
|
{
|
||||||
BorderPart.HeaderTopLeft => '+',
|
BorderPart.HeaderTopLeft => "+",
|
||||||
BorderPart.HeaderTop => '-',
|
BorderPart.HeaderTop => "-",
|
||||||
BorderPart.HeaderTopSeparator => '-',
|
BorderPart.HeaderTopSeparator => "-",
|
||||||
BorderPart.HeaderTopRight => '+',
|
BorderPart.HeaderTopRight => "+",
|
||||||
BorderPart.HeaderLeft => '|',
|
BorderPart.HeaderLeft => "|",
|
||||||
BorderPart.HeaderSeparator => '|',
|
BorderPart.HeaderSeparator => "|",
|
||||||
BorderPart.HeaderRight => '|',
|
BorderPart.HeaderRight => "|",
|
||||||
BorderPart.HeaderBottomLeft => '|',
|
BorderPart.HeaderBottomLeft => "|",
|
||||||
BorderPart.HeaderBottom => '-',
|
BorderPart.HeaderBottom => "-",
|
||||||
BorderPart.HeaderBottomSeparator => '+',
|
BorderPart.HeaderBottomSeparator => "+",
|
||||||
BorderPart.HeaderBottomRight => '|',
|
BorderPart.HeaderBottomRight => "|",
|
||||||
BorderPart.CellLeft => '|',
|
BorderPart.CellLeft => "|",
|
||||||
BorderPart.CellSeparator => '|',
|
BorderPart.CellSeparator => "|",
|
||||||
BorderPart.ColumnRight => '|',
|
BorderPart.ColumnRight => "|",
|
||||||
BorderPart.FooterBottomLeft => '+',
|
BorderPart.FooterBottomLeft => "+",
|
||||||
BorderPart.FooterBottom => '-',
|
BorderPart.FooterBottom => "-",
|
||||||
BorderPart.FooterBottomSeparator => '-',
|
BorderPart.FooterBottomSeparator => "-",
|
||||||
BorderPart.FooterBottomRight => '+',
|
BorderPart.FooterBottomRight => "+",
|
||||||
_ => throw new InvalidOperationException("Unknown box part."),
|
_ => 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
|
public sealed class SquareBorder : Border
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override char GetBoxPart(BorderPart part)
|
protected override string GetBoxPart(BorderPart part)
|
||||||
{
|
{
|
||||||
return part switch
|
return part switch
|
||||||
{
|
{
|
||||||
BorderPart.HeaderTopLeft => '┌',
|
BorderPart.HeaderTopLeft => "┌",
|
||||||
BorderPart.HeaderTop => '─',
|
BorderPart.HeaderTop => "─",
|
||||||
BorderPart.HeaderTopSeparator => '┬',
|
BorderPart.HeaderTopSeparator => "┬",
|
||||||
BorderPart.HeaderTopRight => '┐',
|
BorderPart.HeaderTopRight => "┐",
|
||||||
BorderPart.HeaderLeft => '│',
|
BorderPart.HeaderLeft => "│",
|
||||||
BorderPart.HeaderSeparator => '│',
|
BorderPart.HeaderSeparator => "│",
|
||||||
BorderPart.HeaderRight => '│',
|
BorderPart.HeaderRight => "│",
|
||||||
BorderPart.HeaderBottomLeft => '├',
|
BorderPart.HeaderBottomLeft => "├",
|
||||||
BorderPart.HeaderBottom => '─',
|
BorderPart.HeaderBottom => "─",
|
||||||
BorderPart.HeaderBottomSeparator => '┼',
|
BorderPart.HeaderBottomSeparator => "┼",
|
||||||
BorderPart.HeaderBottomRight => '┤',
|
BorderPart.HeaderBottomRight => "┤",
|
||||||
BorderPart.CellLeft => '│',
|
BorderPart.CellLeft => "│",
|
||||||
BorderPart.CellSeparator => '│',
|
BorderPart.CellSeparator => "│",
|
||||||
BorderPart.ColumnRight => '│',
|
BorderPart.ColumnRight => "│",
|
||||||
BorderPart.FooterBottomLeft => '└',
|
BorderPart.FooterBottomLeft => "└",
|
||||||
BorderPart.FooterBottom => '─',
|
BorderPart.FooterBottom => "─",
|
||||||
BorderPart.FooterBottomSeparator => '┴',
|
BorderPart.FooterBottomSeparator => "┴",
|
||||||
BorderPart.FooterBottomRight => '┘',
|
BorderPart.FooterBottomRight => "┘",
|
||||||
_ => throw new InvalidOperationException("Unknown box part."),
|
_ => throw new InvalidOperationException("Unknown box part."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ namespace Spectre.Console
|
|||||||
private readonly List<Text> _columns;
|
private readonly List<Text> _columns;
|
||||||
private readonly List<List<Text>> _rows;
|
private readonly List<List<Text>> _rows;
|
||||||
private readonly Border _border;
|
private readonly Border _border;
|
||||||
|
private readonly BorderKind _borderKind;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Table"/> class.
|
/// Initializes a new instance of the <see cref="Table"/> class.
|
||||||
@ -25,6 +26,7 @@ namespace Spectre.Console
|
|||||||
_columns = new List<Text>();
|
_columns = new List<Text>();
|
||||||
_rows = new List<List<Text>>();
|
_rows = new List<List<Text>>();
|
||||||
_border = Border.GetBorder(border);
|
_border = Border.GetBorder(border);
|
||||||
|
_borderKind = border;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -104,8 +106,15 @@ namespace Spectre.Console
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IEnumerable<Segment> Render(Encoding encoding, int width)
|
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.
|
// 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();
|
var columnWidths = _columns.Select(c => c.Measure(encoding, maxColumnWidth)).ToArray();
|
||||||
for (var rowIndex = 0; rowIndex < _rows.Count; rowIndex++)
|
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.
|
// 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.
|
// Create the rows.
|
||||||
var rows = new List<List<Text>>();
|
var rows = new List<List<Text>>();
|
||||||
@ -133,9 +142,8 @@ namespace Spectre.Console
|
|||||||
{
|
{
|
||||||
var cellHeight = 1;
|
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>>();
|
var cells = new List<List<SegmentLine>>();
|
||||||
|
|
||||||
foreach (var (rowWidth, cell) in columnWidths.Zip(row, (f, s) => (f, s)))
|
foreach (var (rowWidth, cell) in columnWidths.Zip(row, (f, s) => (f, s)))
|
||||||
{
|
{
|
||||||
var lines = Segment.SplitLines(cell.Render(encoding, rowWidth));
|
var lines = Segment.SplitLines(cell.Render(encoding, rowWidth));
|
||||||
@ -143,7 +151,8 @@ namespace Spectre.Console
|
|||||||
cells.Add(lines);
|
cells.Add(lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstRow)
|
// Show top of header?
|
||||||
|
if (firstRow && showBorder)
|
||||||
{
|
{
|
||||||
result.Add(new Segment(_border.GetPart(BorderPart.HeaderTopLeft)));
|
result.Add(new Segment(_border.GetPart(BorderPart.HeaderTopLeft)));
|
||||||
foreach (var (columnIndex, _, lastColumn, columnWidth) in columnWidths.Enumerate())
|
foreach (var (columnIndex, _, lastColumn, columnWidth) in columnWidths.Enumerate())
|
||||||
@ -171,31 +180,42 @@ namespace Spectre.Console
|
|||||||
var w00t = cells.Enumerate().ToArray();
|
var w00t = cells.Enumerate().ToArray();
|
||||||
foreach (var (cellIndex, firstCell, lastCell, cell) in w00t)
|
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(_border.GetPart(BorderPart.CellLeft)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pad column on left side.
|
||||||
|
if (showBorder)
|
||||||
|
{
|
||||||
result.Add(new Segment(" "));
|
result.Add(new Segment(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add content
|
||||||
result.AddRange(cell[cellRowIndex]);
|
result.AddRange(cell[cellRowIndex]);
|
||||||
|
|
||||||
// Pad cell right
|
// Pad cell content right
|
||||||
var length = cell[cellRowIndex].Sum(segment => segment.CellLength(encoding));
|
var length = cell[cellRowIndex].Sum(segment => segment.CellLength(encoding));
|
||||||
if (length < columnWidths[cellIndex])
|
if (length < columnWidths[cellIndex])
|
||||||
{
|
{
|
||||||
result.Add(new Segment(new string(' ', columnWidths[cellIndex] - length)));
|
result.Add(new Segment(new string(' ', columnWidths[cellIndex] - length)));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Add(new Segment(" "));
|
// Pad column on the right side
|
||||||
|
if (showBorder || (hideBorder && !lastCell))
|
||||||
if (lastCell)
|
|
||||||
{
|
{
|
||||||
// Separator
|
result.Add(new Segment(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastCell && showBorder)
|
||||||
|
{
|
||||||
|
// Add right column edge
|
||||||
result.Add(new Segment(_border.GetPart(BorderPart.ColumnRight)));
|
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)));
|
result.Add(new Segment(_border.GetPart(BorderPart.CellSeparator)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,7 +223,8 @@ namespace Spectre.Console
|
|||||||
result.Add(Segment.LineBreak());
|
result.Add(Segment.LineBreak());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstRow)
|
// Show bottom of header?
|
||||||
|
if (firstRow && showBorder)
|
||||||
{
|
{
|
||||||
result.Add(new Segment(_border.GetPart(BorderPart.HeaderBottomLeft)));
|
result.Add(new Segment(_border.GetPart(BorderPart.HeaderBottomLeft)));
|
||||||
foreach (var (columnIndex, first, lastColumn, columnWidth) in columnWidths.Enumerate())
|
foreach (var (columnIndex, first, lastColumn, columnWidth) in columnWidths.Enumerate())
|
||||||
@ -222,7 +243,8 @@ namespace Spectre.Console
|
|||||||
result.Add(Segment.LineBreak());
|
result.Add(Segment.LineBreak());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastRow)
|
// Show bottom of footer?
|
||||||
|
if (lastRow && showBorder)
|
||||||
{
|
{
|
||||||
result.Add(new Segment(_border.GetPart(BorderPart.FooterBottomLeft)));
|
result.Add(new Segment(_border.GetPart(BorderPart.FooterBottomLeft)));
|
||||||
foreach (var (columnIndex, first, lastColumn, columnWidth) in columnWidths.Enumerate())
|
foreach (var (columnIndex, first, lastColumn, columnWidth) in columnWidths.Enumerate())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user