Improve text composite

- A `Text` object should not be able to justify itself.
  All justification needs to be done by a parent.
- Apply colors and styles to part of a `Text` object
- Markup parser should return a `Text` object
This commit is contained in:
Patrik Svensson
2020-07-30 23:26:22 +02:00
committed by Patrik Svensson
parent 8e4f33bba4
commit f19202b427
33 changed files with 728 additions and 434 deletions

View File

@ -1,31 +0,0 @@
using System;
using System.IO;
namespace Spectre.Console.Tests
{
public sealed class AnsiConsoleFixture : IDisposable
{
private readonly StringWriter _writer;
public IAnsiConsole Console { get; }
public string Output => _writer.ToString();
public AnsiConsoleFixture(ColorSystem system, AnsiSupport ansi = AnsiSupport.Yes)
{
_writer = new StringWriter();
Console = AnsiConsole.Create(new AnsiConsoleSettings
{
Ansi = ansi,
ColorSystem = (ColorSystemSupport)system,
Out = _writer,
});
}
public void Dispose()
{
_writer?.Dispose();
}
}
}

View File

@ -1,7 +1,7 @@
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests
namespace Spectre.Console.Tests.Unit
{
public partial class AnsiConsoleTests
{

View File

@ -3,7 +3,7 @@ using System.Diagnostics.CodeAnalysis;
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests
namespace Spectre.Console.Tests.Unit
{
public partial class AnsiConsoleTests
{

View File

@ -1,7 +1,7 @@
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests
namespace Spectre.Console.Tests.Unit
{
public partial class AnsiConsoleTests
{

View File

@ -3,7 +3,7 @@ using System.Globalization;
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests
namespace Spectre.Console.Tests.Unit
{
public partial class AnsiConsoleTests
{

View File

@ -0,0 +1,24 @@
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public sealed class AppearanceTests
{
[Fact]
public void Should_Combine_Two_Appearances_As_Expected()
{
// Given
var first = new Appearance(Color.White, Color.Yellow, Styles.Bold | Styles.Italic);
var other = new Appearance(Color.Green, Color.Silver, Styles.Underline);
// When
var result = first.Combine(other);
// Then
result.Foreground.ShouldBe(Color.Green);
result.Background.ShouldBe(Color.Silver);
result.Style.ShouldBe(Styles.Bold | Styles.Italic | Styles.Underline);
}
}
}

View File

@ -1,8 +1,7 @@
using Shouldly;
using Spectre.Console.Composition;
using Xunit;
namespace Spectre.Console.Tests.Unit.Composition
namespace Spectre.Console.Tests.Unit
{
public sealed class PanelTests
{
@ -13,7 +12,7 @@ namespace Spectre.Console.Tests.Unit.Composition
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel(new Text("Hello World")));
console.Render(new Panel(Text.New("Hello World")));
// Then
console.Lines.Count.ShouldBe(3);
@ -29,7 +28,7 @@ namespace Spectre.Console.Tests.Unit.Composition
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel(new Text(" \n💩\n ")));
console.Render(new Panel(Text.New(" \n💩\n ")));
// Then
console.Lines.Count.ShouldBe(5);
@ -47,7 +46,7 @@ namespace Spectre.Console.Tests.Unit.Composition
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel(new Text("Hello World\nFoo Bar")));
console.Render(new Panel(Text.New("Hello World\nFoo Bar")));
// Then
console.Lines.Count.ShouldBe(4);
@ -57,6 +56,29 @@ namespace Spectre.Console.Tests.Unit.Composition
console.Lines[3].ShouldBe("└─────────────┘");
}
[Fact]
public void Should_Preserve_Explicit_Line_Ending()
{
// Given
var console = new PlainConsole(width: 80);
var text = new Panel(
Text.New("I heard [underline on blue]you[/] like 📦\n\n\n\nSo I put a 📦 in a 📦"),
content: Justify.Center);
// When
console.Render(text);
// Then
console.Lines.Count.ShouldBe(7);
console.Lines[0].ShouldBe("┌───────────────────────┐");
console.Lines[1].ShouldBe("│ I heard you like 📦 │");
console.Lines[2].ShouldBe("│ │");
console.Lines[3].ShouldBe("│ │");
console.Lines[4].ShouldBe("│ │");
console.Lines[5].ShouldBe("│ So I put a 📦 in a 📦 │");
console.Lines[6].ShouldBe("└───────────────────────┘");
}
[Fact]
public void Should_Fit_Panel_To_Parent_If_Enabled()
{
@ -64,7 +86,7 @@ namespace Spectre.Console.Tests.Unit.Composition
var console = new PlainConsole(width: 25);
// When
console.Render(new Panel(new Text("Hello World"), fit: true));
console.Render(new Panel(Text.New("Hello World"), fit: true));
// Then
console.Lines.Count.ShouldBe(3);
@ -80,7 +102,7 @@ namespace Spectre.Console.Tests.Unit.Composition
var console = new PlainConsole(width: 25);
// When
console.Render(new Panel(new Text("Hello World", justify: Justify.Right), fit: true));
console.Render(new Panel(Text.New("Hello World"), fit: true, content: Justify.Right));
// Then
console.Lines.Count.ShouldBe(3);
@ -96,7 +118,7 @@ namespace Spectre.Console.Tests.Unit.Composition
var console = new PlainConsole(width: 25);
// When
console.Render(new Panel(new Text("Hello World", justify: Justify.Center), fit: true));
console.Render(new Panel(Text.New("Hello World"), fit: true, content: Justify.Center));
// Then
console.Lines.Count.ShouldBe(3);
@ -112,7 +134,7 @@ namespace Spectre.Console.Tests.Unit.Composition
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel(new Panel(new Text("Hello World"))));
console.Render(new Panel(new Panel(Text.New("Hello World"))));
// Then
console.Lines.Count.ShouldBe(5);

View File

@ -2,66 +2,91 @@ using Shouldly;
using Spectre.Console.Composition;
using Xunit;
namespace Spectre.Console.Tests.Unit.Composition
namespace Spectre.Console.Tests.Unit
{
public sealed class SegmentTests
{
[Fact]
public void Should_Split_Segment()
public sealed class TheSplitMethod
{
var lines = Segment.Split(new[]
[Fact]
public void Should_Split_Segment_Correctly()
{
new Segment("Foo"),
new Segment("Bar"),
new Segment("\n"),
new Segment("Baz"),
new Segment("Qux"),
new Segment("\n"),
new Segment("Corgi"),
});
// Given
var appearance = new Appearance(Color.Red, Color.Green, Styles.Bold);
var segment = new Segment("Foo Bar", appearance);
// Then
lines.Count.ShouldBe(3);
// When
var (first, second) = segment.Split(3);
lines[0].Count.ShouldBe(2);
lines[0][0].Text.ShouldBe("Foo");
lines[0][1].Text.ShouldBe("Bar");
lines[1].Count.ShouldBe(2);
lines[1][0].Text.ShouldBe("Baz");
lines[1][1].Text.ShouldBe("Qux");
lines[2].Count.ShouldBe(1);
lines[2][0].Text.ShouldBe("Corgi");
// Then
first.Text.ShouldBe("Foo");
first.Appearance.ShouldBe(appearance);
second.Text.ShouldBe(" Bar");
second.Appearance.ShouldBe(appearance);
}
}
[Fact]
public void Should_Split_Segments_With_Linebreak_In_Text()
public sealed class TheSplitLinesMethod
{
var lines = Segment.Split(new[]
[Fact]
public void Should_Split_Segment()
{
new Segment("Foo\n"),
new Segment("Bar\n"),
new Segment("Baz"),
new Segment("Qux\n"),
new Segment("Corgi"),
});
var lines = Segment.SplitLines(
new[]
{
new Segment("Foo"),
new Segment("Bar"),
new Segment("\n"),
new Segment("Baz"),
new Segment("Qux"),
new Segment("\n"),
new Segment("Corgi"),
});
// Then
lines.Count.ShouldBe(4);
// Then
lines.Count.ShouldBe(3);
lines[0].Count.ShouldBe(1);
lines[0][0].Text.ShouldBe("Foo");
lines[0].Count.ShouldBe(2);
lines[0][0].Text.ShouldBe("Foo");
lines[0][1].Text.ShouldBe("Bar");
lines[1].Count.ShouldBe(1);
lines[1][0].Text.ShouldBe("Bar");
lines[1].Count.ShouldBe(2);
lines[1][0].Text.ShouldBe("Baz");
lines[1][1].Text.ShouldBe("Qux");
lines[2].Count.ShouldBe(2);
lines[2][0].Text.ShouldBe("Baz");
lines[2][1].Text.ShouldBe("Qux");
lines[2].Count.ShouldBe(1);
lines[2][0].Text.ShouldBe("Corgi");
}
lines[3].Count.ShouldBe(1);
lines[3][0].Text.ShouldBe("Corgi");
[Fact]
public void Should_Split_Segments_With_Linebreak_In_Text()
{
var lines = Segment.SplitLines(
new[]
{
new Segment("Foo\n"),
new Segment("Bar\n"),
new Segment("Baz"),
new Segment("Qux\n"),
new Segment("Corgi"),
});
// Then
lines.Count.ShouldBe(4);
lines[0].Count.ShouldBe(1);
lines[0][0].Text.ShouldBe("Foo");
lines[1].Count.ShouldBe(1);
lines[1][0].Text.ShouldBe("Bar");
lines[2].Count.ShouldBe(2);
lines[2][0].Text.ShouldBe("Baz");
lines[2][1].Text.ShouldBe("Qux");
lines[3].Count.ShouldBe(1);
lines[3][0].Text.ShouldBe("Corgi");
}
}
}
}

View File

@ -1,61 +1,77 @@
using Shouldly;
using Spectre.Console.Composition;
using Xunit;
namespace Spectre.Console.Tests.Composition
namespace Spectre.Console.Tests.Unit
{
public sealed class TextTests
{
[Fact]
public void Should_Render_Text_To_Console()
public void Should_Render_Unstyled_Text_As_Expected()
{
// Given
var console = new PlainConsole();
var fixture = new PlainConsole(width: 80);
var text = Text.New("Hello World");
// When
console.Render(new Text("Hello World"));
fixture.Render(text);
// Then
console.Output.ShouldBe("Hello World");
fixture.Output
.NormalizeLineEndings()
.ShouldBe("Hello World");
}
[Fact]
public void Should_Right_Align_Text_To_Parent()
public void Should_Split_Unstyled_Text_To_New_Lines_If_Width_Exceeds_Console_Width()
{
// Given
var console = new PlainConsole(width: 15);
var fixture = new PlainConsole(width: 5);
var text = Text.New("Hello World");
// When
console.Render(new Text("Hello World", justify: Justify.Right));
fixture.Render(text);
// Then
console.Output.ShouldBe(" Hello World");
fixture.Output
.NormalizeLineEndings()
.ShouldBe("Hello\n Worl\nd");
}
[Fact]
public void Should_Center_Text_To_Parent()
public sealed class TheStylizeMethod
{
// Given
var console = new PlainConsole(width: 15);
[Fact]
public void Should_Apply_Style_To_Text()
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
var text = Text.New("Hello World");
text.Stylize(start: 3, end: 8, new Appearance(style: Styles.Underline));
// When
console.Render(new Text("Hello World", justify: Justify.Center));
// When
fixture.Console.Render(text);
// Then
console.Output.ShouldBe(" Hello World ");
}
// Then
fixture.Output
.NormalizeLineEndings()
.ShouldBe("Hello World");
}
[Fact]
public void Should_Split_Text_To_Multiple_Lines_If_It_Does_Not_Fit()
{
// Given
var console = new PlainConsole(width: 5);
[Fact]
public void Should_Apply_Style_To_Text_Which_Spans_Over_Multiple_Lines()
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, width: 5);
var text = Text.New("Hello World");
text.Stylize(start: 3, end: 8, new Appearance(style: Styles.Underline));
// When
console.Render(new Text("Hello World"));
// When
fixture.Console.Render(text);
// Then
console.Output.ShouldBe("Hello\n Worl\nd");
// Then
fixture.Output
.NormalizeLineEndings()
.ShouldBe("Hello\n Worl\nd");
}
}
}
}