namespace XFESystem.Console;
/// An RGB terminal color, independent of the host operating system.
public readonly record struct TerminalColor(byte Red, byte Green, byte Blue)
{
public static TerminalColor ThemeForeground => new(117, 201, 245);
public static TerminalColor ThemeBackground => new(12, 19, 33);
public string Hex => $"#{Red:X2}{Green:X2}{Blue:X2}";
public static TerminalColor FromConsoleColor(ConsoleColor color)
{
var index = color switch
{
ConsoleColor.Black => 0,
ConsoleColor.DarkRed => 1,
ConsoleColor.DarkGreen => 2,
ConsoleColor.DarkYellow => 3,
ConsoleColor.DarkBlue => 4,
ConsoleColor.DarkMagenta => 5,
ConsoleColor.DarkCyan => 6,
ConsoleColor.Gray => 7,
ConsoleColor.DarkGray => 8,
ConsoleColor.Red => 9,
ConsoleColor.Green => 10,
ConsoleColor.Yellow => 11,
ConsoleColor.Blue => 12,
ConsoleColor.Magenta => 13,
ConsoleColor.Cyan => 14,
ConsoleColor.White => 15,
_ => throw new ArgumentOutOfRangeException(nameof(color))
};
return FromIndexed((byte)index);
}
/// Resolve the xterm 16-color palette, 6×6×6 cube and grayscale ramp.
public static TerminalColor FromIndexed(byte index)
{
if (index < Palette.Length)
return Palette[index];
if (index >= 232)
{
var gray = (byte)(8 + (index - 232) * 10);
return new(gray, gray, gray);
}
var cube = index - 16;
return new(Cube(cube / 36), Cube(cube / 6 % 6), Cube(cube % 6));
}
private static byte Cube(int component) => component == 0 ? (byte)0 : (byte)(55 + component * 40);
private static readonly TerminalColor[] Palette =
[
new(0, 0, 0), new(128, 0, 0), new(0, 128, 0), new(128, 128, 0),
new(0, 0, 128), new(128, 0, 128), new(0, 128, 128), new(192, 192, 192),
new(128, 128, 128), new(255, 0, 0), new(0, 255, 0), new(255, 255, 0),
new(0, 0, 255), new(255, 0, 255), new(0, 255, 255), new(255, 255, 255)
];
}