mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-06-19 05:18:16 +08:00
Initial commit
This commit is contained in:
135
src/Spectre.Console/AnsiConsole.cs
Normal file
135
src/Spectre.Console/AnsiConsole.cs
Normal file
@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using Spectre.Console.Internal;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static class AnsiConsole
|
||||
{
|
||||
private static readonly Lazy<IAnsiConsole> _console = new Lazy<IAnsiConsole>(() =>
|
||||
{
|
||||
return Create(new AnsiConsoleSettings
|
||||
{
|
||||
Ansi = AnsiSupport.Detect,
|
||||
ColorSystem = ColorSystemSupport.Detect,
|
||||
Out = System.Console.Out,
|
||||
});
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current renderer.
|
||||
/// </summary>
|
||||
public static IAnsiConsole Console => _console.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the console's capabilities.
|
||||
/// </summary>
|
||||
public static AnsiConsoleCapabilities Capabilities => Console.Capabilities;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffer width of the console.
|
||||
/// </summary>
|
||||
public static int Width
|
||||
{
|
||||
get => Console.Width;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffer height of the console.
|
||||
/// </summary>
|
||||
public static int Height
|
||||
{
|
||||
get => Console.Height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the foreground color.
|
||||
/// </summary>
|
||||
public static Color Foreground
|
||||
{
|
||||
get => Console.Foreground;
|
||||
set => Console.SetColor(value, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the background color.
|
||||
/// </summary>
|
||||
public static Color Background
|
||||
{
|
||||
get => Console.Background;
|
||||
set => Console.SetColor(value, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the style.
|
||||
/// </summary>
|
||||
public static Styles Style
|
||||
{
|
||||
get => Console.Style;
|
||||
set => Console.Style = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="IAnsiConsole"/> instance
|
||||
/// from the provided settings.
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings to use.</param>
|
||||
/// <returns>An <see cref="IAnsiConsole"/> instance.</returns>
|
||||
public static IAnsiConsole Create(AnsiConsoleSettings settings)
|
||||
{
|
||||
return ConsoleBuilder.Build(settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets colors and styles to the default ones.
|
||||
/// </summary>
|
||||
public static void Reset()
|
||||
{
|
||||
Console.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the current style back to the default one.
|
||||
/// </summary>
|
||||
public static void ResetStyle()
|
||||
{
|
||||
Console.ResetStyle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the foreground and background colors to the default ones.
|
||||
/// </summary>
|
||||
public static void ResetColors()
|
||||
{
|
||||
Console.ResetColors();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the content to the console.
|
||||
/// </summary>
|
||||
/// <param name="content">The content to write.</param>
|
||||
public static void Write(string content)
|
||||
{
|
||||
Console.Write(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an empty line to the console.
|
||||
/// </summary>
|
||||
public static void WriteLine()
|
||||
{
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a line to the console.
|
||||
/// </summary>
|
||||
/// <param name="content">The content to write.</param>
|
||||
public static void WriteLine(string content)
|
||||
{
|
||||
Console.WriteLine(content);
|
||||
}
|
||||
}
|
||||
}
|
42
src/Spectre.Console/AnsiConsoleCapabilities.cs
Normal file
42
src/Spectre.Console/AnsiConsoleCapabilities.cs
Normal file
@ -0,0 +1,42 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents console capabilities.
|
||||
/// </summary>
|
||||
public sealed class AnsiConsoleCapabilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not
|
||||
/// the console supports Ansi.
|
||||
/// </summary>
|
||||
public bool SupportsAnsi { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the color system.
|
||||
/// </summary>
|
||||
public ColorSystem ColorSystem { get; }
|
||||
|
||||
internal AnsiConsoleCapabilities(bool supportsAnsi, ColorSystem colorSystem)
|
||||
{
|
||||
SupportsAnsi = supportsAnsi;
|
||||
ColorSystem = colorSystem;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
var supportsAnsi = SupportsAnsi ? "Yes" : "No";
|
||||
var bits = ColorSystem switch
|
||||
{
|
||||
ColorSystem.NoColors => "1 bit",
|
||||
ColorSystem.Legacy => "3 bits",
|
||||
ColorSystem.Standard => "4 bits",
|
||||
ColorSystem.EightBit => "8 bits",
|
||||
ColorSystem.TrueColor => "24 bits",
|
||||
_ => "?"
|
||||
};
|
||||
|
||||
return $"ANSI={supportsAnsi}, Colors={ColorSystem} ({bits})";
|
||||
}
|
||||
}
|
||||
}
|
27
src/Spectre.Console/AnsiConsoleSettings.cs
Normal file
27
src/Spectre.Console/AnsiConsoleSettings.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Settings used by <see cref="ConsoleBuilder"/>
|
||||
/// when building a <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
public sealed class AnsiConsoleSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or
|
||||
/// not ANSI escape sequences are supported.
|
||||
/// </summary>
|
||||
public AnsiSupport Ansi { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color system to use.
|
||||
/// </summary>
|
||||
public ColorSystemSupport ColorSystem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the out buffer.
|
||||
/// </summary>
|
||||
public TextWriter Out { get; set; }
|
||||
}
|
||||
}
|
24
src/Spectre.Console/AnsiSupport.cs
Normal file
24
src/Spectre.Console/AnsiSupport.cs
Normal file
@ -0,0 +1,24 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines ANSI escape sequence support.
|
||||
/// </summary>
|
||||
public enum AnsiSupport
|
||||
{
|
||||
/// <summary>
|
||||
/// ANSI escape sequence support should
|
||||
/// be detected by the system.
|
||||
/// </summary>
|
||||
Detect = 0,
|
||||
|
||||
/// <summary>
|
||||
/// ANSI escape sequences are supported.
|
||||
/// </summary>
|
||||
Yes = 1,
|
||||
|
||||
/// <summary>
|
||||
/// ANSI escape sequences are not supported.
|
||||
/// </summary>
|
||||
No = 2,
|
||||
}
|
||||
}
|
1352
src/Spectre.Console/Color.Known.cs
Normal file
1352
src/Spectre.Console/Color.Known.cs
Normal file
File diff suppressed because it is too large
Load Diff
211
src/Spectre.Console/Color.cs
Normal file
211
src/Spectre.Console/Color.cs
Normal file
@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Internal;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a color.
|
||||
/// </summary>
|
||||
public partial struct Color : IEquatable<Color>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the default color.
|
||||
/// </summary>
|
||||
public static Color Default { get; }
|
||||
|
||||
static Color()
|
||||
{
|
||||
Default = new Color(0, "default", 0, 0, 0, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the red component.
|
||||
/// </summary>
|
||||
public byte R { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the green component.
|
||||
/// </summary>
|
||||
public byte G { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the blue component.
|
||||
/// </summary>
|
||||
public byte B { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the color, if any.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of the color, if any.
|
||||
/// </summary>
|
||||
internal byte? Number { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not this is the default color.
|
||||
/// </summary>
|
||||
internal bool IsDefault { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="red">The red component.</param>
|
||||
/// <param name="green">The green component.</param>
|
||||
/// <param name="blue">The blue component.</param>
|
||||
public Color(byte red, byte green, byte blue)
|
||||
{
|
||||
R = red;
|
||||
G = green;
|
||||
B = blue;
|
||||
IsDefault = false;
|
||||
Name = null;
|
||||
Number = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = (int)2166136261;
|
||||
hash = (hash * 16777619) ^ R.GetHashCode();
|
||||
hash = (hash * 16777619) ^ G.GetHashCode();
|
||||
hash = (hash * 16777619) ^ B.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Color color && Equals(color);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(Color other)
|
||||
{
|
||||
return Number == other.Number || (R == other.R && G == other.G && B == other.B);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Color"/> instances are equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first color instance to compare.</param>
|
||||
/// <param name="right">The second color instance to compare.</param>
|
||||
/// <returns><c>true</c> if the two colors are equal, otherwise <c>false</c>.</returns>
|
||||
public static bool operator ==(Color left, Color right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Color"/> instances are not equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first color instance to compare.</param>
|
||||
/// <param name="right">The second color instance to compare.</param>
|
||||
/// <returns><c>true</c> if the two colors are not equal, otherwise <c>false</c>.</returns>
|
||||
public static bool operator !=(Color left, Color right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convers a <see cref="ConsoleColor"/> to a <see cref="Color"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The color to convert.</param>
|
||||
public static implicit operator Color(ConsoleColor color)
|
||||
{
|
||||
return FromConsoleColor(color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convers a color number into a <see cref="Color"/>.
|
||||
/// </summary>
|
||||
/// <param name="number">The color number.</param>
|
||||
/// <returns>The color representing the specified color number.</returns>
|
||||
public static Color FromColorNumber(int number)
|
||||
{
|
||||
if (number < 0 || number > 255)
|
||||
{
|
||||
throw new InvalidOperationException("Color number must be between 0 and 255");
|
||||
}
|
||||
|
||||
return ColorPalette.EightBit.First(x => x.Number == number);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convers a <see cref="Color"/> to a <see cref="ConsoleColor"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The color to convert.</param>
|
||||
/// <returns>A <see cref="ConsoleColor"/> representing the <see cref="Color"/>.</returns>
|
||||
public static ConsoleColor ToConsoleColor(Color color)
|
||||
{
|
||||
if (color.IsDefault)
|
||||
{
|
||||
return (ConsoleColor)(-1);
|
||||
}
|
||||
|
||||
if (color.Number == null || color.Number.Value >= 16)
|
||||
{
|
||||
color = ColorPalette.ExactOrClosest(ColorSystem.Standard, color);
|
||||
}
|
||||
|
||||
// Should not happen, but this will make things easier if we mess things up...
|
||||
Debug.Assert(color.Number >= 0 && color.Number < 16, "Color does not fall inside the standard palette range.");
|
||||
|
||||
return color.Number.Value switch
|
||||
{
|
||||
0 => ConsoleColor.Black,
|
||||
1 => ConsoleColor.DarkRed,
|
||||
2 => ConsoleColor.DarkGreen,
|
||||
3 => ConsoleColor.DarkYellow,
|
||||
4 => ConsoleColor.DarkBlue,
|
||||
5 => ConsoleColor.DarkMagenta,
|
||||
6 => ConsoleColor.DarkCyan,
|
||||
7 => ConsoleColor.Gray,
|
||||
8 => ConsoleColor.DarkGray,
|
||||
9 => ConsoleColor.Red,
|
||||
10 => ConsoleColor.Green,
|
||||
11 => ConsoleColor.Yellow,
|
||||
12 => ConsoleColor.Blue,
|
||||
13 => ConsoleColor.Magenta,
|
||||
14 => ConsoleColor.Cyan,
|
||||
15 => ConsoleColor.White,
|
||||
_ => throw new InvalidOperationException("Cannot convert color to console color."),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convers a <see cref="ConsoleColor"/> to a <see cref="Color"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The color to convert.</param>
|
||||
/// <returns>A <see cref="Color"/> representing the <see cref="ConsoleColor"/>.</returns>
|
||||
public static Color FromConsoleColor(ConsoleColor color)
|
||||
{
|
||||
return color switch
|
||||
{
|
||||
ConsoleColor.Black => Black,
|
||||
ConsoleColor.Blue => Blue,
|
||||
ConsoleColor.Cyan => Aqua,
|
||||
ConsoleColor.DarkBlue => Navy,
|
||||
ConsoleColor.DarkCyan => Teal,
|
||||
ConsoleColor.DarkGray => Grey,
|
||||
ConsoleColor.DarkGreen => Green,
|
||||
ConsoleColor.DarkMagenta => Purple,
|
||||
ConsoleColor.DarkRed => Maroon,
|
||||
ConsoleColor.DarkYellow => Olive,
|
||||
ConsoleColor.Gray => Silver,
|
||||
ConsoleColor.Green => Lime,
|
||||
ConsoleColor.Magenta => Fuchsia,
|
||||
ConsoleColor.Red => Red,
|
||||
ConsoleColor.White => White,
|
||||
ConsoleColor.Yellow => Yellow,
|
||||
_ => Default,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
33
src/Spectre.Console/ColorSystem.cs
Normal file
33
src/Spectre.Console/ColorSystem.cs
Normal file
@ -0,0 +1,33 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a color system.
|
||||
/// </summary>
|
||||
public enum ColorSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// No colors.
|
||||
/// </summary>
|
||||
NoColors = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Legacy, 3-bit mode.
|
||||
/// </summary>
|
||||
Legacy = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Standard, 4-bit mode.
|
||||
/// </summary>
|
||||
Standard = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 8-bit mode.
|
||||
/// </summary>
|
||||
EightBit = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 24-bit mode.
|
||||
/// </summary>
|
||||
TrueColor = 4,
|
||||
}
|
||||
}
|
38
src/Spectre.Console/ColorSystemSupport.cs
Normal file
38
src/Spectre.Console/ColorSystemSupport.cs
Normal file
@ -0,0 +1,38 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines what color system should be used.
|
||||
/// </summary>
|
||||
public enum ColorSystemSupport
|
||||
{
|
||||
/// <summary>
|
||||
/// Try to detect the color system.
|
||||
/// </summary>
|
||||
Detect = -1,
|
||||
|
||||
/// <summary>
|
||||
/// No colors.
|
||||
/// </summary>
|
||||
NoColors = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Legacy, 3-bit mode.
|
||||
/// </summary>
|
||||
Legacy = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Standard, 4-bit mode.
|
||||
/// </summary>
|
||||
Standard = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 8-bit mode.
|
||||
/// </summary>
|
||||
EightBit = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 24-bit mode.
|
||||
/// </summary>
|
||||
TrueColor = 4,
|
||||
}
|
||||
}
|
83
src/Spectre.Console/ConsoleExtensions.cs
Normal file
83
src/Spectre.Console/ConsoleExtensions.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
public static class ConsoleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Resets both colors and style for the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to reset.</param>
|
||||
public static void Reset(this IAnsiConsole console)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.ResetColors();
|
||||
console.ResetStyle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the current style back to the default one.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to reset the style for.</param>
|
||||
public static void ResetStyle(this IAnsiConsole console)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.Style = Styles.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the foreground and background colors to the default ones.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to reset colors for.</param>
|
||||
public static void ResetColors(this IAnsiConsole console)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.Foreground = Color.Default;
|
||||
console.Background = Color.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an empty line to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
public static void WriteLine(this IAnsiConsole console)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.WriteLine(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a line to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The console to write to.</param>
|
||||
/// <param name="content">The content to write.</param>
|
||||
public static void WriteLine(this IAnsiConsole console, string content)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
console.WriteLine(content);
|
||||
}
|
||||
}
|
||||
}
|
52
src/Spectre.Console/IAnsiConsole.cs
Normal file
52
src/Spectre.Console/IAnsiConsole.cs
Normal file
@ -0,0 +1,52 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a console.
|
||||
/// </summary>
|
||||
public interface IAnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the console's capabilities.
|
||||
/// </summary>
|
||||
public AnsiConsoleCapabilities Capabilities { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffer width of the console.
|
||||
/// </summary>
|
||||
public int Width { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffer height of the console.
|
||||
/// </summary>
|
||||
public int Height { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current style.
|
||||
/// </summary>
|
||||
Styles Style { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current foreground.
|
||||
/// </summary>
|
||||
Color Foreground { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current background.
|
||||
/// </summary>
|
||||
Color Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string followed by a line terminator to the console.
|
||||
/// </summary>
|
||||
/// <param name="text">The string to write.</param>
|
||||
void Write(string text);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string followed by a line terminator to the console.
|
||||
/// </summary>
|
||||
/// <param name="text">
|
||||
/// The string to write. If value is null, only the line terminator is written.
|
||||
/// </param>
|
||||
void WriteLine(string text);
|
||||
}
|
||||
}
|
44
src/Spectre.Console/Internal/Ansi/AnsiBuilder.cs
Normal file
44
src/Spectre.Console/Internal/Ansi/AnsiBuilder.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class AnsiBuilder
|
||||
{
|
||||
public static string GetAnsi(
|
||||
ColorSystem system,
|
||||
string text,
|
||||
Styles style,
|
||||
Color foreground,
|
||||
Color background)
|
||||
{
|
||||
var codes = AnsiStyleBuilder.GetAnsiCodes(style);
|
||||
|
||||
// Got foreground?
|
||||
if (foreground != Color.Default)
|
||||
{
|
||||
codes = codes.Concat(AnsiColorBuilder.GetAnsiCodes(system, foreground, foreground: true));
|
||||
}
|
||||
|
||||
// Got background?
|
||||
if (background != Color.Default)
|
||||
{
|
||||
codes = codes.Concat(AnsiColorBuilder.GetAnsiCodes(system, background, foreground: false));
|
||||
}
|
||||
|
||||
var result = codes.ToArray();
|
||||
if (result.Length == 0)
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
var lol = string.Concat(
|
||||
"\u001b[",
|
||||
string.Join(";", result),
|
||||
"m",
|
||||
text,
|
||||
"\u001b[0m");
|
||||
|
||||
return lol;
|
||||
}
|
||||
}
|
||||
}
|
70
src/Spectre.Console/Internal/Ansi/AnsiColorBuilder.cs
Normal file
70
src/Spectre.Console/Internal/Ansi/AnsiColorBuilder.cs
Normal file
@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class AnsiColorBuilder
|
||||
{
|
||||
public static IEnumerable<byte> GetAnsiCodes(ColorSystem system, Color color, bool foreground)
|
||||
{
|
||||
return system switch
|
||||
{
|
||||
ColorSystem.NoColors => Array.Empty<byte>(), // No colors
|
||||
ColorSystem.TrueColor => GetTrueColor(color, foreground), // 24-bit
|
||||
ColorSystem.EightBit => GetEightBit(color, foreground), // 8-bit
|
||||
ColorSystem.Standard => GetFourBit(color, foreground), // 4-bit
|
||||
ColorSystem.Legacy => GetThreeBit(color, foreground), // 3-bit
|
||||
_ => throw new InvalidOperationException("Could not determine ANSI color."),
|
||||
};
|
||||
}
|
||||
|
||||
private static IEnumerable<byte> GetThreeBit(Color color, bool foreground)
|
||||
{
|
||||
var number = color.Number;
|
||||
if (number == null || color.Number >= 8)
|
||||
{
|
||||
number = ColorPalette.ExactOrClosest(ColorSystem.Legacy, color).Number;
|
||||
}
|
||||
|
||||
Debug.Assert(number >= 0 && number < 8, "Invalid range for 4-bit color");
|
||||
|
||||
var mod = foreground ? 30 : 40;
|
||||
return new byte[] { (byte)(number.Value + mod) };
|
||||
}
|
||||
|
||||
private static IEnumerable<byte> GetFourBit(Color color, bool foreground)
|
||||
{
|
||||
var number = color.Number;
|
||||
if (number == null || color.Number >= 16)
|
||||
{
|
||||
number = ColorPalette.ExactOrClosest(ColorSystem.Standard, color).Number;
|
||||
}
|
||||
|
||||
Debug.Assert(number >= 0 && number < 16, "Invalid range for 4-bit color");
|
||||
|
||||
var mod = number < 8 ? (foreground ? 30 : 40) : (foreground ? 82 : 92);
|
||||
return new byte[] { (byte)(number.Value + mod) };
|
||||
}
|
||||
|
||||
private static IEnumerable<byte> GetEightBit(Color color, bool foreground)
|
||||
{
|
||||
var number = color.Number ?? ColorPalette.ExactOrClosest(ColorSystem.EightBit, color).Number;
|
||||
Debug.Assert(number >= 0 && number <= 255, "Invalid range for 8-bit color");
|
||||
|
||||
var mod = foreground ? (byte)38 : (byte)48;
|
||||
return new byte[] { mod, 5, (byte)number };
|
||||
}
|
||||
|
||||
private static IEnumerable<byte> GetTrueColor(Color color, bool foreground)
|
||||
{
|
||||
if (color.Number != null)
|
||||
{
|
||||
return GetEightBit(color, foreground);
|
||||
}
|
||||
|
||||
var mod = foreground ? (byte)38 : (byte)48;
|
||||
return new byte[] { mod, 2, color.R, color.G, color.B };
|
||||
}
|
||||
}
|
||||
}
|
129
src/Spectre.Console/Internal/Ansi/AnsiDetector.cs
Normal file
129
src/Spectre.Console/Internal/Ansi/AnsiDetector.cs
Normal file
@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Portions of this code was ported from the supports-ansi project by Qingrong Ke
|
||||
// https://github.com/keqingrong/supports-ansi/blob/master/index.js
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class AnsiDetector
|
||||
{
|
||||
private static readonly Regex[] Regexes = new[]
|
||||
{
|
||||
new Regex("^xterm"), // xterm, PuTTY, Mintty
|
||||
new Regex("^rxvt"), // RXVT
|
||||
new Regex("^eterm"), // Eterm
|
||||
new Regex("^screen"), // GNU screen, tmux
|
||||
new Regex("tmux"), // tmux
|
||||
new Regex("^vt100"), // DEC VT series
|
||||
new Regex("^vt102"), // DEC VT series
|
||||
new Regex("^vt220"), // DEC VT series
|
||||
new Regex("^vt320"), // DEC VT series
|
||||
new Regex("ansi"), // ANSI
|
||||
new Regex("scoansi"), // SCO ANSI
|
||||
new Regex("cygwin"), // Cygwin, MinGW
|
||||
new Regex("linux"), // Linux console
|
||||
new Regex("konsole"), // Konsole
|
||||
new Regex("bvterm"), // Bitvise SSH Client
|
||||
};
|
||||
|
||||
public static bool SupportsAnsi(bool upgrade)
|
||||
{
|
||||
// Github action doesn't setup a correct PTY but supports ANSI.
|
||||
if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("GITHUB_ACTION")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Running on Windows?
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
// Running under ConEmu?
|
||||
var conEmu = Environment.GetEnvironmentVariable("ConEmuANSI");
|
||||
if (!string.IsNullOrEmpty(conEmu) && conEmu.Equals("On", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Windows.SupportsAnsi(upgrade);
|
||||
}
|
||||
|
||||
// Check if the terminal is of type ANSI/VT100/xterm compatible.
|
||||
var term = Environment.GetEnvironmentVariable("TERM");
|
||||
if (!string.IsNullOrWhiteSpace(term))
|
||||
{
|
||||
if (Regexes.Any(regex => regex.IsMatch(term)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[SuppressMessage("Design", "CA1060:Move pinvokes to native methods class")]
|
||||
internal static class Windows
|
||||
{
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore")]
|
||||
private const int STD_OUTPUT_HANDLE = -11;
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore")]
|
||||
private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore")]
|
||||
private const uint DISABLE_NEWLINE_AUTO_RETURN = 0x0008;
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern IntPtr GetStdHandle(int nStdHandle);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern uint GetLastError();
|
||||
|
||||
[SuppressMessage("Design", "CA1031:Do not catch general exception types")]
|
||||
public static bool SupportsAnsi(bool upgrade)
|
||||
{
|
||||
try
|
||||
{
|
||||
var @out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (!GetConsoleMode(@out, out uint mode))
|
||||
{
|
||||
// Could not get console mode.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0)
|
||||
{
|
||||
if (!upgrade)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try enable ANSI support.
|
||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
|
||||
if (!SetConsoleMode(@out, mode))
|
||||
{
|
||||
// Enabling failed.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// All we know here is that we don't support ANSI.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
56
src/Spectre.Console/Internal/Ansi/AnsiStyleBuilder.cs
Normal file
56
src/Spectre.Console/Internal/Ansi/AnsiStyleBuilder.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class AnsiStyleBuilder
|
||||
{
|
||||
// TODO: Rewrite this to not yield
|
||||
public static IEnumerable<byte> GetAnsiCodes(Styles style)
|
||||
{
|
||||
if ((style & Styles.Bold) != 0)
|
||||
{
|
||||
yield return 1;
|
||||
}
|
||||
|
||||
if ((style & Styles.Dim) != 0)
|
||||
{
|
||||
yield return 2;
|
||||
}
|
||||
|
||||
if ((style & Styles.Italic) != 0)
|
||||
{
|
||||
yield return 3;
|
||||
}
|
||||
|
||||
if ((style & Styles.Underline) != 0)
|
||||
{
|
||||
yield return 4;
|
||||
}
|
||||
|
||||
if ((style & Styles.SlowBlink) != 0)
|
||||
{
|
||||
yield return 5;
|
||||
}
|
||||
|
||||
if ((style & Styles.RapidBlink) != 0)
|
||||
{
|
||||
yield return 6;
|
||||
}
|
||||
|
||||
if ((style & Styles.Invert) != 0)
|
||||
{
|
||||
yield return 7;
|
||||
}
|
||||
|
||||
if ((style & Styles.Conceal) != 0)
|
||||
{
|
||||
yield return 8;
|
||||
}
|
||||
|
||||
if ((style & Styles.Strikethrough) != 0)
|
||||
{
|
||||
yield return 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
158
src/Spectre.Console/Internal/Colors/ColorPalette.cs
Normal file
158
src/Spectre.Console/Internal/Colors/ColorPalette.cs
Normal file
@ -0,0 +1,158 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class ColorPalette
|
||||
{
|
||||
public static IReadOnlyList<Color> Legacy { get; }
|
||||
public static IReadOnlyList<Color> Standard { get; }
|
||||
public static IReadOnlyList<Color> EightBit { get; }
|
||||
|
||||
static ColorPalette()
|
||||
{
|
||||
Legacy = new List<Color>
|
||||
{
|
||||
Color.Black, Color.Maroon, Color.Green, Color.Olive,
|
||||
Color.Navy, Color.Purple, Color.Teal, Color.Silver,
|
||||
};
|
||||
|
||||
Standard = new List<Color>(Legacy)
|
||||
{
|
||||
Color.Grey, Color.Red, Color.Lime, Color.Yellow,
|
||||
Color.Blue, Color.Fuchsia, Color.Aqua, Color.White,
|
||||
};
|
||||
|
||||
EightBit = new List<Color>(Standard)
|
||||
{
|
||||
Color.Grey0, Color.NavyBlue, Color.DarkBlue, Color.Blue3,
|
||||
Color.Blue3_1, Color.Blue1, Color.DarkGreen, Color.DeepSkyBlue4,
|
||||
Color.DeepSkyBlue4_1, Color.DeepSkyBlue4_2, Color.DodgerBlue3, Color.DodgerBlue2,
|
||||
Color.Green4, Color.SpringGreen4, Color.Turquoise4, Color.DeepSkyBlue3,
|
||||
Color.DeepSkyBlue3_1, Color.DodgerBlue1, Color.Green3, Color.SpringGreen3,
|
||||
Color.DarkCyan, Color.LightSeaGreen, Color.DeepSkyBlue2, Color.DeepSkyBlue1,
|
||||
Color.Green3_1, Color.SpringGreen3_1, Color.SpringGreen2, Color.Cyan3,
|
||||
Color.DarkTurquoise, Color.Turquoise2, Color.Green1, Color.SpringGreen2_1,
|
||||
Color.SpringGreen1, Color.MediumSpringGreen, Color.Cyan2, Color.Cyan1,
|
||||
Color.DarkRed, Color.DeepPink4, Color.Purple4, Color.Purple4_1,
|
||||
Color.Purple3, Color.BlueViolet, Color.Orange4, Color.Grey37,
|
||||
Color.MediumPurple4, Color.SlateBlue3, Color.SlateBlue3_1, Color.RoyalBlue1,
|
||||
Color.Chartreuse4, Color.DarkSeaGreen4, Color.PaleTurquoise4, Color.SteelBlue,
|
||||
Color.SteelBlue3, Color.CornflowerBlue, Color.Chartreuse3, Color.DarkSeaGreen4_1,
|
||||
Color.CadetBlue, Color.CadetBlue_1, Color.SkyBlue3, Color.SteelBlue1,
|
||||
Color.Chartreuse3_1, Color.PaleGreen3, Color.SeaGreen3, Color.Aquamarine3,
|
||||
Color.MediumTurquoise, Color.SteelBlue1_1, Color.Chartreuse2, Color.SeaGreen2,
|
||||
Color.SeaGreen1, Color.SeaGreen1_1, Color.Aquamarine1, Color.DarkSlateGray2,
|
||||
Color.DarkRed_1, Color.DeepPink4_1, Color.DarkMagenta, Color.DarkMagenta_1,
|
||||
Color.DarkViolet, Color.Purple_1, Color.Orange4_1, Color.LightPink4,
|
||||
Color.Plum4, Color.MediumPurple3, Color.MediumPurple3_1, Color.SlateBlue1,
|
||||
Color.Yellow4, Color.Wheat4, Color.Grey53, Color.LightSlateGrey,
|
||||
Color.MediumPurple, Color.LightSlateBlue, Color.Yellow4_1, Color.DarkOliveGreen3,
|
||||
Color.DarkSeaGreen, Color.LightSkyBlue3, Color.LightSkyBlue3_1, Color.SkyBlue2,
|
||||
Color.Chartreuse2_1, Color.DarkOliveGreen3_1, Color.PaleGreen3_1, Color.DarkSeaGreen3,
|
||||
Color.DarkSlateGray3, Color.SkyBlue1, Color.Chartreuse1, Color.LightGreen,
|
||||
Color.LightGreen_1, Color.PaleGreen1, Color.Aquamarine1_1, Color.DarkSlateGray1,
|
||||
Color.Red3, Color.DeepPink4_2, Color.MediumVioletRed, Color.Magenta3,
|
||||
Color.DarkViolet_1, Color.Purple_2, Color.DarkOrange3, Color.IndianRed,
|
||||
Color.HotPink3, Color.MediumOrchid3, Color.MediumOrchid, Color.MediumPurple2,
|
||||
Color.DarkGoldenrod, Color.LightSalmon3, Color.RosyBrown, Color.Grey63,
|
||||
Color.MediumPurple2_1, Color.MediumPurple1, Color.Gold3, Color.DarkKhaki,
|
||||
Color.NavajoWhite3, Color.Grey69, Color.LightSteelBlue3, Color.LightSteelBlue,
|
||||
Color.Yellow3, Color.DarkOliveGreen3_2, Color.DarkSeaGreen3_1, Color.DarkSeaGreen2,
|
||||
Color.LightCyan3, Color.LightSkyBlue1, Color.GreenYellow, Color.DarkOliveGreen2,
|
||||
Color.PaleGreen1_1, Color.DarkSeaGreen2_1, Color.DarkSeaGreen1, Color.PaleTurquoise1,
|
||||
Color.Red3_1, Color.DeepPink3, Color.DeepPink3_1, Color.Magenta3_1,
|
||||
Color.Magenta3_2, Color.Magenta2, Color.DarkOrange3_1, Color.IndianRed_1,
|
||||
Color.HotPink3_1, Color.HotPink2, Color.Orchid, Color.MediumOrchid1,
|
||||
Color.Orange3, Color.LightSalmon3_1, Color.LightPink3, Color.Pink3,
|
||||
Color.Plum3, Color.Violet, Color.Gold3_1, Color.LightGoldenrod3,
|
||||
Color.Tan, Color.MistyRose3, Color.Thistle3, Color.Plum2,
|
||||
Color.Yellow3_1, Color.Khaki3, Color.LightGoldenrod2, Color.LightYellow3,
|
||||
Color.Grey84, Color.LightSteelBlue1, Color.Yellow2, Color.DarkOliveGreen1,
|
||||
Color.DarkOliveGreen1_1, Color.DarkSeaGreen1_1, Color.Honeydew2, Color.LightCyan1,
|
||||
Color.Red1, Color.DeepPink2, Color.DeepPink1, Color.DeepPink1_1,
|
||||
Color.Magenta2_1, Color.Magenta1, Color.OrangeRed1, Color.IndianRed1,
|
||||
Color.IndianRed1_1, Color.HotPink, Color.HotPink_1, Color.MediumOrchid1_1,
|
||||
Color.DarkOrange, Color.Salmon1, Color.LightCoral, Color.PaleVioletRed1,
|
||||
Color.Orchid2, Color.Orchid1, Color.Orange1, Color.SandyBrown,
|
||||
Color.LightSalmon1, Color.LightPink1, Color.Pink1, Color.Plum1,
|
||||
Color.Gold1, Color.LightGoldenrod2_1, Color.LightGoldenrod2_2, Color.NavajoWhite1,
|
||||
Color.MistyRose1, Color.Thistle1, Color.Yellow1, Color.LightGoldenrod1,
|
||||
Color.Khaki1, Color.Wheat1, Color.Cornsilk1, Color.Grey100,
|
||||
Color.Grey3, Color.Grey7, Color.Grey11, Color.Grey15,
|
||||
Color.Grey19, Color.Grey23, Color.Grey27, Color.Grey30,
|
||||
Color.Grey35, Color.Grey39, Color.Grey42, Color.Grey46,
|
||||
Color.Grey50, Color.Grey54, Color.Grey58, Color.Grey62,
|
||||
Color.Grey66, Color.Grey70, Color.Grey74, Color.Grey78,
|
||||
Color.Grey82, Color.Grey85, Color.Grey89, Color.Grey93,
|
||||
};
|
||||
}
|
||||
|
||||
internal static Color ExactOrClosest(ColorSystem system, Color color)
|
||||
{
|
||||
var exact = Exact(system, color);
|
||||
if (exact != null)
|
||||
{
|
||||
return exact.Value;
|
||||
}
|
||||
|
||||
return Closest(system, color);
|
||||
}
|
||||
|
||||
private static Color? Exact(ColorSystem system, Color color)
|
||||
{
|
||||
if (system == ColorSystem.TrueColor)
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
var palette = system switch
|
||||
{
|
||||
ColorSystem.Legacy => Legacy,
|
||||
ColorSystem.Standard => Standard,
|
||||
ColorSystem.EightBit => EightBit,
|
||||
_ => throw new NotSupportedException(),
|
||||
};
|
||||
|
||||
return palette
|
||||
.Where(c => c.Equals(color))
|
||||
.Cast<Color?>()
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
private static Color Closest(ColorSystem system, Color color)
|
||||
{
|
||||
if (system == ColorSystem.TrueColor)
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
var palette = system switch
|
||||
{
|
||||
ColorSystem.Legacy => Legacy,
|
||||
ColorSystem.Standard => Standard,
|
||||
ColorSystem.EightBit => EightBit,
|
||||
_ => throw new NotSupportedException(),
|
||||
};
|
||||
|
||||
// https://stackoverflow.com/a/9085524
|
||||
static double Distance(Color first, Color second)
|
||||
{
|
||||
var rmean = ((float)first.R + second.R) / 2;
|
||||
var r = first.R - second.R;
|
||||
var g = first.G - second.G;
|
||||
var b = first.B - second.B;
|
||||
return Math.Sqrt(
|
||||
((int)((512 + rmean) * r * r) >> 8)
|
||||
+ (4 * g * g)
|
||||
+ ((int)((767 - rmean) * b * b) >> 8));
|
||||
}
|
||||
|
||||
return Enumerable.Range(0, int.MaxValue)
|
||||
.Zip(palette, (id, other) => (Distance: Distance(other, color), Id: id, Color: other))
|
||||
.OrderBy(x => x.Distance)
|
||||
.FirstOrDefault().Color;
|
||||
}
|
||||
}
|
||||
}
|
55
src/Spectre.Console/Internal/Colors/ColorSystemDetector.cs
Normal file
55
src/Spectre.Console/Internal/Colors/ColorSystemDetector.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class ColorSystemDetector
|
||||
{
|
||||
// Adapted from https://github.com/willmcgugan/rich/blob/f0c29052c22d1e49579956a9207324d9072beed7/rich/console.py#L391
|
||||
// which I think is battletested enough to trust.
|
||||
public static ColorSystem Detect(bool supportsAnsi)
|
||||
{
|
||||
if (Environment.GetEnvironmentVariables().Contains("NO_COLOR"))
|
||||
{
|
||||
// No colors supported
|
||||
return ColorSystem.NoColors;
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
if (supportsAnsi)
|
||||
{
|
||||
var regex = new Regex("^Microsoft Windows (?'major'[0-9]*).(?'minor'[0-9]*).(?'build'[0-9]*)$");
|
||||
var match = regex.Match(RuntimeInformation.OSDescription);
|
||||
if (match.Success && int.TryParse(match.Groups["major"].Value, out var major))
|
||||
{
|
||||
if (major > 10)
|
||||
{
|
||||
// Future Patrik will thank me.
|
||||
return ColorSystem.TrueColor;
|
||||
}
|
||||
|
||||
if (major == 10 && int.TryParse(match.Groups["build"].Value, out var build) && build >= 15063)
|
||||
{
|
||||
return ColorSystem.TrueColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var colorTerm = Environment.GetEnvironmentVariable("COLORTERM");
|
||||
if (!string.IsNullOrWhiteSpace(colorTerm))
|
||||
{
|
||||
if (colorTerm.Equals("truecolor", StringComparison.OrdinalIgnoreCase) ||
|
||||
colorTerm.Equals("24bit", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ColorSystem.TrueColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ColorSystem.EightBit;
|
||||
}
|
||||
}
|
||||
}
|
73
src/Spectre.Console/Internal/Composition/Composer.cs
Normal file
73
src/Spectre.Console/Internal/Composition/Composer.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal sealed class Composer : IRenderable
|
||||
{
|
||||
private readonly BlockElement _root;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length => _root.Length;
|
||||
|
||||
public Composer()
|
||||
{
|
||||
_root = new BlockElement();
|
||||
}
|
||||
|
||||
public static Composer New()
|
||||
{
|
||||
return new Composer();
|
||||
}
|
||||
|
||||
public Composer Text(string text)
|
||||
{
|
||||
_root.Append(new TextElement(text));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Foreground(Color color, Action<Composer> action)
|
||||
{
|
||||
if (action is null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
var content = new Composer();
|
||||
action(content);
|
||||
_root.Append(new ForegroundElement(color, content));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Background(Color color, Action<Composer> action)
|
||||
{
|
||||
if (action is null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
var content = new Composer();
|
||||
action(content);
|
||||
_root.Append(new BackgroundElement(color, content));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Style(Styles style, Action<Composer> action)
|
||||
{
|
||||
if (action is null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
var content = new Composer();
|
||||
action(content);
|
||||
_root.Append(new StyleElement(style, content));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
_root.Render(renderer);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Not used (yet)")]
|
||||
internal sealed class BackgroundElement : IRenderable
|
||||
{
|
||||
private readonly Color _color;
|
||||
private readonly IRenderable _element;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length => _element.Length;
|
||||
|
||||
public BackgroundElement(Color color, IRenderable element)
|
||||
{
|
||||
_color = color;
|
||||
_element = element ?? throw new ArgumentNullException(nameof(element));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
if (renderer is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(renderer));
|
||||
}
|
||||
|
||||
using (renderer.PushColor(_color, foreground: false))
|
||||
{
|
||||
_element.Render(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Not used (yet)")]
|
||||
internal sealed class BlockElement : IRenderable
|
||||
{
|
||||
private readonly List<IRenderable> _elements;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length { get; private set; }
|
||||
|
||||
public IReadOnlyList<IRenderable> Elements => _elements;
|
||||
|
||||
public BlockElement()
|
||||
{
|
||||
_elements = new List<IRenderable>();
|
||||
}
|
||||
|
||||
public BlockElement Append(IRenderable element)
|
||||
{
|
||||
if (element != null)
|
||||
{
|
||||
_elements.Add(element);
|
||||
Length += element.Length;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
foreach (var element in _elements)
|
||||
{
|
||||
element.Render(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Not used (yet)")]
|
||||
internal sealed class ForegroundElement : IRenderable
|
||||
{
|
||||
private readonly Color _color;
|
||||
private readonly IRenderable _element;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length => _element.Length;
|
||||
|
||||
public ForegroundElement(Color color, IRenderable element)
|
||||
{
|
||||
_color = color;
|
||||
_element = element ?? throw new ArgumentNullException(nameof(element));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
if (renderer is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(renderer));
|
||||
}
|
||||
|
||||
using (renderer.PushColor(_color, foreground: true))
|
||||
{
|
||||
_element.Render(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Not used (yet)")]
|
||||
internal sealed class LineBreakElement : IRenderable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public int Length => 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
renderer.Write(Environment.NewLine);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Not used (yet)")]
|
||||
internal sealed class StyleElement : IRenderable
|
||||
{
|
||||
private readonly Styles _style;
|
||||
private readonly IRenderable _element;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length => _element.Length;
|
||||
|
||||
public StyleElement(Styles style, IRenderable element)
|
||||
{
|
||||
_style = style;
|
||||
_element = element ?? throw new ArgumentNullException(nameof(element));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
if (renderer is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(renderer));
|
||||
}
|
||||
|
||||
using (renderer.PushStyle(_style))
|
||||
{
|
||||
_element.Render(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Not used (yet)")]
|
||||
internal sealed class TextElement : IRenderable
|
||||
{
|
||||
private readonly string _text;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Length => _text.Length;
|
||||
|
||||
public TextElement(string text)
|
||||
{
|
||||
_text = text ?? throw new System.ArgumentNullException(nameof(text));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Render(IAnsiConsole renderer)
|
||||
{
|
||||
renderer.Write(_text);
|
||||
}
|
||||
}
|
||||
}
|
19
src/Spectre.Console/Internal/Composition/IRenderable.cs
Normal file
19
src/Spectre.Console/Internal/Composition/IRenderable.cs
Normal file
@ -0,0 +1,19 @@
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents something that can be rendered to a console.
|
||||
/// </summary>
|
||||
internal interface IRenderable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the length of the element.
|
||||
/// </summary>
|
||||
int Length { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Renders the element using the specified renderer.
|
||||
/// </summary>
|
||||
/// <param name="console">The renderer to use.</param>
|
||||
void Render(IAnsiConsole console);
|
||||
}
|
||||
}
|
36
src/Spectre.Console/Internal/ConsoleBuilder.cs
Normal file
36
src/Spectre.Console/Internal/ConsoleBuilder.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using Spectre.Console.Internal;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
internal static class ConsoleBuilder
|
||||
{
|
||||
public static IAnsiConsole Build(AnsiConsoleSettings settings)
|
||||
{
|
||||
if (settings is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(settings));
|
||||
}
|
||||
|
||||
var buffer = settings.Out ?? System.Console.Out;
|
||||
|
||||
var supportsAnsi = settings.Ansi == AnsiSupport.Detect
|
||||
? AnsiDetector.SupportsAnsi(true)
|
||||
: settings.Ansi == AnsiSupport.Yes;
|
||||
|
||||
var colorSystem = settings.ColorSystem == ColorSystemSupport.Detect
|
||||
? ColorSystemDetector.Detect(supportsAnsi)
|
||||
: (ColorSystem)settings.ColorSystem;
|
||||
|
||||
if (supportsAnsi)
|
||||
{
|
||||
return new AnsiConsoleRenderer(buffer, colorSystem)
|
||||
{
|
||||
Style = Styles.None,
|
||||
};
|
||||
}
|
||||
|
||||
return new FallbackConsoleRenderer(buffer, colorSystem);
|
||||
}
|
||||
}
|
||||
}
|
8
src/Spectre.Console/Internal/Constants.cs
Normal file
8
src/Spectre.Console/Internal/Constants.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class Constants
|
||||
{
|
||||
public const int DefaultBufferWidth = 80;
|
||||
public const int DefaultBufferHeight = 9001;
|
||||
}
|
||||
}
|
101
src/Spectre.Console/Internal/Extensions/ConsoleExtensions.cs
Normal file
101
src/Spectre.Console/Internal/Extensions/ConsoleExtensions.cs
Normal file
@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class ConsoleExtensions
|
||||
{
|
||||
public static IDisposable PushColor(this IAnsiConsole console, Color color, bool foreground)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
var current = console.Foreground;
|
||||
console.SetColor(color, foreground);
|
||||
return new ColorScope(console, current, foreground);
|
||||
}
|
||||
|
||||
public static IDisposable PushStyle(this IAnsiConsole console, Styles style)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
var current = console.Style;
|
||||
console.Style = style;
|
||||
return new StyleScope(console, current);
|
||||
}
|
||||
|
||||
public static void SetColor(this IAnsiConsole console, Color color, bool foreground)
|
||||
{
|
||||
if (console is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(console));
|
||||
}
|
||||
|
||||
if (foreground)
|
||||
{
|
||||
console.Foreground = color;
|
||||
}
|
||||
else
|
||||
{
|
||||
console.Background = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ColorScope : IDisposable
|
||||
{
|
||||
private readonly IAnsiConsole _console;
|
||||
private readonly Color _color;
|
||||
private readonly bool _foreground;
|
||||
|
||||
public ColorScope(IAnsiConsole console, Color color, bool foreground)
|
||||
{
|
||||
_console = console ?? throw new ArgumentNullException(nameof(console));
|
||||
_color = color;
|
||||
_foreground = foreground;
|
||||
}
|
||||
|
||||
[SuppressMessage("Design", "CA1065:Do not raise exceptions in unexpected locations")]
|
||||
[SuppressMessage("Performance", "CA1821:Remove empty Finalizers")]
|
||||
~ColorScope()
|
||||
{
|
||||
throw new InvalidOperationException("Color scope was not disposed.");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
_console.SetColor(_color, _foreground);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class StyleScope : IDisposable
|
||||
{
|
||||
private readonly IAnsiConsole _console;
|
||||
private readonly Styles _style;
|
||||
|
||||
public StyleScope(IAnsiConsole console, Styles color)
|
||||
{
|
||||
_console = console ?? throw new ArgumentNullException(nameof(console));
|
||||
_style = color;
|
||||
}
|
||||
|
||||
[SuppressMessage("Design", "CA1065:Do not raise exceptions in unexpected locations")]
|
||||
[SuppressMessage("Performance", "CA1821:Remove empty Finalizers")]
|
||||
~StyleScope()
|
||||
{
|
||||
throw new InvalidOperationException("Style scope was not disposed.");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
_console.Style = _style;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class TextWriterExtensions
|
||||
{
|
||||
[SuppressMessage("Design", "CA1031:Do not catch general exception types")]
|
||||
public static bool IsStandardOut(this TextWriter writer)
|
||||
{
|
||||
try
|
||||
{
|
||||
return writer == System.Console.Out;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
100
src/Spectre.Console/Internal/Rendering/AnsiConsoleRenderer.cs
Normal file
100
src/Spectre.Console/Internal/Rendering/AnsiConsoleRenderer.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal sealed class AnsiConsoleRenderer : IAnsiConsole
|
||||
{
|
||||
private readonly TextWriter _out;
|
||||
private readonly ColorSystem _system;
|
||||
|
||||
public AnsiConsoleCapabilities Capabilities { get; }
|
||||
public Styles Style { get; set; }
|
||||
public Color Foreground { get; set; }
|
||||
public Color Background { get; set; }
|
||||
|
||||
public int Width
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
return System.Console.BufferWidth;
|
||||
}
|
||||
|
||||
return Constants.DefaultBufferWidth;
|
||||
}
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
return System.Console.BufferHeight;
|
||||
}
|
||||
|
||||
return Constants.DefaultBufferHeight;
|
||||
}
|
||||
}
|
||||
|
||||
public AnsiConsoleRenderer(TextWriter @out, ColorSystem system)
|
||||
{
|
||||
_out = @out ?? throw new ArgumentNullException(nameof(@out));
|
||||
_system = system;
|
||||
|
||||
Capabilities = new AnsiConsoleCapabilities(true, system);
|
||||
Foreground = Color.Default;
|
||||
Background = Color.Default;
|
||||
Style = Styles.None;
|
||||
}
|
||||
|
||||
public void Reset(bool colors, bool styles)
|
||||
{
|
||||
if (colors)
|
||||
{
|
||||
Foreground = Color.Default;
|
||||
Background = Color.Default;
|
||||
}
|
||||
|
||||
if (styles)
|
||||
{
|
||||
Style = Styles.None;
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_out.Write(AnsiBuilder.GetAnsi(
|
||||
_system,
|
||||
text,
|
||||
Style,
|
||||
Foreground,
|
||||
Background));
|
||||
}
|
||||
|
||||
public void WriteLine(string text)
|
||||
{
|
||||
if (text == null)
|
||||
{
|
||||
_out.WriteLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
_out.WriteLine(
|
||||
AnsiBuilder.GetAnsi(
|
||||
_system,
|
||||
text,
|
||||
Style,
|
||||
Foreground,
|
||||
Background));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal sealed class FallbackConsoleRenderer : IAnsiConsole
|
||||
{
|
||||
private readonly ConsoleColor _defaultForeground;
|
||||
private readonly ConsoleColor _defaultBackground;
|
||||
|
||||
private readonly TextWriter _out;
|
||||
private readonly ColorSystem _system;
|
||||
private ConsoleColor _foreground;
|
||||
private ConsoleColor _background;
|
||||
|
||||
public AnsiConsoleCapabilities Capabilities { get; }
|
||||
|
||||
public int Width
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
return System.Console.BufferWidth;
|
||||
}
|
||||
|
||||
return Constants.DefaultBufferWidth;
|
||||
}
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
return System.Console.BufferHeight;
|
||||
}
|
||||
|
||||
return Constants.DefaultBufferHeight;
|
||||
}
|
||||
}
|
||||
|
||||
public Styles Style { get; set; }
|
||||
|
||||
public Color Foreground
|
||||
{
|
||||
get => _foreground;
|
||||
set
|
||||
{
|
||||
_foreground = Color.ToConsoleColor(value);
|
||||
if (_system != ColorSystem.NoColors && _out.IsStandardOut())
|
||||
{
|
||||
if ((int)_foreground == -1)
|
||||
{
|
||||
_foreground = _defaultForeground;
|
||||
}
|
||||
|
||||
System.Console.ForegroundColor = _foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Color Background
|
||||
{
|
||||
get => _background;
|
||||
set
|
||||
{
|
||||
_background = Color.ToConsoleColor(value);
|
||||
if (_system != ColorSystem.NoColors && _out.IsStandardOut())
|
||||
{
|
||||
if ((int)_background == -1)
|
||||
{
|
||||
_background = _defaultBackground;
|
||||
}
|
||||
|
||||
if (_system != ColorSystem.NoColors)
|
||||
{
|
||||
System.Console.BackgroundColor = _background;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FallbackConsoleRenderer(TextWriter @out, ColorSystem system)
|
||||
{
|
||||
_out = @out;
|
||||
_system = system;
|
||||
|
||||
Capabilities = new AnsiConsoleCapabilities(false, _system);
|
||||
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
_defaultForeground = System.Console.ForegroundColor;
|
||||
_defaultBackground = System.Console.BackgroundColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
_defaultForeground = ConsoleColor.Gray;
|
||||
_defaultBackground = ConsoleColor.Black;
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(string text)
|
||||
{
|
||||
_out.Write(text);
|
||||
}
|
||||
|
||||
public void WriteLine(string text)
|
||||
{
|
||||
if (text == null)
|
||||
{
|
||||
_out.WriteLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
_out.WriteLine(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
src/Spectre.Console/Spectre.Console.csproj
Normal file
21
src/Spectre.Console/Spectre.Console.csproj
Normal file
@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="..\stylecop.json" Link="stylecop.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Color.*.cs">
|
||||
<DependentUpon>Color.cs</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Memory" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
75
src/Spectre.Console/Styles.cs
Normal file
75
src/Spectre.Console/Styles.cs
Normal file
@ -0,0 +1,75 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a style.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Support for different styles is up to the terminal.
|
||||
/// </remarks>
|
||||
[Flags]
|
||||
public enum Styles
|
||||
{
|
||||
/// <summary>
|
||||
/// No style.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Bold text.
|
||||
/// Not supported in every environment.
|
||||
/// </summary>
|
||||
Bold = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// Dim or faint text.
|
||||
/// Not supported in every environment.
|
||||
/// </summary>
|
||||
Dim = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// Italic text.
|
||||
/// Not supported in every environment.
|
||||
/// </summary>
|
||||
Italic = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// Underlined text.
|
||||
/// Not supported in every environment.
|
||||
/// </summary>
|
||||
Underline = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// Swaps the foreground and background colors.
|
||||
/// Not supported in every environment.
|
||||
/// </summary>
|
||||
Invert = 1 << 4,
|
||||
|
||||
/// <summary>
|
||||
/// Hides the text.
|
||||
/// Not supported in every environment.
|
||||
/// </summary>
|
||||
Conceal = 1 << 5,
|
||||
|
||||
/// <summary>
|
||||
/// Makes text blink.
|
||||
/// Normally less than 150 blinks per minute.
|
||||
/// Not supported in every environment.
|
||||
/// </summary>
|
||||
SlowBlink = 1 << 6,
|
||||
|
||||
/// <summary>
|
||||
/// Makes text blink.
|
||||
/// Normally more than 150 blinks per minute.
|
||||
/// Not supported in every environment.
|
||||
/// </summary>
|
||||
RapidBlink = 1 << 7,
|
||||
|
||||
/// <summary>
|
||||
/// Shows text with a horizontal line through the center.
|
||||
/// Not supported in every environment.
|
||||
/// </summary>
|
||||
Strikethrough = 1 << 8,
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user