using System.Text;
#nullable disable
namespace InteractiveReadLine.Formatting
{
///
/// Represents a formatted string, where each character has a potentially unique foreground and background
/// color assigned to it.
///
public class FormattedText : IEquatable
{
public FormattedText(string text, ConsoleColor? foreground = null, ConsoleColor? background = null)
{
this.Text = text;
this.Foreground = new ConsoleColor?[this.Text.Length];
this.Background = new ConsoleColor?[this.Text.Length];
for (int i = 0; i < this.Text.Length; i++)
{
this.Foreground[i] = foreground;
this.Background[i] = background;
}
}
public FormattedText(FormattedChar c)
: this(c.Char.ToString(), c.Foreground, c.Background)
{
}
///
/// Gets the characters in the text as a string without any formatting
///
public string Text { get; }
///
/// Gets the length of the text
///
public int Length => Text.Length;
///
/// Gets the character and its formatting at position i in the text
///
///
public FormattedChar this[int index] => new FormattedChar(this.Text[index], this.Foreground[index], this.Background[index]);
///
/// Gets the foreground color array of the text
///
public ConsoleColor?[] Foreground { get; }
///
/// Gets the background color array of the text
///
public ConsoleColor?[] Background { get; }
///
/// Sets the foreground color for every character in the text
///
///
public void SetForeground(ConsoleColor? color)
{
for (int i = 0; i < this.Text.Length; i++)
{
Foreground[i] = color;
}
}
///
/// Sets the background color for every character in the text
///
///
public void SetBackground(ConsoleColor? color)
{
for (int i = 0; i < this.Text.Length; i++)
{
Background[i] = color;
}
}
///
/// Splits the formatted text object into an array of FormattedText objects, in which each element of the array
/// consists of text where every character has the same foreground and background colors.
///
///
public FormattedText[] SplitByFormatting()
{
if (this.Text == string.Empty)
{
return Array.Empty();
}
var result = new List();
var buffer = new StringBuilder();
ConsoleColor? fore = null;
ConsoleColor? back = null;
buffer.Append(this.Text[0]);
fore = this.Foreground[0];
back = this.Background[0];
for (int i = 1; i < this.Text.Length; i++)
{
if (fore != this.Foreground[i] || back != this.Background[i])
{
// Either the foreground or the background has changed, so we need to
// finish the existing buffer and start a new one
result.Add(new FormattedText(buffer.ToString(), fore, back));
buffer.Clear();
fore = this.Foreground[i];
back = this.Background[i];
}
buffer.Append(this.Text[i]);
}
// Add the final buffer
result.Add(new FormattedText(buffer.ToString(), fore, back));
return result.ToArray();
}
public static implicit operator FormattedText(string s) => new FormattedText(s);
public static implicit operator FormattedText(FormattedChar c) => new FormattedText(c);
public static FormattedText operator +(FormattedText lhs, FormattedText rhs)
{
var product = new FormattedText(lhs.Text + rhs.Text);
for (int i = 0; i < lhs.Text.Length; i++)
{
product.Foreground[i] = lhs.Foreground[i];
product.Background[i] = lhs.Background[i];
}
for (int i = 0; i < rhs.Text.Length; i++)
{
product.Foreground[i + lhs.Text.Length] = rhs.Foreground[i];
product.Background[i + lhs.Text.Length] = rhs.Background[i];
}
return product;
}
public bool Equals(FormattedText other)
{
if (other == null || this.Text != other.Text)
return false;
for (int i = 0; i < this.Length; i++)
{
if (this.Foreground[i] != other.Foreground[i])
return false;
if (this.Background[i] != other.Background[i])
return false;
}
return true;
}
}
}