mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 00:42:51 +08:00
parent
effdecb1d4
commit
8a01b93aca
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace GridExample
|
||||
|
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace PanelExample
|
||||
|
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace TableExample
|
||||
@ -12,6 +11,42 @@ namespace TableExample
|
||||
|
||||
// A big table
|
||||
RenderBigTable();
|
||||
|
||||
// A complex table
|
||||
RenderComplexTable();
|
||||
}
|
||||
|
||||
private static void RenderComplexTable()
|
||||
{
|
||||
// Create simple table.
|
||||
var simple = new Table { Border = BorderKind.Rounded };
|
||||
simple.AddColumn(new TableColumn("[u]Foo[/]").Centered());
|
||||
simple.AddColumn(new TableColumn("[u]Bar[/]"));
|
||||
simple.AddColumn(new TableColumn("[u]Baz[/]"));
|
||||
simple.AddRow("Hello", "[red]World![/]", "");
|
||||
simple.AddRow("[blue]Bounjour[/]", "[white]le[/]", "[red]monde![/]");
|
||||
simple.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
|
||||
|
||||
// Create other table.
|
||||
var second = new Table { Border = BorderKind.Square };
|
||||
second.AddColumn(new TableColumn("[u]Foo[/]"));
|
||||
second.AddColumn(new TableColumn("[u]Bar[/]"));
|
||||
second.AddColumn(new TableColumn("[u]Baz[/]"));
|
||||
second.AddRow("Hello", "[red]World![/]", "");
|
||||
second.AddRow(simple, new Text("Whaaat"), new Text("Lolz"));
|
||||
second.AddRow("[blue]Hej[/]", "[yellow]Världen![/]", "");
|
||||
|
||||
var table = new Table { Border = BorderKind.Rounded };
|
||||
table.AddColumn(new TableColumn(new Panel("[u]Foo[/]")));
|
||||
table.AddColumn(new TableColumn(new Panel("[u]Bar[/]")));
|
||||
table.AddColumn(new TableColumn(new Panel("[u]Baz[/]")));
|
||||
|
||||
// Add some rows
|
||||
table.AddRow(new Text("Hello").Centered(), new Markup("[red]World![/] 🌍"), Text.Empty);
|
||||
table.AddRow(second, new Text("Whaaat"), new Text("Lol"));
|
||||
table.AddRow(new Markup("[blue]Hej[/]").Centered(), new Markup("[yellow]Världen![/]"), Text.Empty);
|
||||
|
||||
AnsiConsole.Render(table);
|
||||
}
|
||||
|
||||
private static void RenderSimpleTable()
|
||||
|
@ -81,3 +81,6 @@ dotnet_diagnostic.RCS1079.severity = warning
|
||||
|
||||
# RCS1057: Add empty line between declarations.
|
||||
dotnet_diagnostic.RCS1057.severity = none
|
||||
|
||||
# IDE0004: Remove Unnecessary Cast
|
||||
dotnet_diagnostic.IDE0004.severity = warning
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using Shouldly;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Rendering;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
|
@ -125,8 +125,7 @@ namespace Spectre.Console.Tests.Unit
|
||||
|
||||
// When
|
||||
console.Render(
|
||||
new Panel(
|
||||
new Text("Hello World").WithAlignment(Justify.Right))
|
||||
new Panel(new Text("Hello World").RightAligned())
|
||||
{
|
||||
Expand = true,
|
||||
});
|
||||
@ -146,8 +145,7 @@ namespace Spectre.Console.Tests.Unit
|
||||
|
||||
// When
|
||||
console.Render(
|
||||
new Panel(
|
||||
new Text("Hello World").WithAlignment(Justify.Center))
|
||||
new Panel(new Text("Hello World").Centered())
|
||||
{
|
||||
Expand = true,
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Rendering;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
|
@ -59,7 +59,21 @@ namespace Spectre.Console.Tests.Unit
|
||||
public sealed class TheAddRowMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Throw_If_Rows_Are_Null()
|
||||
public void Should_Throw_If_String_Rows_Are_Null()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => table.AddRow((string[])null));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<ArgumentNullException>()
|
||||
.ParamName.ShouldBe("columns");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Renderable_Rows_Are_Null()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
|
@ -1,87 +1,81 @@
|
||||
using System.Text;
|
||||
using Shouldly;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Rendering;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
public sealed class TextTests
|
||||
{
|
||||
public sealed class Measuring
|
||||
[Fact]
|
||||
public void Should_Consider_The_Longest_Word_As_Minimum_Width()
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Return_The_Longest_Word_As_Minimum_Width()
|
||||
{
|
||||
var text = new Text("Foo Bar Baz\nQux\nLol mobile");
|
||||
var text = new Text("Foo Bar Baz\nQux\nLol mobile");
|
||||
|
||||
var result = text.Measure(new RenderContext(Encoding.Unicode, false), 80);
|
||||
var result = ((IRenderable)text).Measure(new RenderContext(Encoding.Unicode, false), 80);
|
||||
|
||||
result.Min.ShouldBe(6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Return_The_Longest_Line_As_Maximum_Width()
|
||||
{
|
||||
var text = new Text("Foo Bar Baz\nQux\nLol mobile");
|
||||
|
||||
var result = text.Measure(new RenderContext(Encoding.Unicode, false), 80);
|
||||
|
||||
result.Max.ShouldBe(11);
|
||||
}
|
||||
result.Min.ShouldBe(6);
|
||||
}
|
||||
|
||||
public sealed class Rendering
|
||||
[Fact]
|
||||
public void Should_Consider_The_Longest_Line_As_Maximum_Width()
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Render_Unstyled_Text_As_Expected()
|
||||
{
|
||||
// Given
|
||||
var fixture = new PlainConsole(width: 80);
|
||||
var text = new Text("Hello World");
|
||||
var text = new Text("Foo Bar Baz\nQux\nLol mobile");
|
||||
|
||||
// When
|
||||
fixture.Render(text);
|
||||
var result = ((IRenderable)text).Measure(new RenderContext(Encoding.Unicode, false), 80);
|
||||
|
||||
// Then
|
||||
fixture.Output
|
||||
.NormalizeLineEndings()
|
||||
.ShouldBe("Hello World");
|
||||
}
|
||||
result.Max.ShouldBe(11);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Hello\n\nWorld\n\n")]
|
||||
[InlineData("Hello\r\n\r\nWorld\r\n\r\n")]
|
||||
public void Should_Write_Line_Breaks(string input)
|
||||
{
|
||||
// Given
|
||||
var fixture = new PlainConsole(width: 5);
|
||||
var text = new Text(input);
|
||||
[Fact]
|
||||
public void Should_Render_Unstyled_Text_As_Expected()
|
||||
{
|
||||
// Given
|
||||
var fixture = new PlainConsole(width: 80);
|
||||
var text = new Text("Hello World");
|
||||
|
||||
// When
|
||||
fixture.Render(text);
|
||||
// When
|
||||
fixture.Render(text);
|
||||
|
||||
// Then
|
||||
fixture.RawOutput.ShouldBe("Hello\n\nWorld\n\n");
|
||||
}
|
||||
// Then
|
||||
fixture.Output
|
||||
.NormalizeLineEndings()
|
||||
.ShouldBe("Hello World");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(5, "Hello World", "Hello\nWorld")]
|
||||
[InlineData(10, "Hello Sweet Nice World", "Hello \nSweet Nice\nWorld")]
|
||||
public void Should_Split_Unstyled_Text_To_New_Lines_If_Width_Exceeds_Console_Width(
|
||||
int width, string input, string expected)
|
||||
{
|
||||
// Given
|
||||
var fixture = new PlainConsole(width);
|
||||
var text = new Text(input);
|
||||
[Theory]
|
||||
[InlineData("Hello\n\nWorld\n\n")]
|
||||
[InlineData("Hello\r\n\r\nWorld\r\n\r\n")]
|
||||
public void Should_Write_Line_Breaks(string input)
|
||||
{
|
||||
// Given
|
||||
var fixture = new PlainConsole(width: 5);
|
||||
var text = new Text(input);
|
||||
|
||||
// When
|
||||
fixture.Render(text);
|
||||
// When
|
||||
fixture.Render(text);
|
||||
|
||||
// Then
|
||||
fixture.Output
|
||||
.NormalizeLineEndings()
|
||||
.ShouldBe(expected);
|
||||
}
|
||||
// Then
|
||||
fixture.RawOutput.ShouldBe("Hello\n\nWorld\n\n");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(5, "Hello World", "Hello\nWorld")]
|
||||
[InlineData(10, "Hello Sweet Nice World", "Hello \nSweet Nice\nWorld")]
|
||||
public void Should_Split_Unstyled_Text_To_New_Lines_If_Width_Exceeds_Console_Width(
|
||||
int width, string input, string expected)
|
||||
{
|
||||
// Given
|
||||
var fixture = new PlainConsole(width);
|
||||
var text = new Text(input);
|
||||
|
||||
// When
|
||||
fixture.Render(text);
|
||||
|
||||
// Then
|
||||
fixture.Output
|
||||
.NormalizeLineEndings()
|
||||
.ShouldBe(expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
|
@ -1,27 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="Text"/>.
|
||||
/// </summary>
|
||||
public static class TextExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the text alignment.
|
||||
/// </summary>
|
||||
/// <param name="text">The <see cref="Text"/> instance.</param>
|
||||
/// <param name="alignment">The text alignment.</param>
|
||||
/// <returns>The same <see cref="Text"/> instance.</returns>
|
||||
public static Text WithAlignment(this Text text, Justify alignment)
|
||||
{
|
||||
if (text is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(text));
|
||||
}
|
||||
|
||||
text.Alignment = alignment;
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
|
61
src/Spectre.Console/Rendering/AlignableExtensions.cs
Normal file
61
src/Spectre.Console/Rendering/AlignableExtensions.cs
Normal file
@ -0,0 +1,61 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IAlignable"/>.
|
||||
/// </summary>
|
||||
public static class AlignableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the alignment for an <see cref="IAlignable"/> object.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The alignable type.</typeparam>
|
||||
/// <param name="alignable">The alignable object.</param>
|
||||
/// <param name="alignment">The alignment.</param>
|
||||
/// <returns>The same alignable object.</returns>
|
||||
public static T WithAlignment<T>(this T alignable, Justify alignment)
|
||||
where T : IAlignable
|
||||
{
|
||||
alignable.Alignment = alignment;
|
||||
return alignable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="IAlignable"/> object to be left aligned.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The alignable type.</typeparam>
|
||||
/// <param name="alignable">The alignable object.</param>
|
||||
/// <returns>The same alignable object.</returns>
|
||||
public static T LeftAligned<T>(this T alignable)
|
||||
where T : IAlignable
|
||||
{
|
||||
alignable.Alignment = Justify.Left;
|
||||
return alignable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="IAlignable"/> object to be centered.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The alignable type.</typeparam>
|
||||
/// <param name="alignable">The alignable object.</param>
|
||||
/// <returns>The same alignable object.</returns>
|
||||
public static T Centered<T>(this T alignable)
|
||||
where T : IAlignable
|
||||
{
|
||||
alignable.Alignment = Justify.Center;
|
||||
return alignable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="IAlignable"/> object to be right aligned.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The alignable type.</typeparam>
|
||||
/// <param name="alignable">The alignable object.</param>
|
||||
/// <returns>The same alignable object.</returns>
|
||||
public static T RightAligned<T>(this T alignable)
|
||||
where T : IAlignable
|
||||
{
|
||||
alignable.Alignment = Justify.Right;
|
||||
return alignable;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a border used by tables.
|
@ -1,4 +1,4 @@
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the different border parts.
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an old school ASCII border.
|
@ -1,4 +1,4 @@
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an invisible border.
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a rounded border.
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a square border.
|
@ -1,15 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a grid.
|
||||
/// A renderable grid.
|
||||
/// </summary>
|
||||
public sealed class Grid : IRenderable
|
||||
public sealed class Grid : Renderable
|
||||
{
|
||||
private readonly Table _table;
|
||||
|
||||
@ -28,13 +28,13 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Measurement Measure(RenderContext context, int maxWidth)
|
||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
return ((IRenderable)_table).Measure(context, maxWidth);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<Segment> Render(RenderContext context, int width)
|
||||
protected override IEnumerable<Segment> Render(RenderContext context, int width)
|
||||
{
|
||||
return ((IRenderable)_table).Render(context, width);
|
||||
}
|
||||
@ -109,8 +109,8 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
public void AddEmptyRow()
|
||||
{
|
||||
var columns = new string[_table.ColumnCount];
|
||||
Enumerable.Range(0, _table.ColumnCount).ForEach(index => columns[index] = string.Empty);
|
||||
var columns = new IRenderable[_table.ColumnCount];
|
||||
Enumerable.Range(0, _table.ColumnCount).ForEach(index => columns[index] = Text.Empty);
|
||||
AddRow(columns);
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ namespace Spectre.Console
|
||||
/// Adds a new row to the grid.
|
||||
/// </summary>
|
||||
/// <param name="columns">The columns to add.</param>
|
||||
public void AddRow(params string[] columns)
|
||||
public void AddRow(params IRenderable[] columns)
|
||||
{
|
||||
if (columns is null)
|
||||
{
|
@ -3,7 +3,7 @@ namespace Spectre.Console
|
||||
/// <summary>
|
||||
/// Represents a grid column.
|
||||
/// </summary>
|
||||
public sealed class GridColumn
|
||||
public sealed class GridColumn : IAlignable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the width of the column.
|
31
src/Spectre.Console/Rendering/GridExtensions.cs
Normal file
31
src/Spectre.Console/Rendering/GridExtensions.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="Grid"/>.
|
||||
/// </summary>
|
||||
public static class GridExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a new row to the grid.
|
||||
/// </summary>
|
||||
/// <param name="grid">The grid to add the row to.</param>
|
||||
/// <param name="columns">The columns to add.</param>
|
||||
public static void AddRow(this Grid grid, params string[] columns)
|
||||
{
|
||||
if (grid is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(grid));
|
||||
}
|
||||
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
grid.AddRow(columns.Select(column => new Markup(column)).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
13
src/Spectre.Console/Rendering/IAlignable.cs
Normal file
13
src/Spectre.Console/Rendering/IAlignable.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents something that is alignable.
|
||||
/// </summary>
|
||||
public interface IAlignable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the alignment.
|
||||
/// </summary>
|
||||
Justify? Alignment { get; set; }
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents something that can be rendered to the console.
|
43
src/Spectre.Console/Rendering/Markup.cs
Normal file
43
src/Spectre.Console/Rendering/Markup.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// A renderable piece of markup text.
|
||||
/// </summary>
|
||||
public sealed class Markup : Renderable, IAlignable
|
||||
{
|
||||
private readonly Text _text;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Justify? Alignment
|
||||
{
|
||||
get => _text.Alignment;
|
||||
set => _text.Alignment = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Markup"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The markup text.</param>
|
||||
/// <param name="style">The style of the text.</param>
|
||||
public Markup(string text, Style? style = null)
|
||||
{
|
||||
_text = MarkupParser.Parse(text, style);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
return ((IRenderable)_text).Measure(context, maxWidth);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||
{
|
||||
return ((IRenderable)_text).Render(context, maxWidth);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a measurement.
|
@ -1,13 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Rendering;
|
||||
using SpectreBorder = Spectre.Console.Rendering.Border;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a panel which contains another renderable item.
|
||||
/// A renderable panel.
|
||||
/// </summary>
|
||||
public sealed class Panel : IRenderable
|
||||
public sealed class Panel : Renderable
|
||||
{
|
||||
private const int EdgeWidth = 2;
|
||||
|
||||
@ -42,6 +43,15 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
public Padding Padding { get; set; } = new Padding(1, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Panel"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The panel content.</param>
|
||||
public Panel(string text)
|
||||
: this(new Markup(text))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Panel"/> class.
|
||||
/// </summary>
|
||||
@ -52,23 +62,25 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Measurement IRenderable.Measure(RenderContext context, int maxWidth)
|
||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
var childWidth = _child.Measure(context, maxWidth);
|
||||
return new Measurement(childWidth.Min + 2 + Padding.GetHorizontalPadding(), childWidth.Max + 2 + Padding.GetHorizontalPadding());
|
||||
return new Measurement(
|
||||
childWidth.Min + 2 + Padding.GetHorizontalPadding(),
|
||||
childWidth.Max + 2 + Padding.GetHorizontalPadding());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerable<Segment> IRenderable.Render(RenderContext context, int width)
|
||||
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||
{
|
||||
var border = Composition.Border.GetBorder(Border, (context.LegacyConsole || !context.Unicode) && SafeBorder);
|
||||
var border = SpectreBorder.GetBorder(Border, (context.LegacyConsole || !context.Unicode) && SafeBorder);
|
||||
|
||||
var paddingWidth = Padding.GetHorizontalPadding();
|
||||
var childWidth = width - EdgeWidth - paddingWidth;
|
||||
var childWidth = maxWidth - EdgeWidth - paddingWidth;
|
||||
|
||||
if (!Expand)
|
||||
{
|
||||
var measurement = _child.Measure(context, width - EdgeWidth - paddingWidth);
|
||||
var measurement = _child.Measure(context, maxWidth - EdgeWidth - paddingWidth);
|
||||
childWidth = measurement.Max;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a render context.
|
41
src/Spectre.Console/Rendering/Renderable.cs
Normal file
41
src/Spectre.Console/Rendering/Renderable.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for a renderable object implementing <see cref="IRenderable"/>.
|
||||
/// </summary>
|
||||
public abstract class Renderable : IRenderable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
Measurement IRenderable.Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
return Measure(context, maxWidth);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerable<Segment> IRenderable.Render(RenderContext context, int maxWidth)
|
||||
{
|
||||
return Render(context, maxWidth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Measures the renderable object.
|
||||
/// </summary>
|
||||
/// <param name="context">The render context.</param>
|
||||
/// <param name="maxWidth">The maximum allowed width.</param>
|
||||
/// <returns>The minimum and maximum width of the object.</returns>
|
||||
protected virtual Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
return new Measurement(maxWidth, maxWidth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the object.
|
||||
/// </summary>
|
||||
/// <param name="context">The render context.</param>
|
||||
/// <param name="maxWidth">The maximum allowed width.</param>
|
||||
/// <returns>A collection of segments.</returns>
|
||||
protected abstract IEnumerable<Segment> Render(RenderContext context, int maxWidth);
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using Spectre.Console.Internal;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a renderable segment.
|
@ -3,7 +3,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a collection of segments.
|
@ -1,7 +1,7 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
internal sealed class SegmentLineEnumerator : IEnumerable<Segment>
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Composition
|
||||
namespace Spectre.Console.Rendering
|
||||
{
|
||||
internal sealed class SegmentLineIterator : IEnumerator<Segment>
|
||||
{
|
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
@ -100,13 +100,13 @@ namespace Spectre.Console
|
||||
var maxWidths = new List<int>();
|
||||
|
||||
// Include columns in measurement
|
||||
var measure = ((IRenderable)column.Text).Measure(options, maxWidth);
|
||||
var measure = column.Text.Measure(options, maxWidth);
|
||||
minWidths.Add(measure.Min);
|
||||
maxWidths.Add(measure.Max);
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
measure = ((IRenderable)row).Measure(options, maxWidth);
|
||||
measure = row.Measure(options, maxWidth);
|
||||
minWidths.Add(measure.Min);
|
||||
maxWidths.Add(measure.Max);
|
||||
}
|
@ -1,18 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
using SpectreBorder = Spectre.Console.Rendering.Border;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a table.
|
||||
/// A renderable table.
|
||||
/// </summary>
|
||||
public sealed partial class Table : IRenderable
|
||||
public sealed partial class Table : Renderable
|
||||
{
|
||||
private readonly List<TableColumn> _columns;
|
||||
private readonly List<List<Text>> _rows;
|
||||
private readonly List<List<IRenderable>> _rows;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of columns in the table.
|
||||
@ -67,21 +68,7 @@ namespace Spectre.Console
|
||||
public Table()
|
||||
{
|
||||
_columns = new List<TableColumn>();
|
||||
_rows = new List<List<Text>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a column to the table.
|
||||
/// </summary>
|
||||
/// <param name="column">The column to add.</param>
|
||||
public void AddColumn(string column)
|
||||
{
|
||||
if (column is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(column));
|
||||
}
|
||||
|
||||
AddColumn(new TableColumn(column));
|
||||
_rows = new List<List<IRenderable>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -103,23 +90,6 @@ namespace Spectre.Console
|
||||
_columns.Add(column);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds multiple columns to the table.
|
||||
/// </summary>
|
||||
/// <param name="columns">The columns to add.</param>
|
||||
public void AddColumns(params string[] columns)
|
||||
{
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
foreach (var column in columns)
|
||||
{
|
||||
AddColumn(column);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds multiple columns to the table.
|
||||
/// </summary>
|
||||
@ -142,8 +112,8 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
public void AddEmptyRow()
|
||||
{
|
||||
var columns = new string[ColumnCount];
|
||||
Enumerable.Range(0, ColumnCount).ForEach(index => columns[index] = string.Empty);
|
||||
var columns = new IRenderable[ColumnCount];
|
||||
Enumerable.Range(0, ColumnCount).ForEach(index => columns[index] = Text.Empty);
|
||||
AddRow(columns);
|
||||
}
|
||||
|
||||
@ -151,7 +121,7 @@ namespace Spectre.Console
|
||||
/// Adds a row to the table.
|
||||
/// </summary>
|
||||
/// <param name="columns">The row columns to add.</param>
|
||||
public void AddRow(params string[] columns)
|
||||
public void AddRow(params IRenderable[] columns)
|
||||
{
|
||||
if (columns is null)
|
||||
{
|
||||
@ -168,11 +138,11 @@ namespace Spectre.Console
|
||||
throw new InvalidOperationException("The number of row columns are greater than the number of table columns.");
|
||||
}
|
||||
|
||||
_rows.Add(columns.Select(column => Text.Markup(column)).ToList());
|
||||
_rows.Add(columns.ToList());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Measurement IRenderable.Measure(RenderContext context, int maxWidth)
|
||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
if (context is null)
|
||||
{
|
||||
@ -194,20 +164,20 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerable<Segment> IRenderable.Render(RenderContext context, int width)
|
||||
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||
{
|
||||
if (context is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var border = Composition.Border.GetBorder(Border, (context.LegacyConsole || !context.Unicode) && SafeBorder);
|
||||
var border = SpectreBorder.GetBorder(Border, (context.LegacyConsole || !context.Unicode) && SafeBorder);
|
||||
var tableWidth = maxWidth;
|
||||
|
||||
var showBorder = Border != BorderKind.None;
|
||||
var hideBorder = Border == BorderKind.None;
|
||||
var hasRows = _rows.Count > 0;
|
||||
|
||||
var maxWidth = width;
|
||||
if (Width != null)
|
||||
{
|
||||
maxWidth = Math.Min(Width.Value, maxWidth);
|
||||
@ -219,13 +189,13 @@ namespace Spectre.Console
|
||||
var columnWidths = CalculateColumnWidths(context, maxWidth);
|
||||
|
||||
// Update the table width.
|
||||
width = columnWidths.Sum() + GetExtraWidth(includePadding: true);
|
||||
tableWidth = columnWidths.Sum() + GetExtraWidth(includePadding: true);
|
||||
|
||||
var rows = new List<List<Text>>();
|
||||
var rows = new List<List<IRenderable>>();
|
||||
if (ShowHeaders)
|
||||
{
|
||||
// Add columns to top of rows
|
||||
rows.Add(new List<Text>(_columns.Select(c => c.Text)));
|
||||
rows.Add(new List<IRenderable>(_columns.Select(c => c.Text)));
|
||||
}
|
||||
|
||||
// Add rows.
|
||||
@ -244,7 +214,7 @@ namespace Spectre.Console
|
||||
var justification = _columns[columnIndex].Alignment;
|
||||
var childContext = context.WithJustification(justification);
|
||||
|
||||
var lines = Segment.SplitLines(((IRenderable)cell).Render(childContext, rowWidth));
|
||||
var lines = Segment.SplitLines(cell.Render(childContext, rowWidth));
|
||||
cellHeight = Math.Max(cellHeight, lines.Count);
|
||||
cells.Add(lines);
|
||||
}
|
@ -1,16 +1,17 @@
|
||||
using System;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a table column.
|
||||
/// </summary>
|
||||
public sealed class TableColumn
|
||||
public sealed class TableColumn : IAlignable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the text associated with the column.
|
||||
/// </summary>
|
||||
public Text Text { get; }
|
||||
public IRenderable Text { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the width of the column.
|
||||
@ -39,8 +40,17 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
/// <param name="text">The table column text.</param>
|
||||
public TableColumn(string text)
|
||||
: this(new Markup(text))
|
||||
{
|
||||
Text = Text.Markup(text ?? throw new ArgumentNullException(nameof(text)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TableColumn"/> class.
|
||||
/// </summary>
|
||||
/// <param name="renderable">The <see cref="IRenderable"/> instance to use as the table column.</param>
|
||||
public TableColumn(IRenderable renderable)
|
||||
{
|
||||
Text = renderable ?? throw new ArgumentNullException(nameof(renderable));
|
||||
Width = null;
|
||||
Padding = new Padding(1, 1);
|
||||
NoWrap = false;
|
78
src/Spectre.Console/Rendering/TableExtensions.cs
Normal file
78
src/Spectre.Console/Rendering/TableExtensions.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="Table"/>.
|
||||
/// </summary>
|
||||
public static class TableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a column to the table.
|
||||
/// </summary>
|
||||
/// <param name="table">The table to add the column to.</param>
|
||||
/// <param name="column">The column to add.</param>
|
||||
/// <returns>The added <see cref="TableColumn"/> instance.</returns>
|
||||
public static TableColumn AddColumn(this Table table, string column)
|
||||
{
|
||||
if (table is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(table));
|
||||
}
|
||||
|
||||
if (column is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(column));
|
||||
}
|
||||
|
||||
var tableColumn = new TableColumn(column);
|
||||
table.AddColumn(tableColumn);
|
||||
|
||||
return tableColumn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds multiple columns to the table.
|
||||
/// </summary>
|
||||
/// <param name="table">The table to add the columns to.</param>
|
||||
/// <param name="columns">The columns to add.</param>
|
||||
public static void AddColumns(this Table table, params string[] columns)
|
||||
{
|
||||
if (table is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(table));
|
||||
}
|
||||
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
foreach (var column in columns)
|
||||
{
|
||||
AddColumn(table, column);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a row to the table.
|
||||
/// </summary>
|
||||
/// <param name="table">The table to add the row to.</param>
|
||||
/// <param name="columns">The row columns to add.</param>
|
||||
public static void AddRow(this Table table, params string[] columns)
|
||||
{
|
||||
if (table is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(table));
|
||||
}
|
||||
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
table.AddRow(columns.Select(column => new Markup(column)).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
@ -3,24 +3,29 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Composition;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a piece of text.
|
||||
/// A renderable piece of text.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{_text,nq}")]
|
||||
[SuppressMessage("Naming", "CA1724:Type names should not match namespaces")]
|
||||
public sealed class Text : IRenderable
|
||||
public sealed class Text : Renderable, IAlignable
|
||||
{
|
||||
private readonly List<SegmentLine> _lines;
|
||||
|
||||
/// <summary>
|
||||
/// Gets an empty <see cref="Text"/> instance.
|
||||
/// </summary>
|
||||
public static Text Empty { get; } = new Text(string.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text alignment.
|
||||
/// </summary>
|
||||
public Justify Alignment { get; set; } = Justify.Left;
|
||||
public Justify? Alignment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Text"/> class.
|
||||
@ -60,7 +65,7 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Measurement Measure(RenderContext context, int maxWidth)
|
||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
if (_lines.Count == 0)
|
||||
{
|
||||
@ -74,7 +79,7 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||
{
|
||||
if (context is null)
|
||||
{
|
||||
@ -89,7 +94,7 @@ namespace Spectre.Console
|
||||
var lines = SplitLines(context, maxWidth);
|
||||
|
||||
// Justify lines
|
||||
var justification = context.Justification ?? Alignment;
|
||||
var justification = context.Justification ?? Alignment ?? Justify.Left;
|
||||
foreach (var (_, _, last, line) in lines.Enumerate())
|
||||
{
|
||||
var length = line.Sum(l => l.StripLineEndings().CellLength(context.Encoding));
|
Loading…
x
Reference in New Issue
Block a user