Compare commits

...

4 Commits

Author SHA1 Message Date
Khalid Abuhakmeh
0a0380ae0a Don't throw when console is small
this just returns an empty collection when
take is 0. It leads to some strange output, but
it doesn't blow up.

 #93
2020-10-08 22:17:12 +02:00
Patrik Svensson
ae92c606bb Add support for remapping emojis
Closes #94
2020-10-07 17:33:05 +02:00
Patrik Svensson
68e92f3365 Add various exception improvements 2020-10-07 11:57:28 +02:00
Patrik Svensson
39a8588dc3 Rename ExceptionFormats.None 2020-10-07 11:57:28 +02:00
23 changed files with 494 additions and 52 deletions

View File

@@ -30,6 +30,25 @@ var phrase = "Mmmm :birthday_cake:";
var rendered = Emoji.Replace(phrase);
```
# Remapping or adding an emoji
Sometimes you want to remap an existing emoji, or
add a completely new one. For this you can use the
`Emoji.Remap` method. This approach works both with
markup strings and `Emoji.Replace`.
```csharp
// Remap the emoji
Emoji.Remap("globe_showing_europe_africa", "😄");
// Render markup
AnsiConsole.MarkupLine("Hello :globe_showing_europe_africa:!");
// Replace emojis in string
var phrase = "Hello :globe_showing_europe_africa:!";
var rendered = Emoji.Replace(phrase);
```
# Emojis
_The images in the table below might not render correctly in your

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

View File

@@ -9,9 +9,9 @@ You can make exception a bit more readable by using the `WriteException` method.
AnsiConsole.WriteException(ex);
```
<img src="assets/images/exception.png" style="max-width: 100%; margin-bottom: 20px">
<img src="assets/images/exception.png" style="max-width: 100%;">
## Shortening parts
You can also shorten specific parts of the exception to make it even
more readable, and make paths clickable hyperlinks. Whether or not
@@ -24,3 +24,29 @@ AnsiConsole.WriteException(ex,
```
<img src="assets/images/compact_exception.png" style="max-width: 100%;">
## Customizing exception output
In addition to shorten specific part of the exception, you can
also override the default styling.
```csharp
AnsiConsole.WriteException(ex, new ExceptionSettings
{
Format = ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks,
Style = new ExceptionStyle
{
Exception = Style.WithForeground(Color.Grey),
Message = Style.WithForeground(Color.White),
NonEmphasized = Style.WithForeground(Color.Cornsilk1),
Parenthesis = Style.WithForeground(Color.Cornsilk1),
Method = Style.WithForeground(Color.Red),
ParameterName = Style.WithForeground(Color.Cornsilk1),
ParameterType = Style.WithForeground(Color.Red),
Path = Style.WithForeground(Color.Red),
LineNumber = Style.WithForeground(Color.Cornsilk1),
}
});
```
<img src="assets/images/custom_exception.png" style="max-width: 100%;">

View File

@@ -43,6 +43,12 @@ AnsiConsole.Markup("[[Hello]] "); // [Hello]
AnsiConsole.Markup("[red][[World]][/]"); // [World]
```
You can also use the `SafeMarkup` extension method.
```csharp
AnsiConsole.Markup("[red]{0}[/]", "Hello [World]".SafeMarkup());
```
# Setting background color
You can set the background color in markup by prefixing the color with

View File

@@ -6,11 +6,19 @@ namespace EmojiExample
{
public static void Main(string[] args)
{
// Markup
// Show a known emoji
RenderEmoji();
// Show a remapped emoji
Emoji.Remap("globe_showing_europe_africa", Emoji.Known.GrinningFaceWithSmilingEyes);
RenderEmoji();
}
private static void RenderEmoji()
{
AnsiConsole.Render(
new Panel("[yellow]Hello :globe_showing_europe_africa:![/]")
.RoundedBorder()
.SetHeader("Markup"));
.RoundedBorder());
}
}
}

View File

@@ -14,11 +14,35 @@ namespace Exceptions
}
catch (Exception ex)
{
AnsiConsole.WriteLine();
AnsiConsole.Render(new Panel("[u]Default[/]").Expand());
AnsiConsole.WriteLine();
AnsiConsole.WriteException(ex);
AnsiConsole.WriteLine();
AnsiConsole.Render(new Panel("[u]Compact[/]").Expand());
AnsiConsole.WriteLine();
AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks);
AnsiConsole.WriteLine();
AnsiConsole.Render(new Panel("[u]Custom colors[/]").Expand());
AnsiConsole.WriteLine();
AnsiConsole.WriteException(ex, new ExceptionSettings
{
Format = ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks,
Style = new ExceptionStyle
{
Exception = Style.WithForeground(Color.Grey),
Message = Style.WithForeground(Color.White),
NonEmphasized = Style.WithForeground(Color.Cornsilk1),
Parenthesis = Style.WithForeground(Color.Cornsilk1),
Method = Style.WithForeground(Color.Red),
ParameterName = Style.WithForeground(Color.Cornsilk1),
ParameterType = Style.WithForeground(Color.Red),
Path = Style.WithForeground(Color.Red),
LineNumber = Style.WithForeground(Color.Cornsilk1),
}
});
}
}

View File

@@ -87,3 +87,6 @@ dotnet_diagnostic.RCS1227.severity = none
# IDE0004: Remove Unnecessary Cast
dotnet_diagnostic.IDE0004.severity = warning
# CA1810: Initialize reference type static fields inline
dotnet_diagnostic.CA1810.severity = none

View File

@@ -52,7 +52,7 @@ namespace Spectre.Console.Tests
Writer.Write(segment.Text);
}
public string[] WriteExceptionAndGetLines(Exception ex, ExceptionFormats formats = ExceptionFormats.None)
public string[] WriteExceptionAndGetLines(Exception ex, ExceptionFormats formats = ExceptionFormats.Default)
{
this.WriteException(ex, formats);

View File

@@ -228,6 +228,39 @@ namespace Spectre.Console.Tests.Unit
}
}
public sealed class TheToMarkupMethod
{
[Fact]
public void Should_Return_Expected_Markup_For_Default_Color()
{
// Given, When
var result = Color.Default.ToMarkup();
// Then
result.ShouldBe("default");
}
[Fact]
public void Should_Return_Expected_Markup_For_Known_Color()
{
// Given, When
var result = Color.Red.ToMarkup();
// Then
result.ShouldBe("red");
}
[Fact]
public void Should_Return_Expected_Markup_For_Custom_Color()
{
// Given, When
var result = new Color(255, 1, 12).ToMarkup();
// Then
result.ShouldBe("#FF010C");
}
}
public sealed class TheToStringMethod
{
[Fact]

View File

@@ -317,5 +317,60 @@ namespace Spectre.Console.Tests.Unit
result.ShouldBeFalse();
}
}
public sealed class TheToMarkupMethod
{
[Fact]
public void Should_Return_Expected_Markup_For_Style_With_Foreground_Color()
{
// Given
var style = new Style(Color.Red);
// When
var result = style.ToMarkup();
// Then
result.ShouldBe("red");
}
[Fact]
public void Should_Return_Expected_Markup_For_Style_With_Foreground_And_Background_Color()
{
// Given
var style = new Style(Color.Red, Color.Green);
// When
var result = style.ToMarkup();
// Then
result.ShouldBe("red on green");
}
[Fact]
public void Should_Return_Expected_Markup_For_Style_With_Foreground_And_Background_Color_And_Decoration()
{
// Given
var style = new Style(Color.Red, Color.Green, Decoration.Bold | Decoration.Underline);
// When
var result = style.ToMarkup();
// Then
result.ShouldBe("bold underline red on green");
}
[Fact]
public void Should_Return_Expected_Markup_For_Style_With_Only_Background_Color()
{
// Given
var style = new Style(background: Color.Green);
// When
var result = style.ToMarkup();
// Then
result.ShouldBe("default on green");
}
}
}
}

View File

@@ -12,9 +12,19 @@ namespace Spectre.Console
/// </summary>
/// <param name="exception">The exception to write to the console.</param>
/// <param name="format">The exception format options.</param>
public static void WriteException(Exception exception, ExceptionFormats format = ExceptionFormats.None)
public static void WriteException(Exception exception, ExceptionFormats format = ExceptionFormats.Default)
{
Console.WriteException(exception, format);
}
/// <summary>
/// Writes an exception to the console.
/// </summary>
/// <param name="exception">The exception to write to the console.</param>
/// <param name="settings">The exception settings.</param>
public static void WriteException(Exception exception, ExceptionSettings settings)
{
Console.WriteException(exception, settings);
}
}
}

View File

@@ -249,8 +249,13 @@ namespace Spectre.Console
/// Converts the color to a markup string.
/// </summary>
/// <returns>A <see cref="string"/> representing the color as markup.</returns>
public string ToMarkupString()
public string ToMarkup()
{
if (IsDefault)
{
return "default";
}
if (Number != null)
{
var name = ColorTable.GetName(Number.Value);

View File

@@ -1,3 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Spectre.Console
@@ -8,6 +10,35 @@ namespace Spectre.Console
public static partial class Emoji
{
private static readonly Regex _emojiCode = new Regex(@"(:(\S*?):)", RegexOptions.Compiled);
private static readonly Dictionary<string, string> _remappings;
static Emoji()
{
_remappings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// Remaps a specific emoji tag with a new emoji.
/// </summary>
/// <param name="tag">The emoji tag.</param>
/// <param name="emoji">The emoji.</param>
public static void Remap(string tag, string emoji)
{
if (tag is null)
{
throw new ArgumentNullException(nameof(tag));
}
if (emoji is null)
{
throw new ArgumentNullException(nameof(emoji));
}
tag = tag.TrimStart(':').TrimEnd(':');
emoji = emoji.TrimStart(':').TrimEnd(':');
_remappings[tag] = emoji;
}
/// <summary>
/// Replaces emoji markup with corresponding unicode characters.
@@ -19,6 +50,12 @@ namespace Spectre.Console
static string ReplaceEmoji(Match match)
{
var key = match.Groups[2].Value;
if (_remappings.Count > 0 && _remappings.TryGetValue(key, out var remappedEmoji))
{
return remappedEmoji;
}
if (_emojis.TryGetValue(key, out var emoji))
{
return emoji;

View File

@@ -11,7 +11,7 @@ namespace Spectre.Console
/// <summary>
/// The default formatting.
/// </summary>
None = 0,
Default = 0,
/// <summary>
/// Whether or not paths should be shortened.

View File

@@ -0,0 +1,27 @@
namespace Spectre.Console
{
/// <summary>
/// Exception settings.
/// </summary>
public sealed class ExceptionSettings
{
/// <summary>
/// Gets or sets the exception format.
/// </summary>
public ExceptionFormats Format { get; set; }
/// <summary>
/// Gets or sets the exception style.
/// </summary>
public ExceptionStyle Style { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ExceptionSettings"/> class.
/// </summary>
public ExceptionSettings()
{
Format = ExceptionFormats.Default;
Style = new ExceptionStyle();
}
}
}

View File

@@ -0,0 +1,58 @@
namespace Spectre.Console
{
/// <summary>
/// Represent an exception style.
/// </summary>
public sealed class ExceptionStyle
{
/// <summary>
/// Gets or sets the message color.
/// </summary>
public Style Message { get; set; } = new Style(Color.Red, Color.Default, Decoration.Bold);
/// <summary>
/// Gets or sets the exception color.
/// </summary>
public Style Exception { get; set; } = new Style(Color.White);
/// <summary>
/// Gets or sets the method color.
/// </summary>
public Style Method { get; set; } = new Style(Color.Yellow);
/// <summary>
/// Gets or sets the parameter type color.
/// </summary>
public Style ParameterType { get; set; } = new Style(Color.Blue);
/// <summary>
/// Gets or sets the parameter name color.
/// </summary>
public Style ParameterName { get; set; } = new Style(Color.Silver);
/// <summary>
/// Gets or sets the parenthesis color.
/// </summary>
public Style Parenthesis { get; set; } = new Style(Color.Silver);
/// <summary>
/// Gets or sets the path color.
/// </summary>
public Style Path { get; set; } = new Style(Color.Yellow, Color.Default, Decoration.Bold);
/// <summary>
/// Gets or sets the line number color.
/// </summary>
public Style LineNumber { get; set; } = new Style(Color.Blue);
/// <summary>
/// Gets or sets the color for dimmed text such as "at" or "in".
/// </summary>
public Style Dimmed { get; set; } = new Style(Color.Grey);
/// <summary>
/// Gets or sets the color for non emphasized items.
/// </summary>
public Style NonEmphasized { get; set; } = new Style(Color.Silver);
}
}

View File

@@ -13,9 +13,20 @@ namespace Spectre.Console
/// <param name="console">The console.</param>
/// <param name="exception">The exception to write to the console.</param>
/// <param name="format">The exception format options.</param>
public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionFormats format = ExceptionFormats.None)
public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionFormats format = ExceptionFormats.Default)
{
Render(console, exception.GetRenderable(format));
}
/// <summary>
/// Writes an exception to the console.
/// </summary>
/// <param name="console">The console.</param>
/// <param name="exception">The exception to write to the console.</param>
/// <param name="settings">The exception settings.</param>
public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionSettings settings)
{
Render(console, exception.GetRenderable(settings));
}
}
}

View File

@@ -14,9 +14,38 @@ namespace Spectre.Console
/// <param name="exception">The exception to format.</param>
/// <param name="format">The exception format options.</param>
/// <returns>A <see cref="IRenderable"/> representing the exception.</returns>
public static IRenderable GetRenderable(this Exception exception, ExceptionFormats format = ExceptionFormats.None)
public static IRenderable GetRenderable(this Exception exception, ExceptionFormats format = ExceptionFormats.Default)
{
return ExceptionFormatter.Format(exception, format);
if (exception is null)
{
throw new ArgumentNullException(nameof(exception));
}
return GetRenderable(exception, new ExceptionSettings
{
Format = format,
});
}
/// <summary>
/// Gets a <see cref="IRenderable"/> representation of the exception.
/// </summary>
/// <param name="exception">The exception to format.</param>
/// <param name="settings">The exception settings.</param>
/// <returns>A <see cref="IRenderable"/> representing the exception.</returns>
public static IRenderable GetRenderable(this Exception exception, ExceptionSettings settings)
{
if (exception is null)
{
throw new ArgumentNullException(nameof(exception));
}
if (settings is null)
{
throw new ArgumentNullException(nameof(settings));
}
return ExceptionFormatter.Format(exception, settings);
}
}
}

View File

@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace Spectre.Console.Internal
{
internal static class DecorationTable
{
private static readonly Dictionary<string, Decoration?> _lookup;
private static readonly Dictionary<Decoration, string> _reverseLookup;
[SuppressMessage("Performance", "CA1810:Initialize reference type static fields inline")]
static DecorationTable()
@@ -28,6 +30,21 @@ namespace Spectre.Console.Internal
{ "strikethrough", Decoration.Strikethrough },
{ "s", Decoration.Strikethrough },
};
_reverseLookup = new Dictionary<Decoration, string>();
foreach (var (name, decoration) in _lookup)
{
// Cannot happen, but the compiler thinks so...
if (decoration == null)
{
continue;
}
if (!_reverseLookup.ContainsKey(decoration.Value))
{
_reverseLookup[decoration.Value] = name;
}
}
}
public static Decoration? GetDecoration(string name)
@@ -35,5 +52,23 @@ namespace Spectre.Console.Internal
_lookup.TryGetValue(name, out var result);
return result;
}
public static List<string> GetMarkupNames(Decoration decoration)
{
var result = new List<string>();
Enum.GetValues(typeof(Decoration))
.Cast<Decoration>()
.Where(flag => (decoration & flag) != 0)
.ForEach(flag =>
{
if (flag != Decoration.None && _reverseLookup.TryGetValue(flag, out var name))
{
result.Add(name);
}
});
return result;
}
}
}

View File

@@ -8,13 +8,7 @@ namespace Spectre.Console
{
internal static class ExceptionFormatter
{
private static readonly Color _typeColor = Color.White;
private static readonly Color _methodColor = Color.Yellow;
private static readonly Color _parameterColor = Color.Blue;
private static readonly Color _pathColor = Color.Yellow;
private static readonly Color _dimmedColor = Color.Grey;
public static IRenderable Format(Exception exception, ExceptionFormats format)
public static IRenderable Format(Exception exception, ExceptionSettings settings)
{
if (exception is null)
{
@@ -27,10 +21,10 @@ namespace Spectre.Console
return new Text(exception.ToString());
}
return GetException(info, format);
return GetException(info, settings);
}
private static IRenderable GetException(ExceptionInfo info, ExceptionFormats format)
private static IRenderable GetException(ExceptionInfo info, ExceptionSettings settings)
{
if (info is null)
{
@@ -39,20 +33,20 @@ namespace Spectre.Console
return new Rows(new IRenderable[]
{
GetMessage(info, format),
GetStackFrames(info, format),
GetMessage(info, settings),
GetStackFrames(info, settings),
}).Expand();
}
private static Markup GetMessage(ExceptionInfo ex, ExceptionFormats format)
private static Markup GetMessage(ExceptionInfo ex, ExceptionSettings settings)
{
var shortenTypes = (format & ExceptionFormats.ShortenTypes) != 0;
var type = Emphasize(ex.Type, new[] { '.' }, _typeColor.ToMarkupString(), shortenTypes);
var message = $"[b red]{ex.Message.SafeMarkup()}[/]";
var shortenTypes = (settings.Format & ExceptionFormats.ShortenTypes) != 0;
var type = Emphasize(ex.Type, new[] { '.' }, settings.Style.Exception, shortenTypes, settings);
var message = $"[{settings.Style.Message.ToMarkup()}]{ex.Message.SafeMarkup()}[/]";
return new Markup(string.Concat(type, ": ", message));
}
private static Grid GetStackFrames(ExceptionInfo ex, ExceptionFormats format)
private static Grid GetStackFrames(ExceptionInfo ex, ExceptionSettings settings)
{
var grid = new Grid();
grid.AddColumn(new GridColumn().PadLeft(2).PadRight(0).NoWrap());
@@ -63,7 +57,7 @@ namespace Spectre.Console
{
grid.AddRow(
Text.Empty,
GetException(ex.Inner, format));
GetException(ex.Inner, settings));
}
// Stack frames
@@ -72,47 +66,57 @@ namespace Spectre.Console
var builder = new StringBuilder();
// Method
var shortenMethods = (format & ExceptionFormats.ShortenMethods) != 0;
builder.Append(Emphasize(frame.Method, new[] { '.' }, _methodColor.ToMarkupString(), shortenMethods));
builder.Append('(');
builder.Append(string.Join(", ", frame.Parameters.Select(x => $"[{_parameterColor.ToMarkupString()}]{x.Type.SafeMarkup()}[/] {x.Name}")));
builder.Append(')');
var shortenMethods = (settings.Format & ExceptionFormats.ShortenMethods) != 0;
builder.Append(Emphasize(frame.Method, new[] { '.' }, settings.Style.Method, shortenMethods, settings));
builder.Append('[').Append(settings.Style.Parenthesis.ToMarkup()).Append(']').Append('(').Append("[/]");
AppendParameters(builder, frame, settings);
builder.Append('[').Append(settings.Style.Parenthesis.ToMarkup()).Append(']').Append(')').Append("[/]");
if (frame.Path != null)
{
builder.Append(" [").Append(_dimmedColor.ToMarkupString()).Append("]in[/] ");
builder.Append(" [").Append(settings.Style.Dimmed.ToMarkup()).Append("]in[/] ");
// Path
AppendPath(builder, frame, format);
AppendPath(builder, frame, settings);
// Line number
if (frame.LineNumber != null)
{
builder.Append(':');
builder.Append('[').Append(_parameterColor.ToMarkupString()).Append(']').Append(frame.LineNumber).Append("[/]");
builder.Append('[').Append(settings.Style.Dimmed.ToMarkup()).Append("]:[/]");
builder.Append('[').Append(settings.Style.LineNumber.ToMarkup()).Append(']').Append(frame.LineNumber).Append("[/]");
}
}
grid.AddRow($"[{_dimmedColor.ToMarkupString()}]at[/]", builder.ToString());
grid.AddRow(
$"[{settings.Style.Dimmed.ToMarkup()}]at[/]",
builder.ToString());
}
return grid;
}
private static void AppendPath(StringBuilder builder, StackFrameInfo frame, ExceptionFormats format)
private static void AppendParameters(StringBuilder builder, StackFrameInfo frame, ExceptionSettings settings)
{
var typeColor = settings.Style.ParameterType.ToMarkup();
var nameColor = settings.Style.ParameterName.ToMarkup();
var parameters = frame.Parameters.Select(x => $"[{typeColor}]{x.Type.SafeMarkup()}[/] [{nameColor}]{x.Name}[/]");
builder.Append(string.Join(", ", parameters));
}
private static void AppendPath(StringBuilder builder, StackFrameInfo frame, ExceptionSettings settings)
{
if (frame?.Path is null)
{
return;
}
void RenderLink()
void AppendPath()
{
var shortenPaths = (format & ExceptionFormats.ShortenPaths) != 0;
builder.Append(Emphasize(frame.Path, new[] { '/', '\\' }, $"b {_pathColor.ToMarkupString()}", shortenPaths));
var shortenPaths = (settings.Format & ExceptionFormats.ShortenPaths) != 0;
builder.Append(Emphasize(frame.Path, new[] { '/', '\\' }, settings.Style.Path, shortenPaths, settings));
}
if ((format & ExceptionFormats.ShowLinks) != 0)
if ((settings.Format & ExceptionFormats.ShowLinks) != 0)
{
var hasLink = frame.TryGetUri(out var uri);
if (hasLink && uri != null)
@@ -120,7 +124,7 @@ namespace Spectre.Console
builder.Append("[link=").Append(uri.AbsoluteUri).Append(']');
}
RenderLink();
AppendPath();
if (hasLink && uri != null)
{
@@ -129,11 +133,11 @@ namespace Spectre.Console
}
else
{
RenderLink();
AppendPath();
}
}
private static string Emphasize(string input, char[] separators, string color, bool compact)
private static string Emphasize(string input, char[] separators, Style color, bool compact, ExceptionSettings settings)
{
var builder = new StringBuilder();
@@ -143,10 +147,12 @@ namespace Spectre.Console
{
if (!compact)
{
builder.Append("[silver]").Append(type, 0, index + 1).Append("[/]");
builder.Append('[').Append(settings.Style.NonEmphasized.ToMarkup()).Append(']')
.Append(type, 0, index + 1).Append("[/]");
}
builder.Append('[').Append(color).Append(']').Append(type, index + 1, type.Length - index - 1).Append("[/]");
builder.Append('[').Append(color.ToMarkup()).Append(']')
.Append(type, index + 1, type.Length - index - 1).Append("[/]");
}
else
{

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
namespace Spectre.Console.Internal
{
internal static class DictionaryExtensions
{
public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple, out T1 key, out T2 value)
{
key = tuple.Key;
value = tuple.Value;
}
}
}

View File

@@ -306,7 +306,7 @@ namespace Spectre.Console.Rendering
{
// This shouldn't really occur, but I don't like
// never ending loops if it does...
throw new InvalidOperationException("Text folding failed since 'take' was zero.");
return new List<Segment>();
}
result.Add(new Segment(segment.Text.Substring(index, take), segment.Style));

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Spectre.Console.Internal;
namespace Spectre.Console
@@ -25,7 +27,7 @@ namespace Spectre.Console
public Decoration Decoration { get; }
/// <summary>
/// Gets the link.
/// Gets the link associated with the style.
/// </summary>
public string? Link { get; }
@@ -191,6 +193,41 @@ namespace Spectre.Console
}
}
/// <summary>
/// Returns the markup representation of this style.
/// </summary>
/// <returns>The markup representation of this style.</returns>
public string ToMarkup()
{
var builder = new List<string>();
if (Decoration != Decoration.None)
{
var result = DecorationTable.GetMarkupNames(Decoration);
if (result.Count != 0)
{
builder.AddRange(result);
}
}
if (Foreground != Color.Default)
{
builder.Add(Foreground.ToMarkup());
}
if (Background != Color.Default)
{
if (builder.Count == 0)
{
builder.Add("default");
}
builder.Add("on " + Background.ToMarkup());
}
return string.Join(" ", builder);
}
/// <inheritdoc/>
public override bool Equals(object? obj)
{