namespace InnovEnergy.Lib.Utils; public class TextBlock { private readonly IReadOnlyList _Lines; private TextBlock(params String[] lines) => _Lines = lines; public override String ToString() => _Lines.JoinLines(); public static TextBlock Empty { get; } = new TextBlock(); public static TextBlock AlignLeft(IEnumerable things) { var lines = things .SelectMany(GetLines) .Unless(String.IsNullOrEmpty) .ToList(); if (!lines.Any()) return Empty; var width = lines.Max(l => l.Length); var alignedLines = lines .Select(l => l.PadRight(width)) .ToArray(lines.Count); return new TextBlock(alignedLines); } private static TextBlock AlignRight(IReadOnlyList things) { var lines = things .SelectMany(GetLines) .Unless(String.IsNullOrEmpty) .ToList(); if (!lines.Any()) return Empty; var width = lines.Max(l => l.Length); var alignedLines = lines .Select(l => l.PadLeft(width)) .ToArray(lines.Count); return new TextBlock(alignedLines); } public static TextBlock AlignCenterHorizontal(IReadOnlyList things) { var lines = things .SelectMany(GetLines) .Where(l => !String.IsNullOrEmpty(l)) .ToList(); if (!lines.Any()) return Empty; var width = lines.Max(l => l.Length); var alignedLines = lines .Select(l => l.PadLeft((width + l.Length) / 2).PadRight(width)) .ToArray(lines.Count); return new TextBlock(alignedLines); } public static TextBlock AlignTop(IReadOnlyList things) { var columns = things .Select(GetLines) .Where(c => c.Count > 0) .ToList(); if (!columns.Any()) return Empty; var height = columns.Max(l => l.Count); var alignedLines = Enumerable .Range(0, height) .Select(l => columns.Select(c => c.ElementAtOr(l, Space(c[0].Length))).Join()) .ToArray(height); return new TextBlock(alignedLines); } public static TextBlock AlignBottom(IReadOnlyList things) { var columns = things .Select(GetLines) .Where(c => c.Count > 0) .ToList(); if (!columns.Any()) return Empty; var height = columns.Max(l => l.Count); var alignedLines = Enumerable .Range(0, height) .Select(l => columns.Select(c => c.ElementAtOr(c.Count - height + l, Space(c[0].Length))).Join()) .ToArray(height); return new TextBlock(alignedLines); } public static TextBlock AlignCenterVertical(IReadOnlyList things) { var columns = things .Select(GetLines) .Where(c => c.Count > 0) .ToList(); if (!columns.Any()) return Empty; var height = columns.Max(l => l.Count); var alignedLines = Enumerable .Range(0, height) .Select(l => columns.Select(c => c.ElementAtOr((c.Count - height) / 2 + l, Space(c[0].Length))).Join()) .ToArray(height); return new TextBlock(alignedLines); } public static TextBlock AlignLeft (params Object?[] things) => AlignLeft ((IReadOnlyList) things); public static TextBlock AlignRight (params Object?[] things) => AlignRight ((IReadOnlyList) things); public static TextBlock AlignTop (params Object?[] things) => AlignTop ((IReadOnlyList) things); public static TextBlock AlignBottom (params Object?[] things) => AlignBottom ((IReadOnlyList) things); public static TextBlock AlignCenterVertical (params Object?[] things) => AlignCenterVertical ((IReadOnlyList) things); public static TextBlock AlignCenterHorizontal(params Object?[] things) => AlignCenterHorizontal((IReadOnlyList) things); public static TextBlock FromString(String thing) => AlignLeft(thing); public TextBlock Box() { var width = _Lines.Any() ? _Lines.Max(l => l.Length) : 0; var hLine = "".PadRight(width + 2, '─'); var top = "┌" + hLine + "┐"; var bottom = "└" + hLine + "┘"; var lines = _Lines .Select(l => l.SurroundWith(" ")) .Select(l => l.SurroundWith("│")) .Prepend(top) .Append(bottom) .ToArray(_Lines.Count + 2); return new TextBlock(lines); } public TextBlock TitleBox(String title) { var linesWidth = _Lines.Any() ? _Lines.Max(l => l.Length) : 0; var titleWidth = title.Length; var width = Math.Max(linesWidth, titleWidth); var hLine = "".PadRight(width + 2, '─'); var top = "┌" + hLine + "┐"; var between = "├" + hLine + "┤"; var bottom = "└" + hLine + "┘"; var centeredTitle = "│ " + title.PadLeft((width + title.Length) / 2).PadRight(width) + " │"; var lines = _Lines .Select(l => l.PadRight(width)) .Select(l => l.SurroundWith(" ")) .Select(l => l.SurroundWith("│")) .Prepend(between) .Prepend(centeredTitle) .Prepend(top) .Append(bottom) .ToArray(); return new TextBlock(lines); } public static TextBlock Spacer(Int32 n) { return new TextBlock(Enumerable.Repeat("".PadRight(n), n).ToArray(n)); } public static TextBlock HorizontalSpace(Int32 n) { return new TextBlock("".PadRight(n)); } public static TextBlock VerticalSpace(Int32 n) { return new TextBlock(Enumerable.Repeat("", n).ToArray(n)); } private static IReadOnlyList GetLines(Object? t) { return t switch { TextBlock tb => tb._Lines, null => Array.Empty(), _ => t.ToString()!.SplitLines() }; } private static String Space(Int32 totalWidth) { return "".PadRight(totalWidth); } }