public void ImplicitStringifyingWorks() { var s = new ColoredString("text", ConsoleColor.Blue); string str = s; str.Should().Be("text"); }
/// <summary> /// Generate a new string from this one, with any trailing whitespace /// removed. /// </summary> /// <returns>The new string.</returns> public IString TrimEnd() { var pieces = Content.ToList(); // Trim off all 0-length substrings. while (pieces.Count > 0 && pieces.Last().Length == 0) { pieces.RemoveAt(pieces.Count - 1); } // Trim. while (pieces.Count > 0 && char.IsWhiteSpace(pieces.Last().Content.Last())) { var updatedPiece = pieces.Last(); pieces.RemoveAt(pieces.Count - 1); updatedPiece = new ColoredString(updatedPiece.Content.TrimEnd(), updatedPiece.ForegroundColor, updatedPiece.BackgroundColor); if (updatedPiece.Length > 0) { pieces.Add(updatedPiece); } } return(new ColoredMultistring(pieces)); }
/// <summary> /// Wrap the provided text at the given width, indenting it with the /// given indentation width. /// </summary> /// <param name="text">Text to wrap.</param> /// <param name="width">Maximum width of the text, in number of /// characters.</param> /// <param name="indent">The number of characters to indent /// lines; 0 to indicate no indentation should occur.</param> /// <param name="hangingIndent">The number of characters to /// unindent the first line.</param> /// <returns>The wrapped text.</returns> public static ColoredString Wrap(this ColoredString text, int width, int indent = 0, int hangingIndent = 0) { var wrapped = Wrap(text.Content, width, indent, hangingIndent); Debug.Assert(wrapped != null); return(new ColoredString(wrapped, text.ForegroundColor, text.BackgroundColor)); }
/// <summary> /// Transform the given string into a new one, preserving color. /// </summary> /// <param name="s">The input string.</param> /// <param name="func">The function to apply.</param> /// <returns>The generated string.</returns> /// <exception cref="ArgumentNullException">Thrown when <paramref name="func"/> /// is null.</exception> public static ColoredString Transform(this ColoredString s, Func <string, string> func) { if (func == null) { throw new ArgumentNullException(nameof(func)); } return(new ColoredString(func(s.Content), s.ForegroundColor, s.BackgroundColor)); }
/// <summary> /// Take the color of the given string to produce a new one, but with the given /// content. /// </summary> /// <param name="s">The input string.</param> /// <param name="newContent">The new content to use.</param> /// <returns>The generated string.</returns> /// <exception cref="ArgumentNullException">Thrown when <paramref name="newContent"/> /// is null.</exception> public static ColoredString WithContent(this ColoredString s, string newContent) { if (newContent == null) { throw new ArgumentNullException(nameof(newContent)); } return(s.Transform(_ => newContent)); }
public void StringEqualsItself() { var s = new ColoredString("text", ConsoleColor.Blue, ConsoleColor.DarkGray); #pragma warning disable CS1718 // Comparison made to same variable (s == s).Should().BeTrue(); (s != s).Should().BeFalse(); #pragma warning restore CS1718 // Comparison made to same variable s.Equals(s).Should().BeTrue(); s.Equals((object)s).Should().BeTrue(); s.Equals(s, StringComparison.Ordinal).Should().BeTrue(); s.GetHashCode().Should().Be(s.GetHashCode()); }
public void StringsWithDifferentCases() { var s1 = new ColoredString("text", ConsoleColor.Blue, ConsoleColor.DarkGray); var s2 = new ColoredString("TEXT", ConsoleColor.Blue, ConsoleColor.DarkGray); (s1 == s2).Should().BeFalse(); (s1 != s2).Should().BeTrue(); s1.Equals(s2).Should().BeFalse(); s1.Equals((object)s2).Should().BeFalse(); s1.Equals(s2, StringComparison.Ordinal).Should().BeFalse(); s1.Equals(s2, StringComparison.OrdinalIgnoreCase).Should().BeTrue(); s1.GetHashCode().Should().NotBe(s2.GetHashCode()); }
public void StringsWithDifferentColorsAreNotEqual() { var s1 = new ColoredString("text", ConsoleColor.Blue, ConsoleColor.DarkGray); var s2 = new ColoredString("text", ConsoleColor.Green, ConsoleColor.Red); #pragma warning disable CS1718 // Comparison made to same variable (s1 == s2).Should().BeFalse(); (s1 != s2).Should().BeTrue(); #pragma warning restore CS1718 // Comparison made to same variable s1.Equals(s2).Should().BeFalse(); s1.Equals((object)s2).Should().BeFalse(); s1.Equals(s2, StringComparison.Ordinal).Should().BeFalse(); s1.GetHashCode().Should().NotBe(s2.GetHashCode()); }
/// <summary> /// Compares the specified object against this object. /// </summary> /// <param name="value">The object to compare.</param> /// <returns>True if the objects are equal; false otherwise.</returns> public bool Equals(ColoredString value) => Equals(value, StringComparison.Ordinal);
/// <summary> /// Writes colored text to the console. /// </summary> /// <param name="text">The text to write.</param> public void Write(ColoredString text) { Write(text.Content); }
/// <summary> /// Append a colored string followed by a newline. /// </summary> /// <param name="value">The colored string to append.</param> public void AppendLine(ColoredString value) { Append(value); Append(value.Transform(content => Environment.NewLine)); }
/// <summary> /// Append a colored string. /// </summary> /// <param name="value">The colored string to append.</param> public void Append(ColoredString value) => Insert(Length, value);
/// <summary> /// Inserts the given string at the specified index. /// </summary> /// <param name="index">0-based index.</param> /// <param name="s">The string to insert.</param> public void Insert(int index, ColoredString s) { if (index < 0 || index > Length) { throw new ArgumentOutOfRangeException(nameof(index)); } // Optimization: don't bother if string is empty. if (s.IsEmpty()) { return; } // // At this point, we're guaranteed it's either before or in // the middle of the existing contents. // var pieceIndex = 0; var offset = 0; ColoredString?lastPiece = null; while (pieceIndex < _pieces.Count) { var piece = _pieces[pieceIndex]; Debug.Assert(!piece.IsEmpty()); // Case 1: insertion point is just before this piece. if (index == offset) { if (s.IsSameColorAs(piece)) { _pieces.RemoveAt(pieceIndex); _pieces.Insert(pieceIndex, piece.Transform(content => s.Content + content)); } else { _pieces.Insert(pieceIndex, s); } _totalLength += s.Length; return; } // Case 2: insertion point is in middle of this piece. else if (index < offset + piece.Length) { _pieces.RemoveAt(pieceIndex); if (s.IsSameColorAs(piece)) { _pieces.Insert(pieceIndex, piece.Transform(content => content.Substring(0, index - offset) + s.Content + content.Substring(index - offset))); } else { _pieces.Insert(pieceIndex, piece.Substring(0, index - offset)); _pieces.Insert(pieceIndex + 1, s); _pieces.Insert(pieceIndex + 2, piece.Substring(index - offset)); } _totalLength += s.Length; return; } // Case 3: insertion point is just after this piece. // Only insert during this loop iteration if new piece // can be merged with this one. We'll otherwise get it // the next time around. else if (index == offset + piece.Length) { if (s.IsSameColorAs(piece)) { _pieces.RemoveAt(pieceIndex); _pieces.Insert(pieceIndex, piece.Transform(content => content + s.Content)); _totalLength += s.Length; return; } } offset += piece.Length; lastPiece = piece; ++pieceIndex; } // If we're still here, then it goes at the end. Debug.Assert(index == Length); // Append. _pieces.Add(s); _totalLength += s.Length; }
/// <summary> /// Append a colored string followed by a newline. /// </summary> /// <param name="value">The colored string to append.</param> public void AppendLine(ColoredString value) { _pieces.Add(value); _pieces.Add(new ColoredString(Environment.NewLine, value.ForegroundColor, value.BackgroundColor)); }
/// <summary> /// Returns a new string containing a substring of the given string. /// </summary> /// <param name="s">The string.</param> /// <param name="startIndex">The 0-based index to start from.</param> /// <param name="length">The length of the substring, expressed as /// a count of characters.</param> /// <returns>The new string.</returns> public static ColoredString Substring(this ColoredString s, int startIndex, int length) => s.Transform(content => content.Substring(startIndex, length));
/// <summary> /// Append a colored string followed by a newline. /// </summary> /// <param name="value">The colored string to append.</param> public void AppendLine(ColoredString value) { _pieces.Add(value); _pieces.Add(new ColoredString(Environment.NewLine, value.ForegroundColor, value.BackgroundColor)); }
/// <summary> /// Append a colored string. /// </summary> /// <param name="value">The colored string to append.</param> public void Append(ColoredString value) => _pieces.Add(value);
/// <summary> /// Wrap the provided text at the given width, indenting it with the /// given indentation width. /// </summary> /// <param name="text">Text to wrap.</param> /// <param name="width">Maximum width of the text, in number of /// characters.</param> /// <param name="blockIndent">The number of characters to block-indent /// all lines. Use 0 to indicate no block indentation should occur.</param> /// <param name="hangingIndent">The number of characters to hanging-indent /// the text; all lines after the first line are affected, and the first /// line is left unmodified. Use 0 to indicate no hanging indentation /// should occur.</param> /// <returns>The wrapped text.</returns> public static ColoredString Wrap(this ColoredString text, int width, int blockIndent = 0, int hangingIndent = 0) => text.Transform(content => Wrap(content, width, blockIndent, hangingIndent));
/// <summary> /// Compares the specified object against this object. /// </summary> /// <param name="value">The object to compare.</param> /// <param name="comparisonType">Type of comparison to perform.</param> /// <returns>True if the objects are equal; false otherwise.</returns> public bool Equals(ColoredString value, StringComparison comparisonType) => Content.Equals(value.Content, comparisonType) && (ForegroundColor == value.ForegroundColor) && (BackgroundColor == value.BackgroundColor);
/// <summary> /// Append a colored string. /// </summary> /// <param name="value">The colored string to append.</param> public void Append(ColoredString value) => _pieces.Add(value);
/// <summary> /// Simple constructor. /// </summary> /// <param name="value">String content.</param> public ColoredMultistring(ColoredString value) { Content = new[] { value }; }
public void ConstructorWorks() { var s = new ColoredString("text", ConsoleColor.Blue); }