mirror of
https://github.com/spectreconsole/spectre.console.git
synced 2025-12-27 00:08:02 +01:00
143 lines
4.6 KiB
C#
143 lines
4.6 KiB
C#
using System;
|
|
|
|
namespace Spectre.Console.Internal
|
|
{
|
|
internal static class StyleParser
|
|
{
|
|
public static Style Parse(string text)
|
|
{
|
|
var style = Parse(text, out var error);
|
|
if (error != null)
|
|
{
|
|
throw new InvalidOperationException(error);
|
|
}
|
|
|
|
return style;
|
|
}
|
|
|
|
public static bool TryParse(string text, out Style style)
|
|
{
|
|
style = Parse(text, out var error);
|
|
return error == null;
|
|
}
|
|
|
|
private static Style Parse(string text, out string error)
|
|
{
|
|
var effectiveDecoration = (Decoration?)null;
|
|
var effectiveForeground = (Color?)null;
|
|
var effectiveBackground = (Color?)null;
|
|
|
|
var parts = text.Split(new[] { ' ' });
|
|
var foreground = true;
|
|
foreach (var part in parts)
|
|
{
|
|
if (part.Equals("default", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (part.Equals("on", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
foreground = false;
|
|
continue;
|
|
}
|
|
|
|
var decoration = DecorationTable.GetDecoration(part);
|
|
if (decoration != null)
|
|
{
|
|
if (effectiveDecoration == null)
|
|
{
|
|
effectiveDecoration = Decoration.None;
|
|
}
|
|
|
|
effectiveDecoration |= decoration.Value;
|
|
}
|
|
else
|
|
{
|
|
var color = ColorTable.GetColor(part);
|
|
if (color == null)
|
|
{
|
|
if (part.StartsWith("#", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
color = ParseHexColor(part, out error);
|
|
if (!string.IsNullOrWhiteSpace(error))
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error = !foreground
|
|
? $"Could not find color '{part}'."
|
|
: $"Could not find color or style '{part}'.";
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
if (foreground)
|
|
{
|
|
if (effectiveForeground != null)
|
|
{
|
|
error = "A foreground color has already been set.";
|
|
return null;
|
|
}
|
|
|
|
effectiveForeground = color;
|
|
}
|
|
else
|
|
{
|
|
if (effectiveBackground != null)
|
|
{
|
|
error = "A background color has already been set.";
|
|
return null;
|
|
}
|
|
|
|
effectiveBackground = color;
|
|
}
|
|
}
|
|
}
|
|
|
|
error = null;
|
|
return new Style(effectiveForeground, effectiveBackground, effectiveDecoration);
|
|
}
|
|
|
|
private static Color? ParseHexColor(string hex, out string error)
|
|
{
|
|
error = null;
|
|
|
|
hex = hex ?? string.Empty;
|
|
hex = hex.Replace("#", string.Empty).Trim();
|
|
|
|
try
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(hex))
|
|
{
|
|
if (hex.Length == 6)
|
|
{
|
|
return new Color(
|
|
(byte)Convert.ToUInt32(hex.Substring(0, 2), 16),
|
|
(byte)Convert.ToUInt32(hex.Substring(2, 2), 16),
|
|
(byte)Convert.ToUInt32(hex.Substring(4, 2), 16));
|
|
}
|
|
else if (hex.Length == 3)
|
|
{
|
|
return new Color(
|
|
(byte)Convert.ToUInt32(new string(hex[0], 2), 16),
|
|
(byte)Convert.ToUInt32(new string(hex[1], 2), 16),
|
|
(byte)Convert.ToUInt32(new string(hex[2], 2), 16));
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
error = $"Invalid hex color '#{hex}'. {ex.Message}";
|
|
return null;
|
|
}
|
|
|
|
error = $"Invalid hex color '#{hex}'.";
|
|
return null;
|
|
}
|
|
}
|
|
}
|