mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 17:02:51 +08:00
Add method to get VT/ANSI codes for renderables
This commit is contained in:
parent
01f707c78d
commit
cba02070f9
@ -5,7 +5,7 @@ using Xunit;
|
|||||||
|
|
||||||
namespace Spectre.Console.Tests.Unit
|
namespace Spectre.Console.Tests.Unit
|
||||||
{
|
{
|
||||||
public partial class AnsiConsoleTests
|
public sealed partial class AnsiConsoleTests
|
||||||
{
|
{
|
||||||
public sealed class Advanced
|
public sealed class Advanced
|
||||||
{
|
{
|
||||||
@ -42,6 +42,20 @@ namespace Spectre.Console.Tests.Unit
|
|||||||
console.Output.NormalizeLineEndings()
|
console.Output.NormalizeLineEndings()
|
||||||
.ShouldBeEmpty();
|
.ShouldBeEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Should_Return_Ansi_For_Renderable()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var console = new TestConsole().Colors(ColorSystem.TrueColor);
|
||||||
|
var markup = new Console.Markup("[yellow]Hello [blue]World[/]![/]");
|
||||||
|
|
||||||
|
// When
|
||||||
|
var result = console.ToAnsi(markup);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
result.ShouldBe("[38;5;11mHello [0m[38;5;12mWorld[0m[38;5;11m![0m");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
namespace Spectre.Console.Advanced
|
namespace Spectre.Console.Advanced
|
||||||
{
|
{
|
||||||
@ -24,5 +25,16 @@ namespace Spectre.Console.Advanced
|
|||||||
console.Write(new ControlCode(sequence));
|
console.Write(new ControlCode(sequence));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the VT/ANSI control code sequence for a <see cref="IRenderable"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="console">The console.</param>
|
||||||
|
/// <param name="renderable">The renderable to the VT/ANSI control code sequence for.</param>
|
||||||
|
/// <returns>The VT/ANSI control code sequence.</returns>
|
||||||
|
public static string ToAnsi(this IAnsiConsole console, IRenderable renderable)
|
||||||
|
{
|
||||||
|
return AnsiBuilder.Build(console, renderable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,60 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Spectre.Console.Rendering;
|
||||||
using static Spectre.Console.AnsiSequences;
|
using static Spectre.Console.AnsiSequences;
|
||||||
|
|
||||||
namespace Spectre.Console
|
namespace Spectre.Console
|
||||||
{
|
{
|
||||||
internal sealed class AnsiBuilder
|
internal static class AnsiBuilder
|
||||||
{
|
{
|
||||||
private readonly Profile _profile;
|
private static readonly AnsiLinkHasher _linkHasher;
|
||||||
private readonly AnsiLinkHasher _linkHasher;
|
|
||||||
|
|
||||||
public AnsiBuilder(Profile profile)
|
static AnsiBuilder()
|
||||||
{
|
{
|
||||||
_profile = profile ?? throw new ArgumentNullException(nameof(profile));
|
|
||||||
_linkHasher = new AnsiLinkHasher();
|
_linkHasher = new AnsiLinkHasher();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetAnsi(string text, Style style)
|
public static string Build(IAnsiConsole console, IRenderable renderable)
|
||||||
{
|
{
|
||||||
if (style is null)
|
var builder = new StringBuilder();
|
||||||
|
foreach (var segment in renderable.GetSegments(console))
|
||||||
|
{
|
||||||
|
if (segment.IsControlCode)
|
||||||
|
{
|
||||||
|
builder.Append(segment.Text);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parts = segment.Text.NormalizeNewLines().Split(new[] { '\n' });
|
||||||
|
foreach (var (_, _, last, part) in parts.Enumerate())
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(part))
|
||||||
|
{
|
||||||
|
builder.Append(Build(console.Profile, part, segment.Style));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!last)
|
||||||
|
{
|
||||||
|
builder.Append(Environment.NewLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Build(Profile profile, string text, Style style)
|
||||||
|
{
|
||||||
|
if (profile is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(profile));
|
||||||
|
}
|
||||||
|
else if (text is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(text));
|
||||||
|
}
|
||||||
|
else if (style is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(style));
|
throw new ArgumentNullException(nameof(style));
|
||||||
}
|
}
|
||||||
@ -29,7 +66,7 @@ namespace Spectre.Console
|
|||||||
{
|
{
|
||||||
codes = codes.Concat(
|
codes = codes.Concat(
|
||||||
AnsiColorBuilder.GetAnsiCodes(
|
AnsiColorBuilder.GetAnsiCodes(
|
||||||
_profile.Capabilities.ColorSystem,
|
profile.Capabilities.ColorSystem,
|
||||||
style.Foreground,
|
style.Foreground,
|
||||||
true));
|
true));
|
||||||
}
|
}
|
||||||
@ -39,7 +76,7 @@ namespace Spectre.Console
|
|||||||
{
|
{
|
||||||
codes = codes.Concat(
|
codes = codes.Concat(
|
||||||
AnsiColorBuilder.GetAnsiCodes(
|
AnsiColorBuilder.GetAnsiCodes(
|
||||||
_profile.Capabilities.ColorSystem,
|
profile.Capabilities.ColorSystem,
|
||||||
style.Background,
|
style.Background,
|
||||||
false));
|
false));
|
||||||
}
|
}
|
||||||
@ -54,7 +91,7 @@ namespace Spectre.Console
|
|||||||
? $"{SGR(result)}{text}{SGR(0)}"
|
? $"{SGR(result)}{text}{SGR(0)}"
|
||||||
: text;
|
: text;
|
||||||
|
|
||||||
if (style.Link != null && !_profile.Capabilities.Legacy)
|
if (style.Link != null && !profile.Capabilities.Legacy)
|
||||||
{
|
{
|
||||||
var link = style.Link;
|
var link = style.Link;
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ namespace Spectre.Console
|
|||||||
{
|
{
|
||||||
internal sealed class AnsiConsoleBackend : IAnsiConsoleBackend
|
internal sealed class AnsiConsoleBackend : IAnsiConsoleBackend
|
||||||
{
|
{
|
||||||
private readonly AnsiBuilder _builder;
|
|
||||||
private readonly IAnsiConsole _console;
|
private readonly IAnsiConsole _console;
|
||||||
|
|
||||||
public IAnsiConsoleCursor Cursor { get; }
|
public IAnsiConsoleCursor Cursor { get; }
|
||||||
@ -15,8 +14,6 @@ namespace Spectre.Console
|
|||||||
public AnsiConsoleBackend(IAnsiConsole console)
|
public AnsiConsoleBackend(IAnsiConsole console)
|
||||||
{
|
{
|
||||||
_console = console ?? throw new ArgumentNullException(nameof(console));
|
_console = console ?? throw new ArgumentNullException(nameof(console));
|
||||||
_builder = new AnsiBuilder(_console.Profile);
|
|
||||||
|
|
||||||
Cursor = new AnsiConsoleCursor(this);
|
Cursor = new AnsiConsoleCursor(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,33 +30,10 @@ namespace Spectre.Console
|
|||||||
|
|
||||||
public void Write(IRenderable renderable)
|
public void Write(IRenderable renderable)
|
||||||
{
|
{
|
||||||
var builder = new StringBuilder();
|
var result = AnsiBuilder.Build(_console, renderable);
|
||||||
foreach (var segment in renderable.GetSegments(_console))
|
if (result?.Length > 0)
|
||||||
{
|
{
|
||||||
if (segment.IsControlCode)
|
_console.Profile.Out.Writer.Write(result);
|
||||||
{
|
|
||||||
builder.Append(segment.Text);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var parts = segment.Text.NormalizeNewLines().Split(new[] { '\n' });
|
|
||||||
foreach (var (_, _, last, part) in parts.Enumerate())
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(part))
|
|
||||||
{
|
|
||||||
builder.Append(_builder.GetAnsi(part, segment.Style));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!last)
|
|
||||||
{
|
|
||||||
builder.Append(Environment.NewLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (builder.Length > 0)
|
|
||||||
{
|
|
||||||
_console.Profile.Out.Writer.Write(builder.ToString());
|
|
||||||
_console.Profile.Out.Writer.Flush();
|
_console.Profile.Out.Writer.Flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user