Fix bug when splitting text containing CJK chars

In Segment.Split, we didn't take cell width into account
when calculating the offset, which resulted in some "fun" bugs.
I've added a new overload for Segment.Split and obsoleted the old one.

Closes #150
This commit is contained in:
Patrik Svensson
2020-12-16 23:30:03 +01:00
committed by Patrik Svensson
parent ee305702e8
commit 6932c95731
5 changed files with 125 additions and 29 deletions

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Spectre.Console.Internal;
namespace Spectre.Console.Rendering
{
@ -145,6 +146,7 @@ namespace Spectre.Console.Rendering
/// </summary>
/// <param name="offset">The offset where to split the segment.</param>
/// <returns>One or two new segments representing the split.</returns>
[Obsolete("Use Split(RenderContext, Int32) instead")]
public (Segment First, Segment? Second) Split(int offset)
{
if (offset < 0)
@ -162,6 +164,44 @@ namespace Spectre.Console.Rendering
new Segment(Text.Substring(offset, Text.Length - offset), Style));
}
/// <summary>
/// Splits the segment at the offset.
/// </summary>
/// <param name="context">The render context.</param>
/// <param name="offset">The offset where to split the segment.</param>
/// <returns>One or two new segments representing the split.</returns>
public (Segment First, Segment? Second) Split(RenderContext context, int offset)
{
if (offset < 0)
{
return (this, null);
}
if (offset >= CellCount(context))
{
return (this, null);
}
var index = 0;
if (offset > 0)
{
var accumulated = 0;
foreach (var character in Text)
{
index++;
accumulated += Cell.GetCellLength(context, character);
if (accumulated >= offset)
{
break;
}
}
}
return (
new Segment(Text.Substring(0, index), Style),
new Segment(Text.Substring(index, Text.Length - index), Style));
}
/// <summary>
/// Clones the segment.
/// </summary>
@ -219,14 +259,16 @@ namespace Spectre.Console.Rendering
while (stack.Count > 0)
{
var segment = stack.Pop();
var segmentLength = segment.CellCount(context);
// Does this segment make the line exceed the max width?
if (line.CellCount(context) + segment.CellCount(context) > maxWidth)
var lineLength = line.CellCount(context);
if (lineLength + segmentLength > maxWidth)
{
var diff = -(maxWidth - (line.Length + segment.Text.Length));
var diff = -(maxWidth - (lineLength + segmentLength));
var offset = segment.Text.Length - diff;
var (first, second) = segment.Split(offset);
var (first, second) = segment.Split(context, offset);
line.Add(first);
lines.Add(line);