Add XML Document and move the Rune folder into the Text folder.

This commit is contained in:
BDisp
2023-05-10 22:44:44 +01:00
parent 2048965ba6
commit ca689a1a66
6 changed files with 346 additions and 134 deletions

View File

@@ -1,110 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Terminal.Gui {
public static class RuneExtensions {
public static Rune MaxRune = new Rune (0x10FFFF);
public static int ColumnWidth (this Rune rune)
{
return RuneUtilities.ColumnWidth (rune);
}
public static bool IsNonSpacingChar (this Rune rune)
{
return RuneUtilities.IsNonSpacingChar (rune.Value);
}
public static bool IsWideChar (this Rune rune)
{
return RuneUtilities.IsWideChar (rune.Value);
}
public static int RuneUnicodeLength (this Rune rune, Encoding encoding = null)
{
if (encoding == null) {
encoding = Encoding.UTF8;
}
var bytes = encoding.GetBytes (rune.ToString ().ToCharArray ());
var offset = 0;
if (bytes [bytes.Length - 1] == 0) {
offset++;
}
return bytes.Length - offset;
}
public static int EncodeRune (this Rune rune, byte [] dest, int start = 0, int nbytes = -1)
{
var bytes = Encoding.UTF8.GetBytes (rune.ToString ());
int length = 0;
for (int i = 0; i < (nbytes == -1 ? bytes.Length : nbytes); i++) {
if (bytes [i] == 0) {
break;
}
dest [start + i] = bytes [i];
length++;
}
return length;
}
public static (Rune Rune, int Size) DecodeRune (byte [] buffer, int start = 0, int nbytes = -1)
{
var operationStatus = Rune.DecodeFromUtf8 (buffer, out Rune rune, out int bytesConsumed);
return (rune, bytesConsumed);
}
public static (Rune Rune, int Size) DecodeLastRune (byte [] buffer, int end = -1)
{
var operationStatus = Rune.DecodeLastFromUtf8 (buffer, out Rune rune, out int bytesConsumed);
if (operationStatus == System.Buffers.OperationStatus.Done) {
return (rune, bytesConsumed);
} else {
return (default, 0);
}
}
public static bool DecodeSurrogatePair (this Rune rune, out char [] spair)
{
if (rune.IsSurrogatePair ()) {
spair = rune.ToString ().ToCharArray ();
return true;
}
spair = null;
return false;
}
public static bool EncodeSurrogatePair (char highsurrogate, char lowSurrogate, out Rune result)
{
result = default;
if (char.IsSurrogatePair (highsurrogate, lowSurrogate)) {
result = (Rune)char.ConvertToUtf32 (highsurrogate, lowSurrogate);
return true;
}
return false;
}
public static bool IsSurrogatePair (this Rune rune)
{
return char.IsSurrogatePair (rune.ToString (), 0);
}
public static bool IsValid (byte [] buffer)
{
var str = Encoding.Unicode.GetString (buffer);
foreach (var rune in str.EnumerateRunes ()) {
if (rune == Rune.ReplacementChar) {
return false;
}
}
return true;
}
public static bool IsValid (this Rune rune)
{
return Rune.IsValid (rune.Value);
}
}
}

View File

@@ -32,37 +32,93 @@ namespace Terminal.Gui {
.ToString ();
}
/// <summary>
/// Returns the number of columns used by the string on console applications.
/// It's never return less than 0, like the <see cref="RuneExtensions.ColumnWidth(Rune)"/>.
/// </summary>
/// <param name="instr">The string to measure.</param>
/// <returns></returns>
public static int ConsoleWidth (this string instr)
{
return instr.EnumerateRunes ().Sum (r => Math.Max (r.ColumnWidth (), 0));
}
/// <summary>
/// Returns the number of runes in a string.
/// </summary>
/// <param name="instr">The string to count.</param>
/// <returns></returns>
public static int RuneCount (this string instr)
{
return instr.EnumerateRunes ().Count ();
}
/// <summary>
/// Converts a string into a <see cref="Rune"/> array.
/// </summary>
/// <param name="instr">The string to convert.</param>
/// <returns></returns>
public static Rune [] ToRunes (this string instr)
{
return instr.EnumerateRunes ().ToArray ();
}
/// <summary>
/// Converts a string into a List of runes.
/// </summary>
/// <param name="instr">The string to convert.</param>
/// <returns></returns>
public static List<Rune> ToRuneList (this string instr)
{
return instr.EnumerateRunes ().ToList ();
}
/// <summary>
/// DecodeRune unpacks the first UTF-8 encoding in the string returns the rune and its width in bytes.
/// </summary>
/// <param name="instr">The string to decode.</param>
/// <param name="start">Starting offset to look into.</param>
/// <param name="nbytes">Number of bytes valid in the buffer, or -1 to make it the length of the buffer.</param>
/// <returns></returns>
public static (Rune Rune, int Size) DecodeRune (this string instr, int start = 0, int nbytes = -1)
{
return RuneExtensions.DecodeRune (Encoding.UTF8.GetBytes (instr), start, nbytes);
var rune = instr.EnumerateRunes ().ToArray () [start];
var bytes = Encoding.UTF8.GetBytes (rune.ToString ());
if (nbytes == -1) {
nbytes = bytes.Length;
}
var operationStatus = Rune.DecodeFromUtf8 (bytes, out rune, out int bytesConsumed);
if (operationStatus == System.Buffers.OperationStatus.Done && bytesConsumed >= nbytes) {
return (rune, bytesConsumed);
} else {
return (Rune.ReplacementChar, 1);
}
}
/// <summary>
/// DecodeLastRune unpacks the last UTF-8 encoding in the string.
/// </summary>
/// <param name="instr">The string to decode.</param>
/// <param name="end">Scan up to that point, if the value is -1, it sets the value to the length of the buffer.</param>
/// <returns></returns>
public static (Rune rune, int size) DecodeLastRune (this string instr, int end = -1)
{
var bytes = Encoding.UTF8.GetBytes (instr);
return RuneExtensions.DecodeLastRune (bytes, end);
var rune = instr.EnumerateRunes ().ToArray () [end == -1 ? ^1 : end];
var bytes = Encoding.UTF8.GetBytes (rune.ToString ());
var operationStatus = Rune.DecodeFromUtf8 (bytes, out rune, out int bytesConsumed);
if (operationStatus == System.Buffers.OperationStatus.Done) {
return (rune, bytesConsumed);
} else {
return (Rune.ReplacementChar, 1);
}
}
/// <summary>
/// Reports whether this <see cref="Rune"/> is a valid surrogate pair and can be decoded from UTF-16.
/// </summary>
/// <param name="instr">The string to decode.</param>
/// <param name="chars">The chars if is valid. Null otherwise.</param>
/// <returns></returns>
public static bool DecodeSurrogatePair (this string instr, out char [] chars)
{
chars = null;
@@ -76,11 +132,22 @@ namespace Terminal.Gui {
return false;
}
/// <summary>
/// Returns a version of the string as a byte array, it might allocate or return
/// the internal byte buffer, depending on the backing implementation.
/// </summary>
/// <param name="instr">The string to convert.</param>
/// <returns></returns>
public static byte [] ToByteArray (this string instr)
{
return Encoding.Unicode.GetBytes (instr.ToCharArray ());
}
/// <summary>
/// Converts a <see cref="Rune"/> array into a string.
/// </summary>
/// <param name="runes">The rune array to convert.</param>
/// <returns></returns>
public static string Make (Rune [] runes)
{
var str = string.Empty;
@@ -92,6 +159,11 @@ namespace Terminal.Gui {
return str;
}
/// <summary>
/// Converts a List of runes into a string.
/// </summary>
/// <param name="runes">The List of runes to convert.</param>
/// <returns></returns>
public static string Make (List<Rune> runes)
{
var str = string.Empty;
@@ -101,16 +173,32 @@ namespace Terminal.Gui {
return str;
}
/// <summary>
/// Converts a rune into a string.
/// </summary>
/// <param name="rune">The rune to convert.</param>
/// <returns></returns>
public static string Make (Rune rune)
{
return rune.ToString ();
}
/// <summary>
/// Converts a numeric value of a rune into a string.
/// </summary>
/// <param name="rune">The rune to convert.</param>
/// <returns></returns>
public static string Make (uint rune)
{
return ((Rune)rune).ToString ();
}
/// <summary>
/// Converts a byte array into a string in te provided encoding (default is UTF8)
/// </summary>
/// <param name="bytes">The byte array to convert.</param>
/// <param name="encoding">The encoding to be used.</param>
/// <returns></returns>
public static string Make (byte [] bytes, Encoding encoding = null)
{
if (encoding == null) {
@@ -119,6 +207,11 @@ namespace Terminal.Gui {
return encoding.GetString (bytes);
}
/// <summary>
/// Converts a array of characters into a string.
/// </summary>
/// <param name="chars">The array of characters to convert.</param>
/// <returns></returns>
public static string Make (params char [] chars)
{
var c = new char [chars.Length];

View File

@@ -0,0 +1,194 @@
using System;
using System.Text;
namespace Terminal.Gui {
/// <summary>
/// Extension helper of <see cref="System.Text.Rune"/> to work with specific text manipulation./>
/// </summary>
public static class RuneExtensions {
/// <summary>
/// Maximum valid Unicode code point.
/// </summary>
public static Rune MaxRune = new Rune (0x10FFFF);
/// <summary>
/// Number of column positions of a wide-character code.
/// This is used to measure runes as displayed by text-based terminals.
/// </summary>
/// <param name="rune">The rune to measure.</param>
/// <returns>
/// The width in columns, 0 if the argument is the null character,
/// -1 if the value is not printable,
/// otherwise the number of columns that the rune occupies.
/// </returns>
public static int ColumnWidth (this Rune rune)
{
return RuneUtilities.ColumnWidth (rune);
}
/// <summary>
/// Check if the rune is a non-spacing character.
/// </summary>
/// <param name="rune">The rune to inspect.</param>
/// <returns>True if is a non-spacing character, false otherwise.</returns>
public static bool IsNonSpacingChar (this Rune rune)
{
return RuneUtilities.IsNonSpacingChar (rune.Value);
}
/// <summary>
/// Check if the rune is a wide character.
/// </summary>
/// <param name="rune">The rune to inspect.</param>
/// <returns>True if is a wide character, false otherwise.</returns>
public static bool IsWideChar (this Rune rune)
{
return RuneUtilities.IsWideChar (rune.Value);
}
/// <summary>
/// Get number of bytes required to encode the rune, based on the provided encoding.
/// </summary>
/// <param name="rune">The rune to probe.</param>
/// <param name="encoding">The encoding used, default is UTF8.</param>
/// <returns></returns>
public static int RuneUnicodeLength (this Rune rune, Encoding encoding = null)
{
if (encoding == null) {
encoding = Encoding.UTF8;
}
var bytes = encoding.GetBytes (rune.ToString ().ToCharArray ());
var offset = 0;
if (bytes [bytes.Length - 1] == 0) {
offset++;
}
return bytes.Length - offset;
}
/// <summary>
/// Writes into the destination buffer starting at offset the UTF8 encoded version of the rune.
/// </summary>
/// <param name="rune">The rune to encode.</param>
/// <param name="dest">The destination buffer.</param>
/// <param name="start">Starting offset to look into.</param>
/// <param name="nbytes">Number of bytes valid in the buffer, or -1 to make it the length of the buffer.</param>
/// <returns>he number of bytes written into the destination buffer.</returns>
public static int EncodeRune (this Rune rune, byte [] dest, int start = 0, int nbytes = -1)
{
var bytes = Encoding.UTF8.GetBytes (rune.ToString ());
int length = 0;
for (int i = 0; i < (nbytes == -1 ? bytes.Length : nbytes); i++) {
if (bytes [i] == 0) {
break;
}
dest [start + i] = bytes [i];
length++;
}
return length;
}
/// <summary>
/// DecodeRune unpacks the first UTF-8 encoding in the string returns the rune and its width in bytes.
/// </summary>
/// <param name="rune">The rune to encode.</param>
/// <param name="buffer">The byte array to look into.</param>
/// <param name="start">Starting offset to look into.</param>
/// <param name="nbytes">Number of bytes valid in the buffer, or -1 to make it the length of the buffer.</param>
/// <returns></returns>
public static (Rune Rune, int Size) DecodeRune (this Rune rune, byte [] buffer, int start = 0, int nbytes = -1)
{
var operationStatus = Rune.DecodeFromUtf8 (buffer, out Rune nrune, out int bytesConsumed);
if (operationStatus == System.Buffers.OperationStatus.Done) {
return (nrune, bytesConsumed);
} else {
return (Rune.ReplacementChar, 1);
}
}
/// <summary>
/// DecodeLastRune unpacks the last UTF-8 encoding in the byte array.
/// </summary>
/// <param name="buffer">Buffer to decode rune from.</param>
/// <param name="end">Scan up to that point, if the value is -1, it sets the value to the length of the buffer.</param>
/// <returns></returns>
public static (Rune Rune, int Size) DecodeLastRune (byte [] buffer, int end = -1)
{
var operationStatus = Rune.DecodeLastFromUtf8 (buffer, out Rune rune, out int bytesConsumed);
if (operationStatus == System.Buffers.OperationStatus.Done) {
return (rune, bytesConsumed);
} else {
return (Rune.ReplacementChar, 1);
}
}
/// <summary>
/// Reports whether this <see cref="Rune"/> is a valid surrogate pair and can be decoded from UTF-16.
/// </summary>
/// <param name="rune">The rune to decode.</param>
/// <param name="chars">The chars if is valid. Null otherwise.</param>
/// <returns><c>true</c>If is a valid surrogate pair, <c>false</c>otherwise.</returns>
public static bool DecodeSurrogatePair (this Rune rune, out char [] chars)
{
if (rune.IsSurrogatePair ()) {
chars = rune.ToString ().ToCharArray ();
return true;
}
chars = null;
return false;
}
/// <summary>
/// Gets a value indicating whether this <see cref="Rune"/> can be
/// encoded as UTF-16 from a surrogate pair or zero otherwise.
/// </summary>
/// <param name="highsurrogate">The high surrogate code point.</param>
/// <param name="lowSurrogate">The low surrogate code point.</param>
/// <param name="result">The returning rune.</param>
/// <returns><c>True</c>if the returning rune is greater than 0 <c>False</c>otherwise.</returns>
public static bool EncodeSurrogatePair (char highsurrogate, char lowSurrogate, out Rune result)
{
result = default;
if (char.IsSurrogatePair (highsurrogate, lowSurrogate)) {
result = (Rune)char.ConvertToUtf32 (highsurrogate, lowSurrogate);
return true;
}
return false;
}
/// <summary>
/// Reports whether a rune is a surrogate code point.
/// </summary>
/// <param name="rune">The rune to probe.</param>
/// <returns><c>true</c>If is a surrogate code point, <c>false</c>otherwise.</returns>
public static bool IsSurrogatePair (this Rune rune)
{
return char.IsSurrogatePair (rune.ToString (), 0);
}
/// <summary>
/// Gets a value indicating whether this <see cref="Rune"/> can be encoded as UTF-8.
/// </summary>
/// <param name="buffer">The byte array to probe.</param>
/// <value><c>true</c> if is valid; otherwise, <c>false</c>.</value>
public static bool IsValid (byte [] buffer)
{
var str = Encoding.Unicode.GetString (buffer);
foreach (var rune in str.EnumerateRunes ()) {
if (rune == Rune.ReplacementChar) {
return false;
}
}
return true;
}
/// <summary>
/// Gets a value indicating whether this <see cref="Rune"/> is valid.
/// </summary>
/// <param name="rune">The rune to probe.</param>
/// <returns></returns>
public static bool IsValid (this Rune rune)
{
return Rune.IsValid (rune.Value);
}
}
}

View File

@@ -91,7 +91,7 @@ namespace Terminal.Gui {
{ 0xff01, 0xff60 }, { 0xffe0, 0xffe6 },
{ 0x16fe0, 0x16fe4 }, { 0x16ff0, 0x16ff1 }, { 0x17000, 0x187f7 },
{ 0x18800, 0x18cd5 }, { 0x18d00, 0x18d08 }, { 0x1aff0, 0x1affc },
{ 0x1b000, 0x1b122 }, { 0x1b150, 0x1b152 }, { 0x1b164, 0x1b167 }, { 0x1b170, 0x1b2fb }, {0x1d539, 0x1d539},
{ 0x1b000, 0x1b122 }, { 0x1b150, 0x1b152 }, { 0x1b164, 0x1b167 }, { 0x1b170, 0x1b2fb }, {0x1d538, 0x1d550},
{ 0x1f004, 0x1f004 }, { 0x1f0cf, 0x1f0cf }, /*{ 0x1f100, 0x1f10a },*/
//{ 0x1f110, 0x1f12d }, { 0x1f130, 0x1f169 }, { 0x1f170, 0x1f1ac },
{ 0x1f18f, 0x1f199 },

View File

@@ -1,5 +1,4 @@
using System.Text;
using System;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;

View File

@@ -52,7 +52,7 @@ namespace Terminal.Gui.TextTests {
Assert.Equal (0, e.ColumnWidth ());
string join = "\u1104\u1161";
Assert.Equal ("따", join);
Assert.Equal (2, join.EnumerateRunes().Sum (x => x.ColumnWidth ()));
Assert.Equal (2, join.EnumerateRunes ().Sum (x => x.ColumnWidth ()));
Assert.Equal (OperationStatus.Done, Rune.DecodeFromUtf16 (join.ToCharArray (), out Rune result, out int charsConsumed));
Assert.False (join.DecodeSurrogatePair (out char [] spair));
Assert.Equal (2, join.RuneCount ());
@@ -62,7 +62,7 @@ namespace Terminal.Gui.TextTests {
Assert.Equal (3, e.Utf8SequenceLength);
string joinNormalize = join.Normalize ();
Assert.Equal ("따", joinNormalize);
Assert.Equal (2, joinNormalize.EnumerateRunes().Sum (x => x.ColumnWidth ()));
Assert.Equal (2, joinNormalize.EnumerateRunes ().Sum (x => x.ColumnWidth ()));
Assert.Equal (OperationStatus.Done, Rune.DecodeFromUtf16 (joinNormalize.ToCharArray (), out result, out charsConsumed));
Assert.False (joinNormalize.DecodeSurrogatePair (out spair));
Assert.Equal (1, joinNormalize.RuneCount ());
@@ -196,37 +196,37 @@ namespace Terminal.Gui.TextTests {
Assert.Equal ('\u1100', (uint)rune.Value);
string str = "\u2615";
Assert.Equal ("☕", str);
Assert.Equal (2, str.EnumerateRunes().Sum(x => x.ColumnWidth()));
Assert.Equal (2, str.EnumerateRunes ().Sum (x => x.ColumnWidth ()));
Assert.Equal (2, str.ConsoleWidth ());
Assert.Equal (1, str.RuneCount ());
Assert.Equal (1, str.Length);
str = "\u2615\ufe0f"; // Identical but \ufe0f forces it to be rendered as a colorful image as compared to a monochrome text variant.
Assert.Equal ("☕️", str);
Assert.Equal (2, str.EnumerateRunes().Sum(x => x.ColumnWidth()));
Assert.Equal (2, str.EnumerateRunes ().Sum (x => x.ColumnWidth ()));
Assert.Equal (2, str.ConsoleWidth ());
Assert.Equal (2, str.RuneCount ());
Assert.Equal (2, str.Length);
str = "\u231a";
Assert.Equal ("⌚", str);
Assert.Equal (2, str.EnumerateRunes().Sum(x => x.ColumnWidth()));
Assert.Equal (2, str.EnumerateRunes ().Sum (x => x.ColumnWidth ()));
Assert.Equal (2, str.ConsoleWidth ());
Assert.Equal (1, str.RuneCount ());
Assert.Equal (1, str.Length);
str = "\u231b";
Assert.Equal ("⌛", str);
Assert.Equal (2, str.EnumerateRunes().Sum(x => x.ColumnWidth()));
Assert.Equal (2, str.EnumerateRunes ().Sum (x => x.ColumnWidth ()));
Assert.Equal (2, str.ConsoleWidth ());
Assert.Equal (1, str.RuneCount ());
Assert.Equal (1, str.Length);
str = "\u231c";
Assert.Equal ("⌜", str);
Assert.Equal (1, str.EnumerateRunes().Sum(x => x.ColumnWidth()));
Assert.Equal (1, str.EnumerateRunes ().Sum (x => x.ColumnWidth ()));
Assert.Equal (1, str.ConsoleWidth ());
Assert.Equal (1, str.RuneCount ());
Assert.Equal (1, str.Length);
str = "\u1dc0";
Assert.Equal ("᷀", str);
Assert.Equal (0, str.EnumerateRunes().Sum(x => x.ColumnWidth()));
Assert.Equal (0, str.EnumerateRunes ().Sum (x => x.ColumnWidth ()));
Assert.Equal (0, str.ConsoleWidth ());
Assert.Equal (1, str.RuneCount ());
Assert.Equal (1, str.Length);
@@ -530,7 +530,7 @@ namespace Terminal.Gui.TextTests {
Assert.Equal ("ô", f);
Assert.Equal (f, s);
Assert.Equal (1, f.ConsoleWidth ());
Assert.Equal (1, s.EnumerateRunes().Sum (c => c.ColumnWidth ()));
Assert.Equal (1, s.EnumerateRunes ().Sum (c => c.ColumnWidth ()));
Assert.Equal (2, s.Length);
(var rune, var size) = f.DecodeRune ();
Assert.Equal (rune, l);
@@ -548,7 +548,7 @@ namespace Terminal.Gui.TextTests {
Assert.Equal ("A̅", f);
Assert.Equal (f, s);
Assert.Equal (1, f.ConsoleWidth ());
Assert.Equal (1, s.EnumerateRunes().Sum(c => c.ColumnWidth()));
Assert.Equal (1, s.EnumerateRunes ().Sum (c => c.ColumnWidth ()));
Assert.Equal (2, s.Length);
(rune, size) = f.DecodeRune ();
Assert.Equal (rune, l);
@@ -566,7 +566,7 @@ namespace Terminal.Gui.TextTests {
Assert.Equal ("ä", f);
Assert.Equal (f, s);
Assert.Equal (1, f.ConsoleWidth ());
Assert.Equal (1, s.EnumerateRunes().Sum(c => c.ColumnWidth()));
Assert.Equal (1, s.EnumerateRunes ().Sum (c => c.ColumnWidth ()));
Assert.Equal (2, s.Length);
(rune, size) = f.DecodeRune ();
Assert.Equal (rune, l);
@@ -584,7 +584,7 @@ namespace Terminal.Gui.TextTests {
Assert.Equal ("伀〪", f); // Occupies 4 columns.
Assert.Equal (f, s);
Assert.Equal (4, f.ConsoleWidth ());
Assert.Equal (4, s.EnumerateRunes().Sum(c => c.ColumnWidth()));
Assert.Equal (4, s.EnumerateRunes ().Sum (c => c.ColumnWidth ()));
Assert.Equal (2, s.Length);
(rune, size) = f.DecodeRune ();
Assert.Equal (rune, l);
@@ -627,10 +627,10 @@ namespace Terminal.Gui.TextTests {
Assert.Equal (us, s);
if (r.ColumnWidth () < 0) {
Assert.NotEqual (r.ColumnWidth (), us.ConsoleWidth ());
Assert.NotEqual (s.EnumerateRunes().Sum (c => c.ColumnWidth ()), us.ConsoleWidth ());
Assert.NotEqual (s.EnumerateRunes ().Sum (c => c.ColumnWidth ()), us.ConsoleWidth ());
} else {
Assert.Equal (r.ColumnWidth (), us.ConsoleWidth ());
Assert.Equal (s.EnumerateRunes().Sum (c => c.ColumnWidth ()), us.ConsoleWidth ());
Assert.Equal (s.EnumerateRunes ().Sum (c => c.ColumnWidth ()), us.ConsoleWidth ());
}
Assert.Equal (us.RuneCount (), s.Length);
} else {
@@ -767,13 +767,31 @@ namespace Terminal.Gui.TextTests {
List<Rune> runes = new List<Rune> ();
int tSize = 0;
for (int i = 0; i < us.RuneCount (); i++) {
(Rune rune, int size) = us.Substring (i, 1).DecodeRune ();
(Rune rune, int size) = us.DecodeRune (i);
runes.Add (rune);
tSize += size;
}
string result = StringExtensions.Make (runes);
Assert.Equal ("Hello, 世界", result);
Assert.Equal (13, tSize);
Assert.Equal (11, result.ConsoleWidth ());
}
[Fact]
public void Test_DecodeRune_With_Surrogate_Pairs ()
{
string us = "Hello, 𝔹𝕆𝔹";
List<Rune> runes = new List<Rune> ();
int tSize = 0;
for (int i = 0; i < us.RuneCount (); i++) {
(Rune rune, int size) = us.DecodeRune (i);
runes.Add (rune);
tSize += size;
}
string result = StringExtensions.Make (runes);
Assert.Equal ("Hello, 𝔹𝕆𝔹", result);
Assert.Equal (19, tSize);
Assert.Equal (13, result.ConsoleWidth ());
}
[Fact]
@@ -783,13 +801,31 @@ namespace Terminal.Gui.TextTests {
List<Rune> runes = new List<Rune> ();
int tSize = 0;
for (int i = us.RuneCount () - 1; i >= 0; i--) {
(Rune rune, int size) = us.Substring (i, 1).DecodeLastRune ();
(Rune rune, int size) = us.DecodeLastRune (i);
runes.Add (rune);
tSize += size;
}
string result = StringExtensions.Make (runes);
Assert.Equal ("界世 ,olleH", result);
Assert.Equal (13, tSize);
Assert.Equal (11, result.ConsoleWidth ());
}
[Fact]
public void Test_DecodeLastRune_With_Surrogate_Pairs ()
{
string us = "Hello, 𝔹𝕆𝔹";
List<Rune> runes = new List<Rune> ();
int tSize = 0;
for (int i = us.RuneCount () - 1; i >= 0; i--) {
(Rune rune, int size) = us.DecodeLastRune (i);
runes.Add (rune);
tSize += size;
}
string result = StringExtensions.Make (runes);
Assert.Equal ("𝔹𝕆𝔹 ,olleH", result);
Assert.Equal (19, tSize);
Assert.Equal (13, result.ConsoleWidth ());
}
[Fact]
@@ -863,14 +899,14 @@ namespace Terminal.Gui.TextTests {
Assert.Equal (200, us.Length);
Assert.Equal (200, us.RuneCount ());
Assert.Equal (200, us.ConsoleWidth ());
int sumRuneWidth = us.EnumerateRunes().Sum (x => x.ColumnWidth ());
int sumRuneWidth = us.EnumerateRunes ().Sum (x => x.ColumnWidth ());
Assert.Equal (200, sumRuneWidth);
us = "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n";
Assert.Equal (201, us.Length);
Assert.Equal (201, us.RuneCount ());
Assert.Equal (200, us.ConsoleWidth ());
sumRuneWidth = us.EnumerateRunes().Sum(x => x.ColumnWidth());
sumRuneWidth = us.EnumerateRunes ().Sum (x => x.ColumnWidth ());
Assert.Equal (199, sumRuneWidth);
}