Change IAnsiConsole to render IRenderable

This makes it possible for encoders to output better representation
of the actual objects instead of working with chopped up segments.

* IAnsiConsole.Write now takes an IRenderable instead of segments
* Calculating cell width does no longer require a render context
* Removed RenderContext.LegacyConsole
* Removed RenderContext.Encoding
* Added Capabilities.Unicode
This commit is contained in:
Patrik Svensson 2021-03-24 23:09:24 +01:00 committed by Phil Scott
parent 2ba6da3514
commit 20650f1e7e
75 changed files with 492 additions and 553 deletions

View File

@ -11,6 +11,7 @@ namespace InfoExample
.AddColumn()
.AddRow("[b]Enrichers[/]", string.Join(", ", AnsiConsole.Profile.Enrichers))
.AddRow("[b]Color system[/]", $"{AnsiConsole.Profile.ColorSystem}")
.AddRow("[b]Unicode?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Unicode)}")
.AddRow("[b]Supports ansi?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Ansi)}")
.AddRow("[b]Supports links?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Links)}")
.AddRow("[b]Legacy console?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Legacy)}")

View File

@ -1,3 +1,4 @@
using System.Diagnostics;
using Spectre.Console;
namespace TableExample

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using Spectre.Console.Rendering;
@ -42,6 +41,7 @@ namespace Spectre.Console.Testing
});
_console.Profile.Width = width;
_console.Profile.Capabilities.Unicode = true;
Input = new FakeConsoleInput();
}
@ -56,17 +56,9 @@ namespace Spectre.Console.Testing
_console.Clear(home);
}
public void Write(IEnumerable<Segment> segments)
public void Write(IRenderable renderable)
{
if (segments is null)
{
return;
}
foreach (var segment in segments)
{
_console.Write(segment);
}
_console.Write(renderable);
}
}
}

View File

@ -0,0 +1,17 @@
namespace Spectre.Console.Testing
{
public sealed class FakeCapabilities : IReadOnlyCapabilities
{
public bool Ansi { get; set; }
public bool Links { get; set; }
public bool Legacy { get; set; }
public bool Tty { get; set; }
public bool Interactive { get; set; }
public bool Unicode { get; set; }
}
}

View File

@ -36,6 +36,7 @@ namespace Spectre.Console.Testing
Profile.Capabilities.Legacy = legacyConsole;
Profile.Capabilities.Interactive = interactive;
Profile.Capabilities.Links = true;
Profile.Capabilities.Unicode = true;
}
public void Dispose()
@ -47,14 +48,9 @@ namespace Spectre.Console.Testing
{
}
public void Write(IEnumerable<Segment> segments)
public void Write(IRenderable renderable)
{
if (segments is null)
{
return;
}
foreach (var segment in segments)
foreach (var segment in renderable.GetSegments(this))
{
Profile.Out.Write(segment.Text);
}

View File

@ -1,10 +1,10 @@
<pre style="font-size:90%;font-family:consolas,'Courier New',monospace">
<span>┌─────────────────┬───────┬─────┐</span>
<span>│ </span><span style="color: #FF0000;background-color: #000000">Foo</span><span> │ </span><span style="color: #008000;font-weight: bold;font-style: italic">Bar</span><span> │ </span><span style="color: #0000FF">Qux</span><span> │</span>
<span>│</span><span> </span><span style="color: #FF0000;background-color: #000000">Foo</span><span> </span><span> </span><span></span><span> </span><span style="color: #008000;font-weight: bold;font-style: italic">Bar</span><span> </span><span> </span><span></span><span> </span><span style="color: #0000FF">Qux</span><span> </span><span>│</span>
<span>├─────────────────┼───────┼─────┤</span>
<span>│ </span><span style="text-decoration: underline">Corgi</span><span> │ </span><span style="font-weight: bold;font-style: italic;text-decoration: line-through">Waldo</span><span> │ </span><span style="color: #7F7F7F">Zap</span><span> │</span>
<span>│ </span><span style="color: #FF0000">╭─────────────╮</span><span> │ │ │</span>
<span>│ </span><span style="color: #FF0000">│</span><span> </span><span style="color: #0000FF">Hello World</span><span> </span><span style="color: #FF0000">│</span><span> │ │ │</span>
<span>│ </span><span style="color: #FF0000">╰─────────────╯</span><span> │ │ │</span>
<span>│</span><span> </span><span style="text-decoration: underline">Corgi</span><span> </span><span> </span><span></span><span> </span><span style="font-weight: bold;font-style: italic;text-decoration: line-through">Waldo</span><span> </span><span></span><span> </span><span style="color: #7F7F7F">Zap</span><span> </span><span>│</span>
<span>│</span><span> </span><span style="color: #FF0000">╭</span><span style="color: #FF0000">─────────────</span><span style="color: #FF0000">╮</span><span> </span><span></span><span> </span><span> </span><span> </span><span></span><span> </span><span> </span><span> </span><span>│</span>
<span>│</span><span> </span><span style="color: #FF0000">│</span><span> </span><span style="color: #0000FF">Hello</span><span style="color: #0000FF"> </span><span style="color: #0000FF">World</span><span> </span><span style="color: #FF0000">│</span><span> </span><span></span><span> </span><span> </span><span> </span><span></span><span> </span><span> </span><span> </span><span>│</span>
<span>│</span><span> </span><span style="color: #FF0000">╰</span><span style="color: #FF0000">─────────────</span><span style="color: #FF0000">╯</span><span> </span><span></span><span> </span><span> </span><span> </span><span></span><span> </span><span> </span><span> </span><span>│</span>
<span>└─────────────────┴───────┴─────┘</span>
</pre>

View File

@ -18,7 +18,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new BarChart()
console.Write(new BarChart()
.Width(60)
.Label("Number of fruits")
.AddItem("Apple", 12)
@ -37,7 +37,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new BarChart()
console.Write(new BarChart()
.Width(60)
.Label("Number of fruits")
.AddItem("Apple", 0)

View File

@ -37,7 +37,7 @@ namespace Spectre.Console.Tests.Unit
var panel = Fixture.GetPanel().NoBorder();
// When
console.Render(panel);
console.Write(panel);
// Then
return Verifier.Verify(console.Output);
@ -69,7 +69,7 @@ namespace Spectre.Console.Tests.Unit
var panel = Fixture.GetPanel().AsciiBorder();
// When
console.Render(panel);
console.Write(panel);
// Then
return Verifier.Verify(console.Output);
@ -101,7 +101,7 @@ namespace Spectre.Console.Tests.Unit
var panel = Fixture.GetPanel().DoubleBorder();
// When
console.Render(panel);
console.Write(panel);
// Then
return Verifier.Verify(console.Output);
@ -133,7 +133,7 @@ namespace Spectre.Console.Tests.Unit
var panel = Fixture.GetPanel().HeavyBorder();
// When
console.Render(panel);
console.Write(panel);
// Then
return Verifier.Verify(console.Output);
@ -162,7 +162,7 @@ namespace Spectre.Console.Tests.Unit
var panel = Fixture.GetPanel().RoundedBorder();
// When
console.Render(panel);
console.Write(panel);
// Then
return Verifier.Verify(console.Output);
@ -191,7 +191,7 @@ namespace Spectre.Console.Tests.Unit
var panel = Fixture.GetPanel().SquareBorder();
// When
console.Render(panel);
console.Write(panel);
// Then
return Verifier.Verify(console.Output);

View File

@ -19,7 +19,7 @@ namespace Spectre.Console.Tests.Unit
var chart = Fixture.GetChart();
// When
console.Render(chart);
console.Write(chart);
// Then
await Verifier.Verify(console.Output);
@ -34,7 +34,7 @@ namespace Spectre.Console.Tests.Unit
var chart = Fixture.GetChart().Width(60);
// When
console.Render(chart);
console.Write(chart);
// Then
await Verifier.Verify(console.Output);
@ -52,7 +52,7 @@ namespace Spectre.Console.Tests.Unit
.UseValueFormatter((v, c) => string.Format(c, "{0}%", v));
// When
console.Render(chart);
console.Write(chart);
// Then
await Verifier.Verify(console.Output);
@ -67,7 +67,7 @@ namespace Spectre.Console.Tests.Unit
var chart = Fixture.GetChart().Width(60).HideTags();
// When
console.Render(chart);
console.Write(chart);
// Then
await Verifier.Verify(console.Output);
@ -82,7 +82,7 @@ namespace Spectre.Console.Tests.Unit
var chart = Fixture.GetChart().Width(60).HideTagValues();
// When
console.Render(chart);
console.Write(chart);
// Then
await Verifier.Verify(console.Output);
@ -97,7 +97,7 @@ namespace Spectre.Console.Tests.Unit
var chart = Fixture.GetChart().Width(60).Culture("sv-SE");
// When
console.Render(chart);
console.Write(chart);
// Then
await Verifier.Verify(console.Output);
@ -112,7 +112,7 @@ namespace Spectre.Console.Tests.Unit
var chart = Fixture.GetChart().Width(60).FullSize();
// When
console.Render(chart);
console.Write(chart);
// Then
await Verifier.Verify(console.Output);
@ -127,7 +127,7 @@ namespace Spectre.Console.Tests.Unit
var chart = Fixture.GetChart().Width(60).FullSize();
// When
console.Render(chart);
console.Write(chart);
// Then
await Verifier.Verify(console.Output);

View File

@ -23,7 +23,7 @@ namespace Spectre.Console.Tests.Unit
.AddCalendarEvent(new DateTime(2020, 10, 12));
// When
console.Render(calendar);
console.Write(calendar);
// Then
return Verifier.Verify(console.Output);
@ -42,7 +42,7 @@ namespace Spectre.Console.Tests.Unit
.AddCalendarEvent(new DateTime(2020, 10, 12));
// When
console.Render(calendar);
console.Write(calendar);
// Then
return Verifier.Verify(console.Output);
@ -61,7 +61,7 @@ namespace Spectre.Console.Tests.Unit
.AddCalendarEvent(new DateTime(2020, 10, 12));
// When
console.Render(calendar);
console.Write(calendar);
// Then
return Verifier.Verify(console.Output);
@ -80,7 +80,7 @@ namespace Spectre.Console.Tests.Unit
.AddCalendarEvent(new DateTime(2020, 10, 12));
// When
console.Render(calendar);
console.Write(calendar);
// Then
return Verifier.Verify(console.Output);
@ -99,7 +99,7 @@ namespace Spectre.Console.Tests.Unit
.AddCalendarEvent(new DateTime(2020, 10, 12));
// When
console.Render(calendar);
console.Write(calendar);
// Then
return Verifier.Verify(console.Output);

View File

@ -50,7 +50,7 @@ namespace Spectre.Console.Tests.Unit
canvas.SetPixel(4, 4, Color.Yellow);
// When
console.Render(canvas);
console.Write(canvas);
// Then
await Verifier.Verify(console.Output);
@ -67,7 +67,7 @@ namespace Spectre.Console.Tests.Unit
.SetPixel(1, 1, Color.Grey));
// When
console.Render(panel);
console.Write(panel);
// Then
await Verifier.Verify(console.Output);
@ -84,7 +84,7 @@ namespace Spectre.Console.Tests.Unit
canvas.SetPixel(19, 9, Color.Grey);
// When
console.Render(canvas);
console.Write(canvas);
// Then
await Verifier.Verify(console.Output);
@ -101,7 +101,7 @@ namespace Spectre.Console.Tests.Unit
canvas.SetPixel(19, 9, Color.Aqua);
// When
console.Render(canvas);
console.Write(canvas);
// Then
await Verifier.Verify(console.Output);
@ -117,7 +117,7 @@ namespace Spectre.Console.Tests.Unit
canvas.SetPixel(19, 1, Color.Grey);
// When
console.Render(canvas);
console.Write(canvas);
// Then
console.Output.ShouldBeEmpty();

View File

@ -39,7 +39,7 @@ namespace Spectre.Console.Tests.Unit
}
// When
console.Render(new Columns(cards));
console.Write(new Columns(cards));
// Then
return Verifier.Verify(console.Output);

View File

@ -20,7 +20,7 @@ namespace Spectre.Console.Tests.Unit
var text = new FigletText(font, "Patrik was here");
// When
console.Render(text);
console.Write(text);
// Then
await Verifier.Verify(console.Output);
@ -35,7 +35,7 @@ namespace Spectre.Console.Tests.Unit
var text = new FigletText(FigletFont.Default, "Patrik was here");
// When
console.Render(text);
console.Write(text);
// Then
await Verifier.Verify(console.Output);
@ -50,7 +50,7 @@ namespace Spectre.Console.Tests.Unit
var text = new FigletText(FigletFont.Default, "Spectre.Console");
// When
console.Render(text);
console.Write(text);
// Then
await Verifier.Verify(console.Output);
@ -66,7 +66,7 @@ namespace Spectre.Console.Tests.Unit
.Alignment(Justify.Left);
// When
console.Render(text);
console.Write(text);
// Then
await Verifier.Verify(console.Output);
@ -82,7 +82,7 @@ namespace Spectre.Console.Tests.Unit
.Alignment(Justify.Center);
// When
console.Render(text);
console.Write(text);
// Then
await Verifier.Verify(console.Output);
@ -98,7 +98,7 @@ namespace Spectre.Console.Tests.Unit
.Alignment(Justify.Right);
// When
console.Render(text);
console.Write(text);
// Then
await Verifier.Verify(console.Output);

View File

@ -96,7 +96,7 @@ namespace Spectre.Console.Tests.Unit
grid.AddEmptyRow();
// When
console.Render(grid);
console.Write(grid);
// Then
return Verifier.Verify(console.Output);
@ -117,7 +117,7 @@ namespace Spectre.Console.Tests.Unit
grid.AddRow("Grault", "Garply", "Fred");
// When
console.Render(grid);
console.Write(grid);
// Then
return Verifier.Verify(console.Output);
@ -136,7 +136,7 @@ namespace Spectre.Console.Tests.Unit
grid.AddRow(" [blue]-c[/], [blue]--configuration[/]", "The configuration to run for.\nThe default for most projects is [green]Debug[/].");
// When
console.Render(grid);
console.Write(grid);
// Then
return Verifier.Verify(console.Output);
@ -157,7 +157,7 @@ namespace Spectre.Console.Tests.Unit
grid.AddRow("Grault", "Garply", "Fred");
// When
console.Render(grid);
console.Write(grid);
// Then
return Verifier.Verify(console.Output);
@ -176,7 +176,7 @@ namespace Spectre.Console.Tests.Unit
grid.AddRow("Grault", "Garply", "Fred");
// When
console.Render(grid);
console.Write(grid);
// Then
return Verifier.Verify(console.Output);
@ -197,7 +197,7 @@ namespace Spectre.Console.Tests.Unit
grid.AddRow("Grault", "Garply", "Fred");
// When
console.Render(grid);
console.Write(grid);
// Then
return Verifier.Verify(console.Output);

View File

@ -66,7 +66,7 @@ namespace Spectre.Console.Tests.Unit
var markup = new Markup("Hello [[ World ]] !");
// When
console.Render(markup);
console.Write(markup);
// Then
console.Output.ShouldBe("Hello [ World ] !");
@ -82,7 +82,7 @@ namespace Spectre.Console.Tests.Unit
var markup = new Markup(input);
// When
console.Render(markup);
console.Write(markup);
// Then
console.Output.ShouldBe(output);

View File

@ -23,7 +23,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Corgi", "Waldo");
// When
console.Render(new Padder(table).Padding(1, 2, 3, 4));
console.Write(new Padder(table).Padding(1, 2, 3, 4));
// Then
return Verifier.Verify(console.Output);
@ -42,7 +42,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Corgi", "Waldo");
// When
console.Render(new Padder(table)
console.Write(new Padder(table)
.Padding(1, 2, 3, 4)
.Expand());
@ -64,7 +64,7 @@ namespace Spectre.Console.Tests.Unit
.Padding(2, 1));
// When
console.Render(new Padder(table)
console.Write(new Padder(table)
.Padding(1, 2, 3, 4)
.Expand());

View File

@ -20,7 +20,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new Panel(new Text("Hello World")));
console.Write(new Panel(new Text("Hello World")));
// Then
return Verifier.Verify(console.Output);
@ -34,7 +34,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new Panel(new Text("Hello World"))
console.Write(new Panel(new Text("Hello World"))
{
Padding = new Padding(0, 0, 0, 0),
});
@ -51,7 +51,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new Panel(new Text("Hello World"))
console.Write(new Panel(new Text("Hello World"))
{
Padding = new Padding(3, 1, 5, 2),
});
@ -68,7 +68,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new Panel("Hello World")
console.Write(new Panel("Hello World")
{
Header = new PanelHeader("Greeting"),
Expand = true,
@ -87,7 +87,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new Panel("Hello World")
console.Write(new Panel("Hello World")
{
Header = new PanelHeader("Greeting").LeftAligned(),
Expand = true,
@ -105,7 +105,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new Panel("Hello World")
console.Write(new Panel("Hello World")
{
Header = new PanelHeader("Greeting").Centered(),
Expand = true,
@ -123,7 +123,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new Panel("Hello World")
console.Write(new Panel("Hello World")
{
Header = new PanelHeader("Greeting").RightAligned(),
Expand = true,
@ -141,7 +141,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 10);
// When
console.Render(new Panel("Hello World")
console.Write(new Panel("Hello World")
{
Header = new PanelHeader("Greeting"),
Expand = true,
@ -159,7 +159,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new Panel(new Text(" \n💩\n ")));
console.Write(new Panel(new Text(" \n💩\n ")));
// Then
return Verifier.Verify(console.Output);
@ -173,7 +173,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new Panel(new Text("Hello World\nFoo Bar")));
console.Write(new Panel(new Text("Hello World\nFoo Bar")));
// Then
return Verifier.Verify(console.Output);
@ -189,7 +189,7 @@ namespace Spectre.Console.Tests.Unit
new Markup("I heard [underline on blue]you[/] like 📦\n\n\n\nSo I put a 📦 in a 📦"));
// When
console.Render(text);
console.Write(text);
// Then
return Verifier.Verify(console.Output);
@ -203,7 +203,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new Panel(new Text("Hello World"))
console.Write(new Panel(new Text("Hello World"))
{
Expand = true,
});
@ -220,7 +220,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 25);
// When
console.Render(
console.Write(
new Panel(new Text("Hello World").RightAligned())
{
Expand = true,
@ -238,7 +238,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 25);
// When
console.Render(
console.Write(
new Panel(new Text("Hello World").Centered())
{
Expand = true,
@ -256,7 +256,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new Panel(new Panel(new Text("Hello World"))));
console.Write(new Panel(new Panel(new Text("Hello World"))));
// Then
return Verifier.Verify(console.Output);
@ -281,7 +281,7 @@ namespace Spectre.Console.Tests.Unit
.Header("[grey]Short paths[/]");
// When
console.Render(panel);
console.Write(panel);
// Then
return Verifier.Verify(console.Output);
@ -300,7 +300,7 @@ namespace Spectre.Console.Tests.Unit
var panel = new Panel(table);
// When
console.Render(panel);
console.Write(panel);
// Then
return Verifier.Verify(console.Output);

View File

@ -1,5 +1,4 @@
using System;
using System.Text;
using System;
using Spectre.Console.Rendering;
using Spectre.Console.Testing;
@ -21,8 +20,8 @@ namespace Spectre.Console.Tests.Unit
public string Render()
{
var console = new FakeConsole();
var context = new RenderContext(Encoding.UTF8, false);
console.Render(Column.Render(context, Task, TimeSpan.Zero));
var context = new RenderContext(console.Profile.Capabilities);
console.Write(Column.Render(context, Task, TimeSpan.Zero));
return console.Output;
}
}

View File

@ -18,7 +18,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole();
var recorder = new Recorder(console);
recorder.Render(new Table()
recorder.Write(new Table()
.AddColumns("Foo", "Bar", "Qux")
.AddRow("Corgi", "Waldo", "Zap")
.AddRow(new Panel("Hello World").RoundedBorder()));
@ -32,13 +32,13 @@ namespace Spectre.Console.Tests.Unit
[Fact]
[Expectation("Html")]
public Task Should_Export_Html_As_Expected()
public Task Should_Export_Html_Text_As_Expected()
{
// Given
var console = new FakeConsole();
var recorder = new Recorder(console);
recorder.Render(new Table()
recorder.Write(new Table()
.AddColumns("[red on black]Foo[/]", "[green bold]Bar[/]", "[blue italic]Qux[/]")
.AddRow("[invert underline]Corgi[/]", "[bold strikethrough]Waldo[/]", "[dim]Zap[/]")
.AddRow(new Panel("[blue]Hello World[/]")

View File

@ -25,7 +25,7 @@ namespace Spectre.Console.Tests.Unit
console.Pipeline.Attach(new HelloRenderHook());
// When
console.Render(new Text("World"));
console.Write(new Text("World"));
// Then
console.Lines[0].ShouldBe("Hello");

View File

@ -28,7 +28,7 @@ namespace Spectre.Console.Tests.Unit
});
// When
console.Render(rows);
console.Write(rows);
// Then
return Verifier.Verify(console.Output);
@ -51,7 +51,7 @@ namespace Spectre.Console.Tests.Unit
}), new Text("Qux"));
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -74,7 +74,7 @@ namespace Spectre.Console.Tests.Unit
}).Expand(), new Text("Qux"));
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);

View File

@ -19,7 +19,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 40);
// When
console.Render(new Rule());
console.Write(new Rule());
// Then
return Verifier.Verify(console.Output);
@ -33,7 +33,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 40);
// When
console.Render(new Rule().DoubleBorder());
console.Write(new Rule().DoubleBorder());
// Then
return Verifier.Verify(console.Output);
@ -47,7 +47,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 40);
// When
console.Render(new Rule("Hello World").DoubleBorder());
console.Write(new Rule("Hello World").DoubleBorder());
// Then
return Verifier.Verify(console.Output);
@ -61,7 +61,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 40);
// When
console.Render(new Rule("Hello World"));
console.Write(new Rule("Hello World"));
// Then
return Verifier.Verify(console.Output);
@ -75,7 +75,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 40);
// When
console.Render(new Rule("Hello World")
console.Write(new Rule("Hello World")
{
Alignment = Justify.Left,
});
@ -92,7 +92,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 40);
// When
console.Render(new Rule("Hello World")
console.Write(new Rule("Hello World")
{
Alignment = Justify.Right,
});
@ -109,7 +109,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 40);
// When
console.Render(new Rule("Hello\nWorld\r\n!"));
console.Write(new Rule("Hello\nWorld\r\n!"));
// Then
return Verifier.Verify(console.Output);
@ -123,7 +123,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 40);
// When
console.Render(new Rule(" Hello World "));
console.Write(new Rule(" Hello World "));
// Then
return Verifier.Verify(console.Output);
@ -149,7 +149,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width);
// When
console.Render(new Rule(input));
console.Write(new Rule(input));
// Then
console.Lines.Count.ShouldBe(1);

View File

@ -1,4 +1,3 @@
using System.Text;
using System.Threading.Tasks;
using Shouldly;
using Spectre.Console.Rendering;
@ -39,11 +38,10 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var style = new Style(Color.Red, Color.Green, Decoration.Bold);
var context = new RenderContext(Encoding.UTF8, false);
var segment = new Segment(text, style);
// When
var (first, second) = segment.Split(context, offset);
var (first, second) = segment.Split(offset);
// Then
first.Text.ShouldBe(expectedFirst);
@ -60,10 +58,8 @@ namespace Spectre.Console.Tests.Unit
[Expectation("Segment", "Split")]
public Task Should_Split_Segment()
{
var context = new RenderContext(Encoding.UTF8, false);
// Given, When
var lines = Segment.SplitLines(
context,
new[]
{
new Segment("Foo"),
@ -95,9 +91,8 @@ namespace Spectre.Console.Tests.Unit
[Expectation("Segment", "Split_Linebreak")]
public Task Should_Split_Segments_With_Linebreak_In_Text()
{
var context = new RenderContext(Encoding.UTF8, false);
// Given, Given
var lines = Segment.SplitLines(
context,
new[]
{
new Segment("Foo\n"),

View File

@ -47,7 +47,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().NoBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -89,7 +89,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().AsciiBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -131,7 +131,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().Ascii2Border();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -173,7 +173,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().AsciiDoubleHeadBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -215,7 +215,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().SquareBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -257,7 +257,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().RoundedBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -299,7 +299,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().MinimalBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -341,7 +341,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().MinimalHeavyHeadBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -383,7 +383,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().MinimalDoubleHeadBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -425,7 +425,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().SimpleBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -467,7 +467,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().HorizontalBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -509,7 +509,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().SimpleHeavyBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -551,7 +551,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().HeavyBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -593,7 +593,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().HeavyEdgeBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -635,7 +635,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().HeavyHeadBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -677,7 +677,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().DoubleBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -719,7 +719,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().DoubleEdgeBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -761,7 +761,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable().MarkdownBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -776,7 +776,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable(header2: Justify.Left).MarkdownBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -791,7 +791,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable(header2: Justify.Center).MarkdownBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -806,7 +806,7 @@ namespace Spectre.Console.Tests.Unit
var table = Fixture.GetTable(header2: Justify.Right).MarkdownBorder();
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);

View File

@ -139,7 +139,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -158,7 +158,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -178,7 +178,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -197,7 +197,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -216,7 +216,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -235,7 +235,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -255,7 +255,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// Render a table in some panels.
console.Render(new Panel(new Panel(table)
console.Write(new Panel(new Panel(table)
{
Border = BoxBorder.Ascii,
}));
@ -278,7 +278,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Lorem ipsum dolor sit amet");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -296,7 +296,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -314,7 +314,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -333,7 +333,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -350,7 +350,7 @@ namespace Spectre.Console.Tests.Unit
table.AddColumn(new TableColumn("Baz") { Padding = new Padding(3, 0, 2, 0) });
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -388,7 +388,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow(new Markup("[blue]Hej[/]"), new Markup("[yellow]Världen[/]"), Text.Empty);
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -408,7 +408,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -429,7 +429,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -450,7 +450,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);
@ -471,7 +471,7 @@ namespace Spectre.Console.Tests.Unit
table.AddRow("Grault", "Garply", "Fred");
// When
console.Render(table);
console.Write(table);
// Then
return Verifier.Verify(console.Output);

View File

@ -1,4 +1,3 @@
using System.Text;
using Shouldly;
using Spectre.Console.Rendering;
using Spectre.Console.Testing;
@ -12,10 +11,11 @@ namespace Spectre.Console.Tests.Unit
public void Should_Consider_The_Longest_Word_As_Minimum_Width()
{
// Given
var caps = new FakeCapabilities { Unicode = true };
var text = new Text("Foo Bar Baz\nQux\nLol mobile");
// When
var result = ((IRenderable)text).Measure(new RenderContext(Encoding.Unicode, false), 80);
var result = ((IRenderable)text).Measure(new RenderContext(caps), 80);
// Then
result.Min.ShouldBe(6);
@ -25,10 +25,11 @@ namespace Spectre.Console.Tests.Unit
public void Should_Consider_The_Longest_Line_As_Maximum_Width()
{
// Given
var caps = new FakeCapabilities { Unicode = true };
var text = new Text("Foo Bar Baz\nQux\nLol mobile");
// When
var result = ((IRenderable)text).Measure(new RenderContext(Encoding.Unicode, false), 80);
var result = ((IRenderable)text).Measure(new RenderContext(caps), 80);
// Then
result.Max.ShouldBe(11);
@ -42,7 +43,7 @@ namespace Spectre.Console.Tests.Unit
var text = new Text("Hello World");
// When
console.Render(text);
console.Write(text);
// Then
console.Output.ShouldBe("Hello World");
@ -58,7 +59,7 @@ namespace Spectre.Console.Tests.Unit
var text = new Text(input);
// When
console.Render(text);
console.Write(text);
// Then
console.Output.ShouldBe("Hello\n\nWorld\n\n");
@ -71,7 +72,7 @@ namespace Spectre.Console.Tests.Unit
var console = new FakeConsole(width: 80);
// When
console.Render(new Markup("[b]Hello World[/]\n[yellow]Hello World[/]"));
console.Write(new Markup("[b]Hello World[/]\n[yellow]Hello World[/]"));
// Then
console.Lines.Count.ShouldBe(2);
@ -90,7 +91,7 @@ namespace Spectre.Console.Tests.Unit
var text = new Text(input);
// When
console.Render(text);
console.Write(text);
// Then
console.Output
@ -110,7 +111,7 @@ namespace Spectre.Console.Tests.Unit
.Overflow(overflow);
// When
console.Render(text);
console.Write(text);
// Then
console.Output

View File

@ -37,7 +37,7 @@ namespace Spectre.Console.Tests.Unit
tree.AddNode("child4");
// When
console.Render(tree);
console.Write(tree);
// Then
return Verifier.Verify(console.Output);
@ -52,7 +52,7 @@ namespace Spectre.Console.Tests.Unit
var tree = new Tree(new Text("Root node"));
// When
console.Render(tree);
console.Write(tree);
// Then
return Verifier.Verify(console.Output);
@ -76,7 +76,7 @@ namespace Spectre.Console.Tests.Unit
tree.AddNodes(root);
// When
var result = Record.Exception(() => console.Render(tree));
var result = Record.Exception(() => console.Write(tree));
// Then
result.ShouldBeOfType<CircularTreeException>();

View File

@ -34,9 +34,9 @@ namespace Spectre.Console
}
/// <summary>
/// Exports all recorded console output as HTML.
/// Exports all recorded console output as HTML text.
/// </summary>
/// <returns>The recorded output as HTML.</returns>
/// <returns>The recorded output as HTML text.</returns>
public static string ExportHtml()
{
if (_recorder == null)

View File

@ -1,3 +1,4 @@
using System;
using Spectre.Console.Rendering;
namespace Spectre.Console
@ -13,7 +14,12 @@ namespace Spectre.Console
/// <param name="renderable">The object to render.</param>
public static void Render(IRenderable renderable)
{
Console.Render(renderable);
if (renderable is null)
{
throw new ArgumentNullException(nameof(renderable));
}
Console.Write(renderable);
}
}
}

View File

@ -14,7 +14,7 @@ namespace Spectre.Console
/// <param name="value">The value to write.</param>
public static void Write(string value)
{
Console.Write(value, CurrentStyle);
Write(value, CurrentStyle);
}
/// <summary>

View File

@ -52,6 +52,7 @@ namespace Spectre.Console
profile.Capabilities.Links = supportsAnsi && !legacyConsole;
profile.Capabilities.Legacy = legacyConsole;
profile.Capabilities.Interactive = interactive;
profile.Capabilities.Unicode = encoding.EncodingName.ContainsExact("Unicode");
// Enrich the profile
ProfileEnricher.Enrich(
@ -95,7 +96,7 @@ namespace Spectre.Console
}
else
{
// Try detecting whether or not this
// Try detecting whether or not this is a legacy console
(_, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), false);
}
}

View File

@ -5,7 +5,7 @@ namespace Spectre.Console
/// <summary>
/// Represents console capabilities.
/// </summary>
public sealed class Capabilities
public sealed class Capabilities : IReadOnlyCapabilities
{
private readonly Profile _profile;
@ -19,11 +19,6 @@ namespace Spectre.Console
/// Gets or sets a value indicating whether or not
/// the console support links.
/// </summary>
/// <remarks>
/// There is probably a lot of room for improvement here
/// once we have more information about the terminal
/// we're running inside.
/// </remarks>
public bool Links { get; set; }
/// <summary>
@ -37,8 +32,8 @@ namespace Spectre.Console
public bool Legacy { get; set; }
/// <summary>
/// Gets a value indicating whether console output
/// has been redirected.
/// Gets a value indicating whether or not
/// console output has been redirected.
/// </summary>
public bool Tty
{
@ -65,6 +60,12 @@ namespace Spectre.Console
/// </summary>
public bool Interactive { get; set; }
/// <summary>
/// Gets or sets a value indicating whether
/// or not the console supports Unicode.
/// </summary>
public bool Unicode { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="Capabilities"/> class.
/// </summary>

View File

@ -23,7 +23,7 @@ namespace Spectre.Console.Cli
if (renderable != null)
{
console ??= _console.Value;
console.Render(renderable);
console.Write(renderable);
}
}
@ -34,7 +34,7 @@ namespace Spectre.Console.Cli
{
if (renderable != null)
{
console.Render(renderable);
console.Write(renderable);
}
}
}

View File

@ -8,7 +8,6 @@ namespace Spectre.Console.Enrichment
{
private static readonly List<IProfileEnricher> _defaultEnrichers = new List<IProfileEnricher>
{
new WindowsTerminalEnricher(),
new AppVeyorEnricher(),
new BambooEnricher(),
new BitbucketEnricher(),

View File

@ -1,19 +0,0 @@
using System.Collections.Generic;
namespace Spectre.Console.Enrichment
{
internal sealed class WindowsTerminalEnricher : IProfileEnricher
{
public string Name => "Windows Terminal";
public bool Enabled(IDictionary<string, string> environmentVariables)
{
return environmentVariables.ContainsKey("WT_SESSION");
}
public void Enrich(Profile profile)
{
profile.Capabilities.Links = true;
}
}
}

View File

@ -15,7 +15,7 @@ namespace Spectre.Console
/// <param name="format">The exception format options.</param>
public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionFormats format = ExceptionFormats.Default)
{
Render(console, exception.GetRenderable(format));
console.Write(exception.GetRenderable(format));
}
/// <summary>
@ -26,7 +26,7 @@ namespace Spectre.Console
/// <param name="settings">The exception settings.</param>
public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionSettings settings)
{
Render(console, exception.GetRenderable(settings));
console.Write(exception.GetRenderable(settings));
}
}
}

View File

@ -38,7 +38,7 @@ namespace Spectre.Console
/// <param name="value">The value to write.</param>
public static void Markup(this IAnsiConsole console, string value)
{
console.Render(MarkupParser.Parse(value));
console.Write(MarkupParser.Parse(value));
}
/// <summary>

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using Spectre.Console.Rendering;
namespace Spectre.Console
@ -14,6 +13,7 @@ namespace Spectre.Console
/// </summary>
/// <param name="console">The console to render to.</param>
/// <param name="renderable">The object to render.</param>
[Obsolete("Consider using IAnsiConsole.Write instead.")]
public static void Render(this IAnsiConsole console, IRenderable renderable)
{
if (console is null)
@ -26,21 +26,7 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(renderable));
}
var context = new RenderContext(console.Profile.Encoding, console.Profile.Capabilities.Legacy);
var renderables = console.Pipeline.Process(context, new[] { renderable });
Render(console, context, renderables);
}
private static void Render(IAnsiConsole console, RenderContext options, IEnumerable<IRenderable> renderables)
{
var result = new List<Segment>();
foreach (var renderable in renderables)
{
result.AddRange(renderable.Render(options, console.Profile.Width));
}
console.Write(Segment.Merge(result));
console.Write(renderable);
}
}
}

View File

@ -1,5 +1,4 @@
using System;
using Spectre.Console.Rendering;
namespace Spectre.Console
{
@ -18,26 +17,6 @@ namespace Spectre.Console
return new Recorder(console);
}
/// <summary>
/// Writes the specified string value to the console.
/// </summary>
/// <param name="console">The console to write to.</param>
/// <param name="segment">The segment to write.</param>
public static void Write(this IAnsiConsole console, Segment segment)
{
if (console is null)
{
throw new ArgumentNullException(nameof(console));
}
if (segment is null)
{
throw new ArgumentNullException(nameof(segment));
}
console.Write(new[] { segment });
}
/// <summary>
/// Writes the specified string value to the console.
/// </summary>
@ -45,7 +24,7 @@ namespace Spectre.Console
/// <param name="text">The text to write.</param>
public static void Write(this IAnsiConsole console, string text)
{
Render(console, new Text(text, Style.Plain));
console.Write(new Text(text, Style.Plain));
}
/// <summary>
@ -56,7 +35,7 @@ namespace Spectre.Console
/// <param name="style">The text style.</param>
public static void Write(this IAnsiConsole console, string text, Style style)
{
Render(console, new Text(text, style));
console.Write(new Text(text, style));
}
/// <summary>
@ -70,7 +49,7 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(console));
}
Render(console, new Text(Environment.NewLine, Style.Plain));
console.Write(new Text(Environment.NewLine, Style.Plain));
}
/// <summary>

View File

@ -1,4 +1,5 @@
using System;
using Spectre.Console.Internal;
namespace Spectre.Console
{

View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using Spectre.Console.Rendering;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="IRenderable"/>.
/// </summary>
public static class RenderableExtensions
{
/// <summary>
/// Gets the segments for a renderable using the specified console.
/// </summary>
/// <param name="renderable">The renderable.</param>
/// <param name="console">The console.</param>
/// <returns>An enumerable containing segments representing the specified <see cref="IRenderable"/>.</returns>
public static IEnumerable<Segment> GetSegments(this IRenderable renderable, IAnsiConsole console)
{
if (console is null)
{
throw new ArgumentNullException(nameof(console));
}
if (renderable is null)
{
throw new ArgumentNullException(nameof(renderable));
}
var context = new RenderContext(console.Profile.Capabilities);
var renderables = console.Pipeline.Process(context, new[] { renderable });
return GetSegments(console, context, renderables);
}
private static IEnumerable<Segment> GetSegments(IAnsiConsole console, RenderContext options, IEnumerable<IRenderable> renderables)
{
var result = new List<Segment>();
foreach (var renderable in renderables)
{
result.AddRange(renderable.Render(options, console.Profile.Width));
}
return Segment.Merge(result);
}
}
}

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Spectre.Console.Rendering;
namespace Spectre.Console
{
@ -60,14 +59,9 @@ namespace Spectre.Console
return result.ToString();
}
internal static int CellLength(this string text, RenderContext context)
internal static int CellLength(this string text)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return Cell.GetCellLength(context, text);
return Cell.GetCellLength(text);
}
internal static string CapitalizeFirstLetter(this string? text, CultureInfo? culture = null)

View File

@ -1,4 +1,3 @@
using System.Collections.Generic;
using Spectre.Console.Rendering;
namespace Spectre.Console
@ -40,9 +39,9 @@ namespace Spectre.Console
void Clear(bool home);
/// <summary>
/// Writes multiple segments to the console.
/// Writes a <see cref="IRenderable"/> to the console.
/// </summary>
/// <param name="segments">The segments to write.</param>
void Write(IEnumerable<Segment> segments);
/// <param name="renderable">The <see cref="IRenderable"/> to write.</param>
void Write(IRenderable renderable);
}
}

View File

@ -0,0 +1,48 @@
namespace Spectre.Console
{
/// <summary>
/// Represents (read-only) console capabilities.
/// </summary>
public interface IReadOnlyCapabilities
{
/// <summary>
/// Gets a value indicating whether or not
/// the console supports Ansi.
/// </summary>
bool Ansi { get; }
/// <summary>
/// Gets a value indicating whether or not
/// the console support links.
/// </summary>
bool Links { get; }
/// <summary>
/// Gets a value indicating whether or not
/// this is a legacy console (cmd.exe) on an OS
/// prior to Windows 10.
/// </summary>
/// <remarks>
/// Only relevant when running on Microsoft Windows.
/// </remarks>
bool Legacy { get; }
/// <summary>
/// Gets a value indicating whether or not
/// console output has been redirected.
/// </summary>
bool Tty { get; }
/// <summary>
/// Gets a value indicating whether
/// or not the console supports interaction.
/// </summary>
bool Interactive { get; }
/// <summary>
/// Gets a value indicating whether
/// or not the console supports Unicode.
/// </summary>
bool Unicode { get; }
}
}

View File

@ -6,14 +6,14 @@ namespace Spectre.Console
{
internal static class Aligner
{
public static string Align(RenderContext context, string text, Justify? alignment, int maxWidth)
public static string Align(string text, Justify? alignment, int maxWidth)
{
if (alignment == null || alignment == Justify.Left)
{
return text;
}
var width = Cell.GetCellLength(context, text);
var width = Cell.GetCellLength(text);
if (width >= maxWidth)
{
return text;
@ -57,7 +57,7 @@ namespace Spectre.Console
return;
}
var width = Segment.CellCount(context, segments);
var width = Segment.CellCount(segments);
if (width >= maxWidth)
{
return;

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using Spectre.Console.Rendering;
@ -8,21 +7,21 @@ namespace Spectre.Console
internal sealed class AnsiConsoleBackend : IAnsiConsoleBackend
{
private readonly AnsiBuilder _builder;
private readonly Profile _profile;
private readonly IAnsiConsole _console;
public IAnsiConsoleCursor Cursor { get; }
public AnsiConsoleBackend(Profile profile)
public AnsiConsoleBackend(IAnsiConsole console)
{
_profile = profile ?? throw new ArgumentNullException(nameof(profile));
_builder = new AnsiBuilder(profile);
_console = console ?? throw new ArgumentNullException(nameof(console));
_builder = new AnsiBuilder(_console.Profile);
Cursor = new AnsiConsoleCursor(this);
}
public void Clear(bool home)
{
Render(new[] { Segment.Control("\u001b[2J") });
Write(new ControlSequence("\u001b[2J"));
if (home)
{
@ -30,10 +29,10 @@ namespace Spectre.Console
}
}
public void Render(IEnumerable<Segment> segments)
public void Write(IRenderable renderable)
{
var builder = new StringBuilder();
foreach (var segment in segments)
foreach (var segment in renderable.GetSegments(_console))
{
if (segment.IsControlCode)
{
@ -58,8 +57,8 @@ namespace Spectre.Console
if (builder.Length > 0)
{
_profile.Out.Write(builder.ToString());
_profile.Out.Flush();
_console.Profile.Out.Write(builder.ToString());
_console.Profile.Out.Flush();
}
}
}

View File

@ -1,5 +1,4 @@
using System;
using Spectre.Console.Rendering;
namespace Spectre.Console
{
@ -16,11 +15,11 @@ namespace Spectre.Console
{
if (show)
{
_backend.Render(new[] { Segment.Control("\u001b[?25h") });
_backend.Write(new ControlSequence("\u001b[?25h"));
}
else
{
_backend.Render(new[] { Segment.Control("\u001b[?25l") });
_backend.Write(new ControlSequence("\u001b[?25l"));
}
}
@ -34,23 +33,23 @@ namespace Spectre.Console
switch (direction)
{
case CursorDirection.Up:
_backend.Render(new[] { Segment.Control($"\u001b[{steps}A") });
_backend.Write(new ControlSequence($"\u001b[{steps}A"));
break;
case CursorDirection.Down:
_backend.Render(new[] { Segment.Control($"\u001b[{steps}B") });
_backend.Write(new ControlSequence($"\u001b[{steps}B"));
break;
case CursorDirection.Right:
_backend.Render(new[] { Segment.Control($"\u001b[{steps}C") });
_backend.Write(new ControlSequence($"\u001b[{steps}C"));
break;
case CursorDirection.Left:
_backend.Render(new[] { Segment.Control($"\u001b[{steps}D") });
_backend.Write(new ControlSequence($"\u001b[{steps}D"));
break;
}
}
public void SetPosition(int column, int line)
{
_backend.Render(new[] { Segment.Control($"\u001b[{line};{column}H") });
_backend.Write(new ControlSequence($"\u001b[{line};{column}H"));
}
}
}

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using Spectre.Console.Rendering;
namespace Spectre.Console
@ -19,13 +18,14 @@ namespace Spectre.Console
public AnsiConsoleFacade(Profile profile, IExclusivityMode exclusivityMode)
{
_renderLock = new object();
_ansiBackend = new AnsiConsoleBackend(profile);
_legacyBackend = new LegacyConsoleBackend(profile);
Profile = profile ?? throw new ArgumentNullException(nameof(profile));
Input = new DefaultInput(Profile);
ExclusivityMode = exclusivityMode ?? throw new ArgumentNullException(nameof(exclusivityMode));
Pipeline = new RenderPipeline();
_ansiBackend = new AnsiConsoleBackend(this);
_legacyBackend = new LegacyConsoleBackend(this);
}
public void Clear(bool home)
@ -36,11 +36,11 @@ namespace Spectre.Console
}
}
public void Write(IEnumerable<Segment> segments)
public void Write(IRenderable renderable)
{
lock (_renderLock)
{
GetBackend().Render(segments);
GetBackend().Write(renderable);
}
}

View File

@ -1,4 +1,3 @@
using System.Collections.Generic;
using Spectre.Console.Rendering;
namespace Spectre.Console
@ -20,9 +19,9 @@ namespace Spectre.Console
void Clear(bool home);
/// <summary>
/// Renders segments to the console.
/// Writes a <see cref="IRenderable"/> to the console backend.
/// </summary>
/// <param name="segments">The segments to render.</param>
void Render(IEnumerable<Segment> segments);
/// <param name="renderable">The <see cref="IRenderable"/> to write.</param>
void Write(IRenderable renderable);
}
}

View File

@ -1,18 +1,17 @@
using System.Collections.Generic;
using Spectre.Console.Rendering;
namespace Spectre.Console
{
internal sealed class LegacyConsoleBackend : IAnsiConsoleBackend
{
private readonly Profile _profile;
private readonly IAnsiConsole _console;
private Style _lastStyle;
public IAnsiConsoleCursor Cursor { get; }
public LegacyConsoleBackend(Profile profile)
public LegacyConsoleBackend(IAnsiConsole console)
{
_profile = profile ?? throw new System.ArgumentNullException(nameof(profile));
_console = console ?? throw new System.ArgumentNullException(nameof(console));
_lastStyle = Style.Plain;
Cursor = new LegacyConsoleCursor();
@ -31,9 +30,9 @@ namespace Spectre.Console
}
}
public void Render(IEnumerable<Segment> segments)
public void Write(IRenderable renderable)
{
foreach (var segment in segments)
foreach (var segment in renderable.GetSegments(_console))
{
if (segment.IsControlCode)
{
@ -45,7 +44,7 @@ namespace Spectre.Console
SetStyle(segment.Style);
}
_profile.Out.Write(segment.Text.NormalizeNewLines(native: true));
_console.Profile.Out.Write(segment.Text.NormalizeNewLines(native: true));
}
}
@ -56,13 +55,13 @@ namespace Spectre.Console
System.Console.ResetColor();
var background = Color.ToConsoleColor(style.Background);
if (_profile.ColorSystem != ColorSystem.NoColors && (int)background != -1)
if (_console.Profile.ColorSystem != ColorSystem.NoColors && (int)background != -1)
{
System.Console.BackgroundColor = background;
}
var foreground = Color.ToConsoleColor(style.Foreground);
if (_profile.ColorSystem != ColorSystem.NoColors && (int)foreground != -1)
if (_console.Profile.ColorSystem != ColorSystem.NoColors && (int)foreground != -1)
{
System.Console.ForegroundColor = foreground;
}

View File

@ -1,34 +1,22 @@
using Spectre.Console.Rendering;
using Wcwidth;
namespace Spectre.Console
{
internal static class Cell
{
public static int GetCellLength(RenderContext context, string text)
public static int GetCellLength(string text)
{
var sum = 0;
foreach (var rune in text)
{
sum += GetCellLength(context, rune);
sum += GetCellLength(rune);
}
return sum;
}
public static int GetCellLength(RenderContext context, char rune)
public static int GetCellLength(char rune)
{
if (context.LegacyConsole)
{
// Is it represented by a single byte?
// In that case we don't have to calculate the
// actual cell width.
if (context.Encoding.GetByteCount(new[] { rune }) == 1)
{
return 1;
}
}
// TODO: We need to figure out why Segment.SplitLines fails
// if we let wcwidth (which returns -1 instead of 1)
// calculate the size for new line characters.

View File

@ -3,52 +3,57 @@ using System.Collections.Generic;
using System.Text;
using Spectre.Console.Rendering;
namespace Spectre.Console
namespace Spectre.Console.Internal
{
internal sealed class HtmlEncoder : IAnsiConsoleEncoder
{
public string Encode(IEnumerable<Segment> segments)
public string Encode(IAnsiConsole console, IEnumerable<IRenderable> renderables)
{
var context = new RenderContext(EncoderCapabilities.Default);
var builder = new StringBuilder();
builder.Append("<pre style=\"font-size:90%;font-family:consolas,'Courier New',monospace\">\n");
foreach (var (_, first, _, segment) in segments.Enumerate())
foreach (var renderable in renderables)
{
if (segment.IsControlCode)
var segments = renderable.Render(context, console.Profile.Width);
foreach (var (_, first, _, segment) in segments.Enumerate())
{
continue;
}
if (segment.Text == "\n" && !first)
{
builder.Append('\n');
continue;
}
var parts = segment.Text.Split(new[] { '\n' }, StringSplitOptions.None);
foreach (var (_, _, last, line) in parts.Enumerate())
{
if (string.IsNullOrEmpty(line))
if (segment.IsControlCode)
{
continue;
}
builder.Append("<span");
if (!segment.Style.Equals(Style.Plain))
{
builder.Append(" style=\"");
builder.Append(BuildCss(segment.Style));
builder.Append('"');
}
builder.Append('>');
builder.Append(line);
builder.Append("</span>");
if (parts.Length > 1 && !last)
if (segment.Text == "\n" && !first)
{
builder.Append('\n');
continue;
}
var parts = segment.Text.Split(new[] { '\n' }, StringSplitOptions.None);
foreach (var (_, _, last, line) in parts.Enumerate())
{
if (string.IsNullOrEmpty(line))
{
continue;
}
builder.Append("<span");
if (!segment.Style.Equals(Style.Plain))
{
builder.Append(" style=\"");
builder.Append(BuildCss(segment.Style));
builder.Append('"');
}
builder.Append('>');
builder.Append(line);
builder.Append("</span>");
if (parts.Length > 1 && !last)
{
builder.Append('\n');
}
}
}
}

View File

@ -2,22 +2,39 @@ using System.Collections.Generic;
using System.Text;
using Spectre.Console.Rendering;
namespace Spectre.Console
namespace Spectre.Console.Internal
{
internal sealed class EncoderCapabilities : IReadOnlyCapabilities
{
public bool Ansi => false;
public bool Links => false;
public bool Legacy => false;
public bool Tty => false;
public bool Interactive => false;
public bool Unicode => true;
public static EncoderCapabilities Default { get; } = new EncoderCapabilities();
}
internal sealed class TextEncoder : IAnsiConsoleEncoder
{
public string Encode(IEnumerable<Segment> segments)
public string Encode(IAnsiConsole console, IEnumerable<IRenderable> renderables)
{
var context = new RenderContext(EncoderCapabilities.Default);
var builder = new StringBuilder();
foreach (var segment in Segment.Merge(segments))
foreach (var renderable in renderables)
{
if (segment.IsControlCode)
var segments = renderable.Render(context, console.Profile.Width);
foreach (var segment in Segment.Merge(segments))
{
continue;
}
if (segment.IsControlCode)
{
continue;
}
builder.Append(segment.Text);
builder.Append(segment.Text);
}
}
return builder.ToString().TrimEnd('\n');

View File

@ -43,12 +43,7 @@ namespace Spectre.Console
get => _out;
set
{
if (value == null)
{
throw new InvalidOperationException("Output buffer cannot be null");
}
_out = value;
_out = value ?? throw new InvalidOperationException("Output buffer cannot be null");
// Reset the width and height if not a TTY.
if (!Capabilities.Tty)
@ -129,12 +124,7 @@ namespace Spectre.Console
get => _capabilities;
set
{
if (value == null)
{
throw new InvalidOperationException("Profile capabilities cannot be null");
}
_capabilities = value;
_capabilities = value ?? throw new InvalidOperationException("Profile capabilities cannot be null");
}
}

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Spectre.Console.Rendering;
namespace Spectre.Console
@ -12,7 +11,7 @@ namespace Spectre.Console
public class Recorder : IAnsiConsole, IDisposable
{
private readonly IAnsiConsole _console;
private readonly List<Segment> _recorded;
private readonly List<IRenderable> _recorded;
/// <inheritdoc/>
public Profile Profile => _console.Profile;
@ -29,11 +28,6 @@ namespace Spectre.Console
/// <inheritdoc/>
public RenderPipeline Pipeline => _console.Pipeline;
/// <summary>
/// Gets a list containing all recorded segments.
/// </summary>
protected List<Segment> Recorded => _recorded;
/// <summary>
/// Initializes a new instance of the <see cref="Recorder"/> class.
/// </summary>
@ -41,7 +35,7 @@ namespace Spectre.Console
public Recorder(IAnsiConsole console)
{
_console = console ?? throw new ArgumentNullException(nameof(console));
_recorded = new List<Segment>();
_recorded = new List<IRenderable>();
}
/// <inheritdoc/>
@ -58,34 +52,25 @@ namespace Spectre.Console
}
/// <inheritdoc/>
public void Write(IEnumerable<Segment> segments)
public void Write(IRenderable renderable)
{
if (segments is null)
if (renderable is null)
{
throw new ArgumentNullException(nameof(segments));
throw new ArgumentNullException(nameof(renderable));
}
Record(segments);
_recorded.Add(renderable);
_console.Write(segments);
_console.Write(renderable);
}
internal Recorder Clone(IAnsiConsole console)
{
var recorder = new Recorder(console);
recorder.Recorded.AddRange(Recorded);
recorder._recorded.AddRange(_recorded);
return recorder;
}
/// <summary>
/// Records the specified segments.
/// </summary>
/// <param name="segments">The segments to be recorded.</param>
protected virtual void Record(IEnumerable<Segment> segments)
{
Recorded.AddRange(segments.Where(s => !s.IsControlCode));
}
/// <summary>
/// Exports the recorded data.
/// </summary>
@ -98,7 +83,7 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(encoder));
}
return encoder.Encode(_recorded);
return encoder.Encode(_console, _recorded);
}
}
}

View File

@ -9,10 +9,11 @@ namespace Spectre.Console.Rendering
public interface IAnsiConsoleEncoder
{
/// <summary>
/// Encodes the specified segments.
/// Encodes the specified <see cref="IRenderable"/> enumerator.
/// </summary>
/// <param name="segments">The segments to encode.</param>
/// <returns>The encoded string.</returns>
string Encode(IEnumerable<Segment> segments);
/// <param name="console">The console to use when encoding.</param>
/// <param name="renderable">The renderable objects to encode.</param>
/// <returns>A string representing the encoded result.</returns>
string Encode(IAnsiConsole console, IEnumerable<IRenderable> renderable);
}
}

View File

@ -51,7 +51,7 @@ namespace Spectre.Console.Rendering
if (_renderable != null)
{
var segments = _renderable.Render(context, maxWidth);
var lines = Segment.SplitLines(context, segments);
var lines = Segment.SplitLines(segments);
var shape = SegmentShape.Calculate(context, lines);
_shape = _shape == null ? shape : _shape.Value.Inflate(shape);

View File

@ -1,4 +1,4 @@
using System.Text;
using System;
namespace Spectre.Console.Rendering
{
@ -7,20 +7,12 @@ namespace Spectre.Console.Rendering
/// </summary>
public sealed class RenderContext
{
/// <summary>
/// Gets the console's output encoding.
/// </summary>
public Encoding Encoding { get; }
/// <summary>
/// Gets a value indicating whether or not this a legacy console (i.e. cmd.exe).
/// </summary>
public bool LegacyConsole { get; }
private readonly IReadOnlyCapabilities _capabilities;
/// <summary>
/// Gets a value indicating whether or not unicode is supported.
/// </summary>
public bool Unicode { get; }
public bool Unicode => _capabilities.Unicode;
/// <summary>
/// Gets the current justification.
@ -36,20 +28,18 @@ namespace Spectre.Console.Rendering
/// <summary>
/// Initializes a new instance of the <see cref="RenderContext"/> class.
/// </summary>
/// <param name="encoding">The console's output encoding.</param>
/// <param name="legacyConsole">A value indicating whether or not this a legacy console (i.e. cmd.exe).</param>
/// <param name="justification">The justification to use when rendering.</param>
public RenderContext(Encoding encoding, bool legacyConsole, Justify? justification = null)
: this(encoding, legacyConsole, justification, false)
/// <param name="capabilities">The capabilities.</param>
/// <param name="justification">The justification.</param>
public RenderContext(IReadOnlyCapabilities capabilities, Justify? justification = null)
: this(capabilities, justification, false)
{
}
private RenderContext(Encoding encoding, bool legacyConsole, Justify? justification = null, bool singleLine = false)
private RenderContext(IReadOnlyCapabilities capabilities, Justify? justification = null, bool singleLine = false)
{
Encoding = encoding ?? throw new System.ArgumentNullException(nameof(encoding));
LegacyConsole = legacyConsole;
_capabilities = capabilities ?? throw new ArgumentNullException(nameof(capabilities));
Justification = justification;
Unicode = Encoding.EncodingName.ContainsExact("Unicode");
SingleLine = singleLine;
}
@ -60,7 +50,7 @@ namespace Spectre.Console.Rendering
/// <returns>A new <see cref="RenderContext"/> instance.</returns>
public RenderContext WithJustification(Justify? justification)
{
return new RenderContext(Encoding, LegacyConsole, justification);
return new RenderContext(_capabilities, justification, SingleLine);
}
/// <summary>
@ -75,7 +65,7 @@ namespace Spectre.Console.Rendering
/// <returns>A new <see cref="RenderContext"/> instance.</returns>
internal RenderContext WithSingleLine()
{
return new RenderContext(Encoding, LegacyConsole, Justification, true);
return new RenderContext(_capabilities, Justification, true);
}
}
}

View File

@ -100,36 +100,24 @@ namespace Spectre.Console.Rendering
/// Gets the number of cells that this segment
/// occupies in the console.
/// </summary>
/// <param name="context">The render context.</param>
/// <returns>The number of cells that this segment occupies in the console.</returns>
public int CellCount(RenderContext context)
public int CellCount()
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (IsControlCode)
{
return 0;
}
return Text.CellLength(context);
return Cell.GetCellLength(Text);
}
/// <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 CellCount(RenderContext context, IEnumerable<Segment> segments)
public static int CellCount(IEnumerable<Segment> segments)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (segments is null)
{
throw new ArgumentNullException(nameof(segments));
@ -138,7 +126,7 @@ namespace Spectre.Console.Rendering
var sum = 0;
foreach (var segment in segments)
{
sum += segment.CellCount(context);
sum += segment.CellCount();
}
return sum;
@ -158,7 +146,6 @@ namespace Spectre.Console.Rendering
/// </summary>
/// <param name="offset">The offset where to split the segment.</param>
/// <returns>One or two new segments representing the split.</returns>
[Obsolete("Use Split(RenderContext, Int32) instead")]
public (Segment First, Segment? Second) Split(int offset)
{
if (offset < 0)
@ -166,30 +153,7 @@ namespace Spectre.Console.Rendering
return (this, null);
}
if (offset >= Text.Length)
{
return (this, null);
}
return (
new Segment(Text.Substring(0, offset), Style),
new Segment(Text.Substring(offset, Text.Length - offset), Style));
}
/// <summary>
/// Splits the segment at the offset.
/// </summary>
/// <param name="context">The render context.</param>
/// <param name="offset">The offset where to split the segment.</param>
/// <returns>One or two new segments representing the split.</returns>
public (Segment First, Segment? Second) Split(RenderContext context, int offset)
{
if (offset < 0)
{
return (this, null);
}
if (offset >= CellCount(context))
if (offset >= CellCount())
{
return (this, null);
}
@ -201,7 +165,7 @@ namespace Spectre.Console.Rendering
foreach (var character in Text)
{
index++;
accumulated += Cell.GetCellLength(context, character);
accumulated += Cell.GetCellLength(character);
if (accumulated >= offset)
{
break;
@ -226,38 +190,26 @@ namespace Spectre.Console.Rendering
/// <summary>
/// Splits the provided segments into lines.
/// </summary>
/// <param name="context">The render context.</param>
/// <param name="segments">The segments to split.</param>
/// <returns>A collection of lines.</returns>
public static List<SegmentLine> SplitLines(RenderContext context, IEnumerable<Segment> segments)
public static List<SegmentLine> SplitLines(IEnumerable<Segment> segments)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (segments is null)
{
throw new ArgumentNullException(nameof(segments));
}
return SplitLines(context, segments, int.MaxValue);
return SplitLines(segments, int.MaxValue);
}
/// <summary>
/// Splits the provided segments into lines with a maximum width.
/// </summary>
/// <param name="context">The render context.</param>
/// <param name="segments">The segments to split into lines.</param>
/// <param name="maxWidth">The maximum width.</param>
/// <returns>A list of lines.</returns>
public static List<SegmentLine> SplitLines(RenderContext context, IEnumerable<Segment> segments, int maxWidth)
public static List<SegmentLine> SplitLines(IEnumerable<Segment> segments, int maxWidth)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (segments is null)
{
throw new ArgumentNullException(nameof(segments));
@ -271,16 +223,16 @@ namespace Spectre.Console.Rendering
while (stack.Count > 0)
{
var segment = stack.Pop();
var segmentLength = segment.CellCount(context);
var segmentLength = segment.CellCount();
// Does this segment make the line exceed the max width?
var lineLength = line.CellCount(context);
var lineLength = line.CellCount();
if (lineLength + segmentLength > maxWidth)
{
var diff = -(maxWidth - (lineLength + segmentLength));
var offset = segment.Text.Length - diff;
var (first, second) = segment.Split(context, offset);
var (first, second) = segment.Split(offset);
line.Add(first);
lines.Add(line);
@ -356,22 +308,16 @@ namespace Spectre.Console.Rendering
/// </summary>
/// <param name="segment">The segment to split.</param>
/// <param name="overflow">The overflow strategy to use.</param>
/// <param name="context">The render context.</param>
/// <param name="maxWidth">The maximum width.</param>
/// <returns>A list of segments that has been split.</returns>
public static List<Segment> SplitOverflow(Segment segment, Overflow? overflow, RenderContext context, int maxWidth)
public static List<Segment> SplitOverflow(Segment segment, Overflow? overflow, int maxWidth)
{
if (segment is null)
{
throw new ArgumentNullException(nameof(segment));
}
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (segment.CellCount(context) <= maxWidth)
if (segment.CellCount() <= maxWidth)
{
return new List<Segment>(1) { segment };
}
@ -383,7 +329,7 @@ namespace Spectre.Console.Rendering
if (overflow == Overflow.Fold)
{
var totalLength = segment.Text.CellLength(context);
var totalLength = segment.Text.CellLength();
var lengthLeft = totalLength;
while (lengthLeft > 0)
{
@ -431,17 +377,11 @@ namespace Spectre.Console.Rendering
/// <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)
public static List<Segment> Truncate(IEnumerable<Segment> segments, int maxWidth)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (segments is null)
{
throw new ArgumentNullException(nameof(segments));
@ -452,7 +392,7 @@ namespace Spectre.Console.Rendering
var totalWidth = 0;
foreach (var segment in segments)
{
var segmentCellWidth = segment.CellCount(context);
var segmentCellWidth = segment.CellCount();
if (totalWidth + segmentCellWidth > maxWidth)
{
break;
@ -464,7 +404,7 @@ namespace Spectre.Console.Rendering
if (result.Count == 0 && segments.Any())
{
var segment = Truncate(context, segments.First(), maxWidth);
var segment = Truncate(segments.First(), maxWidth);
if (segment != null)
{
result.Add(segment);
@ -477,23 +417,17 @@ namespace Spectre.Console.Rendering
/// <summary>
/// Truncates the segment to the specified width.
/// </summary>
/// <param name="context">The render context.</param>
/// <param name="segment">The segment to truncate.</param>
/// <param name="maxWidth">The maximum width that the segment may occupy.</param>
/// <returns>A new truncated segment, or <c>null</c>.</returns>
public static Segment? Truncate(RenderContext context, Segment? segment, int maxWidth)
public static Segment? Truncate(Segment? segment, int maxWidth)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (segment is null)
{
return null;
}
if (segment.CellCount(context) <= maxWidth)
if (segment.CellCount() <= maxWidth)
{
return segment;
}
@ -501,7 +435,7 @@ namespace Spectre.Console.Rendering
var builder = new StringBuilder();
foreach (var character in segment.Text)
{
var accumulatedCellWidth = builder.ToString().CellLength(context);
var accumulatedCellWidth = builder.ToString().CellLength();
if (accumulatedCellWidth >= maxWidth)
{
break;
@ -562,24 +496,19 @@ namespace Spectre.Console.Rendering
return result;
}
internal static List<Segment> TruncateWithEllipsis(IEnumerable<Segment> segments, RenderContext context, int maxWidth)
internal static List<Segment> TruncateWithEllipsis(IEnumerable<Segment> segments, int maxWidth)
{
if (segments is null)
{
throw new ArgumentNullException(nameof(segments));
}
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (CellCount(context, segments) <= maxWidth)
if (CellCount(segments) <= maxWidth)
{
return new List<Segment>(segments);
}
segments = TrimEnd(Truncate(context, segments, maxWidth - 1));
segments = TrimEnd(Truncate(segments, maxWidth - 1));
if (!segments.Any())
{
return new List<Segment>(1);

View File

@ -16,16 +16,10 @@ namespace Spectre.Console.Rendering
/// <summary>
/// Gets the number of cells the segment line occupies.
/// </summary>
/// <param name="context">The render context.</param>
/// <returns>The cell width of the segment line.</returns>
public int CellCount(RenderContext context)
public int CellCount()
{
if (context is null)
{
throw new System.ArgumentNullException(nameof(context));
}
return Segment.CellCount(context, this);
return Segment.CellCount(this);
}
/// <summary>

View File

@ -28,7 +28,7 @@ namespace Spectre.Console.Rendering
}
var height = lines.Count;
var width = lines.Max(l => Segment.CellCount(context, l));
var width = lines.Max(l => Segment.CellCount(l));
return new SegmentShape(width, height);
}
@ -44,7 +44,7 @@ namespace Spectre.Console.Rendering
{
foreach (var line in lines)
{
var length = Segment.CellCount(context, line);
var length = Segment.CellCount(line);
var missing = Width - length;
if (missing > 0)
{

View File

@ -53,7 +53,7 @@ namespace Spectre.Console
{
var line = new Segment(string.Concat(row.Select(x => x.Lines[index])), style);
var lineWidth = line.CellCount(context);
var lineWidth = line.CellCount();
if (alignment == Justify.Left)
{
yield return line;

View File

@ -70,7 +70,7 @@ namespace Spectre.Console
}
var child = _child.Render(context, maxWidth - paddingWidth);
foreach (var (_, _, _, line) in Segment.SplitLines(context, child).Enumerate())
foreach (var line in Segment.SplitLines(child))
{
// Left padding
if (Padding.GetLeftSafe() != 0)
@ -87,7 +87,7 @@ namespace Spectre.Console
}
// Missing space on right side?
var lineWidth = line.CellCount(context);
var lineWidth = line.CellCount();
var diff = width - lineWidth - Padding.GetLeftSafe() - Padding.GetRightSafe();
if (diff > 0)
{

View File

@ -78,7 +78,7 @@ namespace Spectre.Console
{
var edgeWidth = EdgeWidth;
var border = BoxExtensions.GetSafeBorder(Border, (context.LegacyConsole || !context.Unicode) && UseSafeBorder);
var border = BoxExtensions.GetSafeBorder(Border, !context.Unicode && UseSafeBorder);
var borderStyle = BorderStyle ?? Style.Plain;
var showBorder = true;
@ -110,7 +110,7 @@ namespace Spectre.Console
// Split the child segments into lines.
var childSegments = ((IRenderable)child).Render(context, childWidth);
foreach (var (_, _, last, line) in Segment.SplitLines(context, childSegments, childWidth).Enumerate())
foreach (var (_, _, last, line) in Segment.SplitLines(childSegments, childWidth).Enumerate())
{
if (line.Count == 1 && line[0].IsWhiteSpace)
{
@ -128,7 +128,7 @@ namespace Spectre.Console
content.AddRange(line);
// Do we need to pad the panel?
var length = line.Sum(segment => segment.CellCount(context));
var length = line.Sum(segment => segment.CellCount());
if (length < childWidth)
{
var diff = childWidth - length;

View File

@ -118,8 +118,8 @@ namespace Spectre.Console
return new Measurement(0, 0);
}
var min = _lines.Max(line => line.Max(segment => segment.CellCount(context)));
var max = _lines.Max(x => x.CellCount(context));
var min = _lines.Max(line => line.Max(segment => segment.CellCount()));
var max = _lines.Max(x => x.CellCount());
return new Measurement(min, Math.Min(max, maxWidth));
}
@ -139,7 +139,7 @@ namespace Spectre.Console
var lines = context.SingleLine
? new List<SegmentLine>(_lines)
: SplitLines(context, maxWidth);
: SplitLines(maxWidth);
// Justify lines
var justification = context.Justification ?? Alignment ?? Justify.Left;
@ -178,7 +178,7 @@ namespace Spectre.Console
return result;
}
private List<SegmentLine> SplitLines(RenderContext context, int maxWidth)
private List<SegmentLine> SplitLines(int maxWidth)
{
if (maxWidth <= 0)
{
@ -186,7 +186,7 @@ namespace Spectre.Console
return new List<SegmentLine>();
}
if (_lines.Max(x => x.CellCount(context)) <= maxWidth)
if (_lines.Max(x => x.CellCount()) <= maxWidth)
{
return Clone();
}
@ -230,15 +230,15 @@ namespace Spectre.Console
continue;
}
var length = current.CellCount(context);
var length = current.CellCount();
if (length > maxWidth)
{
// The current segment is longer than the width of the console,
// so we will need to crop it up, into new segments.
var segments = Segment.SplitOverflow(current, Overflow, context, maxWidth);
var segments = Segment.SplitOverflow(current, Overflow, maxWidth);
if (segments.Count > 0)
{
if (line.CellCount(context) + segments[0].CellCount(context) > maxWidth)
if (line.CellCount() + segments[0].CellCount() > maxWidth)
{
lines.Add(line);
line = new SegmentLine();
@ -258,7 +258,7 @@ namespace Spectre.Console
}
else
{
if (line.CellCount(context) + length > maxWidth)
if (line.CellCount() + length > maxWidth)
{
line.Add(Segment.Empty);
lines.Add(line);

View File

@ -101,7 +101,7 @@ namespace Spectre.Console
/// <inheritdoc/>
public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
{
var useAscii = (context.LegacyConsole || !context.Unicode) && _spinner.IsUnicode;
var useAscii = !context.Unicode && _spinner.IsUnicode;
var spinner = useAscii ? Spinner.Known.Ascii : _spinner ?? Spinner.Known.Default;
if (!task.IsStarted)
@ -138,14 +138,14 @@ namespace Spectre.Console
{
if (_maxWidth == null)
{
var useAscii = (context.LegacyConsole || !context.Unicode) && _spinner.IsUnicode;
var useAscii = !context.Unicode && _spinner.IsUnicode;
var spinner = useAscii ? Spinner.Known.Ascii : _spinner ?? Spinner.Known.Default;
_maxWidth = Math.Max(
Math.Max(
((IRenderable)new Markup(PendingText ?? " ")).Measure(context, int.MaxValue).Max,
((IRenderable)new Markup(CompletedText ?? " ")).Measure(context, int.MaxValue).Max),
spinner.Frames.Max(frame => Cell.GetCellLength(context, frame)));
spinner.Frames.Max(frame => Cell.GetCellLength(frame)));
}
return _maxWidth.Value;

View File

@ -52,7 +52,7 @@ namespace Spectre.Console
public void Refresh()
{
_renderer.Update(this);
_console.Render(new ControlSequence(string.Empty));
_console.Write(new ControlSequence(string.Empty));
}
internal IReadOnlyList<ProgressTask> GetTasks()

View File

@ -42,7 +42,7 @@ namespace Spectre.Console
{
if (clear)
{
_console.Render(_live.RestoreCursor());
_console.Write(_live.RestoreCursor());
}
else
{
@ -62,7 +62,7 @@ namespace Spectre.Console
_stopwatch.Start();
}
var renderContext = new RenderContext(_console.Profile.Encoding, _console.Profile.Capabilities.Legacy);
var renderContext = new RenderContext(_console.Profile.Capabilities);
var delta = _stopwatch.Elapsed - _lastUpdate;
_lastUpdate = _stopwatch.Elapsed;

View File

@ -32,7 +32,7 @@ namespace Spectre.Console
var width = Math.Min(Width ?? maxWidth, maxWidth);
var completed = Math.Min(MaxValue, Math.Max(0, Value));
var token = !context.Unicode || context.LegacyConsole ? AsciiBar : UnicodeBar;
var token = !context.Unicode ? AsciiBar : UnicodeBar;
var style = completed >= MaxValue ? FinishedStyle : CompletedStyle;
var bars = Math.Max(0, (int)(width * (completed / MaxValue)));

View File

@ -33,12 +33,12 @@ namespace Spectre.Console
public void Clear()
{
_console.Render(_live.RestoreCursor());
_console.Write(_live.RestoreCursor());
}
public void Redraw()
{
_console.Render(new ControlSequence(string.Empty));
_console.Write(new ControlSequence(string.Empty));
}
public bool Update(ConsoleKey key)

View File

@ -59,10 +59,10 @@ namespace Spectre.Console
// Get the title and make sure it fits.
var title = GetTitleSegments(context, Title, maxWidth - extraLength);
if (Segment.CellCount(context, title) > maxWidth - extraLength)
if (Segment.CellCount(title) > maxWidth - extraLength)
{
// Truncate the title
title = Segment.TruncateWithEllipsis(title, context, maxWidth - extraLength);
title = Segment.TruncateWithEllipsis(title, maxWidth - extraLength);
if (!title.Any())
{
// We couldn't fit the title at all.
@ -83,7 +83,7 @@ namespace Spectre.Console
private IEnumerable<Segment> GetLineWithoutTitle(RenderContext context, int maxWidth)
{
var border = Border.GetSafeBorder(context.LegacyConsole || !context.Unicode);
var border = Border.GetSafeBorder(safe: !context.Unicode);
var text = border.GetPart(BoxBorderPart.Top).Repeat(maxWidth);
return new[]
@ -102,9 +102,9 @@ namespace Spectre.Console
private (Segment Left, Segment Right) GetLineSegments(RenderContext context, int width, IEnumerable<Segment> title)
{
var titleLength = Segment.CellCount(context, title);
var titleLength = Segment.CellCount(title);
var border = Border.GetSafeBorder(context.LegacyConsole || !context.Unicode);
var border = Border.GetSafeBorder(safe: !context.Unicode);
var borderPart = border.GetPart(BoxBorderPart.Top);
var alignment = Alignment ?? Justify.Center;
@ -112,7 +112,7 @@ namespace Spectre.Console
{
var left = new Segment(borderPart.Repeat(TitlePadding) + new string(' ', TitleSpacing), Style ?? Style.Plain);
var rightLength = width - titleLength - left.CellCount(context) - TitleSpacing;
var rightLength = width - titleLength - left.CellCount() - TitleSpacing;
var right = new Segment(new string(' ', TitleSpacing) + borderPart.Repeat(rightLength), Style ?? Style.Plain);
return (left, right);
@ -122,7 +122,7 @@ namespace Spectre.Console
var leftLength = ((width - titleLength) / 2) - TitleSpacing;
var left = new Segment(borderPart.Repeat(leftLength) + new string(' ', TitleSpacing), Style ?? Style.Plain);
var rightLength = width - titleLength - left.CellCount(context) - TitleSpacing;
var rightLength = width - titleLength - left.CellCount() - TitleSpacing;
var right = new Segment(new string(' ', TitleSpacing) + borderPart.Repeat(rightLength), Style ?? Style.Plain);
return (left, right);
@ -131,7 +131,7 @@ namespace Spectre.Console
{
var right = new Segment(new string(' ', TitleSpacing) + borderPart.Repeat(TitlePadding), Style ?? Style.Plain);
var leftLength = width - titleLength - right.CellCount(context) - TitleSpacing;
var leftLength = width - titleLength - right.CellCount() - TitleSpacing;
var left = new Segment(borderPart.Repeat(leftLength) + new string(' ', TitleSpacing), Style ?? Style.Plain);
return (left, right);

View File

@ -33,7 +33,7 @@ namespace Spectre.Console
var justification = context.Columns[columnIndex].Alignment;
var childContext = context.Options.WithJustification(justification);
var lines = Segment.SplitLines(context.Options, cell.Render(childContext, rowWidth));
var lines = Segment.SplitLines(cell.Render(childContext, rowWidth));
cellHeight = Math.Max(cellHeight, lines.Count);
cells.Add(lines);
}
@ -41,7 +41,7 @@ namespace Spectre.Console
// Show top of header?
if (isFirstRow && context.ShowBorder)
{
var separator = Aligner.Align(context.Options, context.Border.GetColumnRow(TablePart.Top, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
var separator = Aligner.Align(context.Border.GetColumnRow(TablePart.Top, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
result.Add(new Segment(separator, context.BorderStyle));
result.Add(Segment.LineBreak);
}
@ -52,7 +52,7 @@ namespace Spectre.Console
var textBorder = context.Border.GetColumnRow(TablePart.FooterSeparator, columnWidths, context.Columns);
if (!string.IsNullOrEmpty(textBorder))
{
var separator = Aligner.Align(context.Options, textBorder, context.Alignment, context.MaxWidth);
var separator = Aligner.Align(textBorder, context.Alignment, context.MaxWidth);
result.Add(new Segment(separator, context.BorderStyle));
result.Add(Segment.LineBreak);
}
@ -89,7 +89,7 @@ namespace Spectre.Console
rowResult.AddRange(cell[cellRowIndex]);
// Pad cell content right
var length = cell[cellRowIndex].Sum(segment => segment.CellCount(context.Options));
var length = cell[cellRowIndex].Sum(segment => segment.CellCount());
if (length < columnWidths[cellIndex])
{
rowResult.Add(new Segment(new string(' ', columnWidths[cellIndex] - length)));
@ -123,9 +123,9 @@ namespace Spectre.Console
Aligner.Align(context.Options, rowResult, context.Alignment, context.MaxWidth);
// Is the row larger than the allowed max width?
if (Segment.CellCount(context.Options, rowResult) > context.MaxWidth)
if (Segment.CellCount(rowResult) > context.MaxWidth)
{
result.AddRange(Segment.Truncate(context.Options, rowResult, context.MaxWidth));
result.AddRange(Segment.Truncate(rowResult, context.MaxWidth));
}
else
{
@ -138,7 +138,7 @@ namespace Spectre.Console
// Show header separator?
if (isFirstRow && context.ShowBorder && context.ShowHeaders && context.HasRows)
{
var separator = Aligner.Align(context.Options, context.Border.GetColumnRow(TablePart.HeaderSeparator, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
var separator = Aligner.Align(context.Border.GetColumnRow(TablePart.HeaderSeparator, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
result.Add(new Segment(separator, context.BorderStyle));
result.Add(Segment.LineBreak);
}
@ -146,7 +146,7 @@ namespace Spectre.Console
// Show bottom of footer?
if (isLastRow && context.ShowBorder)
{
var separator = Aligner.Align(context.Options, context.Border.GetColumnRow(TablePart.Bottom, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
var separator = Aligner.Align(context.Border.GetColumnRow(TablePart.Bottom, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
result.Add(new Segment(separator, context.BorderStyle));
result.Add(Segment.LineBreak);
}

View File

@ -47,7 +47,7 @@ namespace Spectre.Console
ShowBorder = _table.Border.Visible;
HasRows = Rows.Any(row => !row.IsHeader && !row.IsFooter);
HasFooters = Rows.Any(column => column.IsFooter);
Border = table.Border.GetSafeBorder((options.LegacyConsole || !options.Unicode) && table.UseSafeBorder);
Border = table.Border.GetSafeBorder(!options.Unicode && table.UseSafeBorder);
BorderStyle = table.BorderStyle ?? Style.Plain;
TableWidth = tableWidth;

View File

@ -91,7 +91,7 @@ namespace Spectre.Console
}
var prefix = levels.Skip(1).ToList();
var renderableLines = Segment.SplitLines(context, current.Renderable.Render(context, maxWidth - Segment.CellCount(context, prefix)));
var renderableLines = Segment.SplitLines(current.Renderable.Render(context, maxWidth - Segment.CellCount(prefix)));
foreach (var (_, isFirstLine, _, line) in renderableLines.Enumerate())
{
@ -124,7 +124,7 @@ namespace Spectre.Console
private Segment GetGuide(RenderContext context, TreeGuidePart part)
{
var guide = Guide.GetSafeTreeGuide(context.LegacyConsole || !context.Unicode);
var guide = Guide.GetSafeTreeGuide(safe: !context.Unicode);
return new Segment(guide.GetPart(part), Style ?? Style.Plain);
}
}