From d306ad82d18a97018772037d6cd99a1bab325dd4 Mon Sep 17 00:00:00 2001 From: Liam Sho Date: Thu, 12 Aug 2021 21:50:31 +0800 Subject: [PATCH] Fix ArgumentOutOfRangeException when rendering a table When rendering a table with East Asia characters (take 2 English alphabets width) will throw ArgumentOutOfRangeException. --- src/Spectre.Console/Rendering/Segment.cs | 44 +++++++++++++++--------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/Spectre.Console/Rendering/Segment.cs b/src/Spectre.Console/Rendering/Segment.cs index ad2fb63..c998abc 100644 --- a/src/Spectre.Console/Rendering/Segment.cs +++ b/src/Spectre.Console/Rendering/Segment.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; +using Wcwidth; namespace Spectre.Console.Rendering { @@ -329,23 +330,10 @@ namespace Spectre.Console.Rendering if (overflow == Overflow.Fold) { - var totalLength = segment.Text.CellLength(); - var lengthLeft = totalLength; - while (lengthLeft > 0) + var splitted = SplitSegment(segment.Text, maxWidth); + foreach (var str in splitted) { - var index = totalLength - lengthLeft; - - // How many characters should we take? - var take = Math.Min(maxWidth, totalLength - index); - if (take <= 0) - { - // This shouldn't really occur, but I don't like - // never ending loops if it does... - return new List(); - } - - result.Add(new Segment(segment.Text.Substring(index, take), segment.Style)); - lengthLeft -= take; + result.Add(new Segment(str, segment.Style)); } } else if (overflow == Overflow.Crop) @@ -567,5 +555,29 @@ namespace Spectre.Console.Rendering return cells; } + + internal static List SplitSegment(string text, int maxCellLength) + { + var list = new List(); + + var length = 0; + var sb = new StringBuilder(); + foreach (var ch in text) + { + if (length + UnicodeCalculator.GetWidth(ch) > maxCellLength) + { + list.Add(sb.ToString()); + sb.Clear(); + length = 0; + } + + length += UnicodeCalculator.GetWidth(ch); + sb.Append(ch); + } + + list.Add(sb.ToString()); + + return list; + } } }