From 2048965ba62a9d2bcae399b1453225dfb8c4bef7 Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 10 May 2023 17:30:04 +0100 Subject: [PATCH] Adjust code and fix all unit tests errors. --- Terminal.Gui/Application.cs | 6 +- .../CursesDriver/CursesDriver.cs | 4 +- .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 8 +- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 4 +- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 4 +- Terminal.Gui/Rune/RuneExtensions.cs | 134 ++--- Terminal.Gui/Rune/RuneUtilities.cs | 2 +- Terminal.Gui/StringExtensions.cs | 64 ++- .../Text/Autocomplete/AppendAutocomplete.cs | 39 +- Terminal.Gui/Text/TextFormatter.cs | 24 +- Terminal.Gui/View/Frame.cs | 2 +- .../Views/AutocompleteFilepathContext.cs | 15 +- Terminal.Gui/Views/FileDialog.cs | 6 +- Terminal.Gui/Views/Menu.cs | 10 +- Terminal.Gui/Views/TabView.cs | 6 +- .../TableView/CheckBoxTableSourceWrapper.cs | 1 + .../Views/TableView/ListTableSource.cs | 9 +- Terminal.Gui/Views/TableView/TableView.cs | 10 +- Terminal.Gui/Views/TextField.cs | 32 +- Terminal.Gui/Views/TextView.cs | 49 +- Terminal.Gui/Views/TreeView/Branch.cs | 2 +- UICatalog/Scenarios/CharacterMap.cs | 13 +- UICatalog/Scenarios/Scrolling.cs | 2 +- UICatalog/Scenarios/TreeViewFileSystem.cs | 18 +- UnitTests/Text/RuneTests.cs | 519 ++++++++++-------- UnitTests/Text/TextFormatterTests.cs | 96 +--- UnitTests/Views/TableViewTests.cs | 4 +- UnitTests/Views/TextFieldTests.cs | 214 ++++---- UnitTests/Views/TextViewTests.cs | 5 +- 29 files changed, 651 insertions(+), 651 deletions(-) diff --git a/Terminal.Gui/Application.cs b/Terminal.Gui/Application.cs index bc4252054..d697946ee 100644 --- a/Terminal.Gui/Application.cs +++ b/Terminal.Gui/Application.cs @@ -442,10 +442,10 @@ namespace Terminal.Gui { } else if (Top != null && Toplevel != Top && _toplevels.Contains (Top)) { Top.OnLeave (Toplevel); } - if (string.IsNullOrEmpty (Toplevel.Id.ToString ())) { + if (string.IsNullOrEmpty (Toplevel.Id)) { var count = 1; var id = (_toplevels.Count + count).ToString (); - while (_toplevels.Count > 0 && _toplevels.FirstOrDefault (x => x.Id.ToString () == id) != null) { + while (_toplevels.Count > 0 && _toplevels.FirstOrDefault (x => x.Id == id) != null) { count++; id = (_toplevels.Count + count).ToString (); } @@ -453,7 +453,7 @@ namespace Terminal.Gui { _toplevels.Push (Toplevel); } else { - var dup = _toplevels.FirstOrDefault (x => x.Id.ToString () == Toplevel.Id); + var dup = _toplevels.FirstOrDefault (x => x.Id == Toplevel.Id); if (dup == null) { _toplevels.Push (Toplevel); } diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index af2b844e5..0fdee1f55 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -130,8 +130,8 @@ namespace Terminal.Gui { public override void AddStr (string str) { // TODO; optimize this to determine if the str fits in the clip region, and if so, use Curses.addstr directly - foreach (var rune in str) - AddRune ((Rune)rune); + foreach (var rune in str.EnumerateRunes ()) + AddRune (rune); } public override void Refresh () diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 8807a193f..5459a8988 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -119,7 +119,7 @@ namespace Terminal.Gui { public override void AddRune (Rune rune) { rune = MakePrintable (rune); - var runeWidth = rune.ColumnWidth(); + var runeWidth = rune.ColumnWidth (); var validClip = IsValidContent (ccol, crow, Clip); if (validClip) { @@ -149,7 +149,7 @@ namespace Terminal.Gui { contents [crow, ccol - 1, 0] = (int)(uint)' '; } else if (runeWidth < 2 && ccol <= Clip.Right - 1 - && ((Rune)contents [crow, ccol, 0]).ColumnWidth() > 1) { + && ((Rune)contents [crow, ccol, 0]).ColumnWidth () > 1) { contents [crow, ccol + 1, 0] = (int)(uint)' '; contents [crow, ccol + 1, 2] = 1; @@ -193,8 +193,8 @@ namespace Terminal.Gui { public override void AddStr (string str) { - foreach (var rune in str) - AddRune ((Rune)rune); + foreach (var rune in str.EnumerateRunes ()) + AddRune (rune); } public override void End () diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 221df2b63..1a9931827 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -731,8 +731,8 @@ namespace Terminal.Gui { public override void AddStr (string str) { - foreach (var rune in str) - AddRune ((Rune)rune); + foreach (var rune in str.EnumerateRunes ()) + AddRune (rune); } public override void End () diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index d08d7dfda..008f75be3 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -1596,8 +1596,8 @@ namespace Terminal.Gui { public override void AddStr (string str) { - foreach (var rune in str) - AddRune ((Rune)rune); + foreach (var rune in str.EnumerateRunes ()) + AddRune (rune); } public override void SetAttribute (Attribute c) diff --git a/Terminal.Gui/Rune/RuneExtensions.cs b/Terminal.Gui/Rune/RuneExtensions.cs index 6a0986343..1bd5a02f7 100644 --- a/Terminal.Gui/Rune/RuneExtensions.cs +++ b/Terminal.Gui/Rune/RuneExtensions.cs @@ -10,7 +10,7 @@ namespace Terminal.Gui { public static int ColumnWidth (this Rune rune) { - return RuneUtilities.ColumnWidth(rune); + return RuneUtilities.ColumnWidth (rune); } public static bool IsNonSpacingChar (this Rune rune) @@ -23,33 +23,67 @@ namespace Terminal.Gui { return RuneUtilities.IsWideChar (rune.Value); } - public static int RuneLen (this Rune rune) + public static int RuneUnicodeLength (this Rune rune, Encoding encoding = null) { - return 0; + 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 offset = 0) + public static int EncodeRune (this Rune rune, byte [] dest, int start = 0, int nbytes = -1) { - return 0; + 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 true; + return false; } public static bool EncodeSurrogatePair (char highsurrogate, char lowSurrogate, out Rune result) { - try { + result = default; + if (char.IsSurrogatePair (highsurrogate, lowSurrogate)) { result = (Rune)char.ConvertToUtf32 (highsurrogate, lowSurrogate); - } catch (Exception) { - result = default; - return false; + return true; } - - return true; + return false; } public static bool IsSurrogatePair (this Rune rune) @@ -57,82 +91,20 @@ namespace Terminal.Gui { return char.IsSurrogatePair (rune.ToString (), 0); } - public static bool IsSurrogate (this Rune rune) - { - return char.IsSurrogate (rune.ToString (), 0); - } - public static bool IsValid (byte [] buffer) { var str = Encoding.Unicode.GetString (buffer); - - return Rune.IsValid(str.EnumerateRunes ().Current.Value); + 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); } - - internal static bool IsHighSurrogate (this Rune rune) - { - return char.IsHighSurrogate (rune.ToString (), 0); - } - - internal static bool IsLowSurrogate (this Rune rune) - { - return char.IsLowSurrogate (rune.ToString (), 0); - } - - //public static bool operator==(this Rune a, Rune b) { return a.Equals(b); } - - //public static bool operator!=(this Rune a, Rune b) { return a.Equals(b); } - - //public static bool Equals(this Rune rune, ) { } } - - ///// - ///// Implements the for comparing two s - ///// used by . - ///// - //public class RuneEqualityComparer : IEqualityComparer { - // /// Determines whether the specified objects are equal. - // /// The first object of type to compare. - // /// The second object of type to compare. - // /// - // /// if the specified objects are equal; otherwise, . - // public bool Equals (Rune x, Rune y) - // { - // return x.Equals (y); - // } - - // /// Returns a hash code for the specified object. - // /// The for which a hash code is to be returned. - // /// A hash code for the specified object. - // /// The type of - // /// is a reference type and is . - // public int GetHashCode (Rune obj) - // { - // return obj.GetHashCode (); - // } - //} - - ///// - ///// Implements the to sort the - ///// from the if needed. - ///// - //public sealed class RuneComparer : IComparer { - // /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other. - // /// The first object to compare. - // /// The second object to compare. - // /// A signed integer that indicates the relative values of and , as shown in the following table.Value Meaning Less than zero - // /// is less than .Zero - // /// equals .Greater than zero - // /// is greater than . - // public int Compare (Rune x, Rune y) - // { - // return x.CompareTo (y); - // } - //} - } diff --git a/Terminal.Gui/Rune/RuneUtilities.cs b/Terminal.Gui/Rune/RuneUtilities.cs index f15696e89..d9712e041 100644 --- a/Terminal.Gui/Rune/RuneUtilities.cs +++ b/Terminal.Gui/Rune/RuneUtilities.cs @@ -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 }, + { 0x1b000, 0x1b122 }, { 0x1b150, 0x1b152 }, { 0x1b164, 0x1b167 }, { 0x1b170, 0x1b2fb }, {0x1d539, 0x1d539}, { 0x1f004, 0x1f004 }, { 0x1f0cf, 0x1f0cf }, /*{ 0x1f100, 0x1f10a },*/ //{ 0x1f110, 0x1f12d }, { 0x1f130, 0x1f169 }, { 0x1f170, 0x1f1ac }, { 0x1f18f, 0x1f199 }, diff --git a/Terminal.Gui/StringExtensions.cs b/Terminal.Gui/StringExtensions.cs index 13baef883..2ad93d33d 100644 --- a/Terminal.Gui/StringExtensions.cs +++ b/Terminal.Gui/StringExtensions.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; using System.Text; namespace Terminal.Gui { @@ -32,65 +34,71 @@ namespace Terminal.Gui { public static int ConsoleWidth (this string instr) { - return 0; - } - - public static int IndexOf (this string instr, Rune rune) - { - return 0; + return instr.EnumerateRunes ().Sum (r => Math.Max (r.ColumnWidth (), 0)); } public static int RuneCount (this string instr) { - return 0; + return instr.EnumerateRunes ().Count (); } - public static Rune[] ToRunes (this string instr) + public static Rune [] ToRunes (this string instr) { - return null; + return instr.EnumerateRunes ().ToArray (); } public static List ToRuneList (this string instr) { - return new List(); + return instr.EnumerateRunes ().ToList (); } - public static (Rune rune, int size) DecodeRune (this string instr, int start = 0, int nbytes = -1) + public static (Rune Rune, int Size) DecodeRune (this string instr, int start = 0, int nbytes = -1) { - return new (new Rune (), 0); + return RuneExtensions.DecodeRune (Encoding.UTF8.GetBytes (instr), start, nbytes); } public static (Rune rune, int size) DecodeLastRune (this string instr, int end = -1) { - return new (new Rune (), 0); + var bytes = Encoding.UTF8.GetBytes (instr); + return RuneExtensions.DecodeLastRune (bytes, end); } public static bool DecodeSurrogatePair (this string instr, out char [] chars) { chars = null; if (instr.Length == 2) { - chars = instr.ToCharArray (); - if (RuneExtensions.EncodeSurrogatePair (chars [0], chars [1], out _)) { - chars = new char[] { chars [0], chars [1] }; + var charsArray = instr.ToCharArray (); + if (RuneExtensions.EncodeSurrogatePair (charsArray [0], charsArray [1], out _)) { + chars = charsArray; return true; } } return false; } - public static byte[] ToByteArray (this string instr) + public static byte [] ToByteArray (this string instr) { return Encoding.Unicode.GetBytes (instr.ToCharArray ()); } public static string Make (Rune [] runes) { - return runes.ToString (); + var str = string.Empty; + + foreach (var rune in runes) { + str += rune.ToString (); + } + + return str; } public static string Make (List runes) { - return runes.ToString (); + var str = string.Empty; + foreach (var rune in runes) { + str += rune.ToString (); + } + return str; } public static string Make (Rune rune) @@ -98,16 +106,24 @@ namespace Terminal.Gui { return rune.ToString (); } - public static string Make (uint rune) { - return rune.ToString (); + return ((Rune)rune).ToString (); } - public static string Make (byte [] bytes) + public static string Make (byte [] bytes, Encoding encoding = null) { - return bytes.ToString (); + if (encoding == null) { + encoding = Encoding.UTF8; + } + return encoding.GetString (bytes); } + public static string Make (params char [] chars) + { + var c = new char [chars.Length]; + + return new string (chars); + } } } diff --git a/Terminal.Gui/Text/Autocomplete/AppendAutocomplete.cs b/Terminal.Gui/Text/Autocomplete/AppendAutocomplete.cs index 2d2d9d6fb..e6de8b3f3 100644 --- a/Terminal.Gui/Text/Autocomplete/AppendAutocomplete.cs +++ b/Terminal.Gui/Text/Autocomplete/AppendAutocomplete.cs @@ -31,12 +31,12 @@ namespace Terminal.Gui { this.textField = textField; SelectionKey = Key.Tab; - ColorScheme = new ColorScheme{ - Normal = new Attribute(Color.DarkGray,0), - Focus = new Attribute(Color.DarkGray,0), - HotNormal = new Attribute(Color.DarkGray,0), - HotFocus = new Attribute(Color.DarkGray,0), - Disabled = new Attribute(Color.DarkGray,0), + ColorScheme = new ColorScheme { + Normal = new Attribute (Color.DarkGray, 0), + Focus = new Attribute (Color.DarkGray, 0), + HotNormal = new Attribute (Color.DarkGray, 0), + HotFocus = new Attribute (Color.DarkGray, 0), + Disabled = new Attribute (Color.DarkGray, 0), }; } @@ -65,16 +65,13 @@ namespace Terminal.Gui { } else if (key == Key.CursorDown) { return this.CycleSuggestion (-1); - } - else if(key == CloseKey && Suggestions.Any()) - { - ClearSuggestions(); + } else if (key == CloseKey && Suggestions.Any ()) { + ClearSuggestions (); _suspendSuggestions = true; return true; } - if(char.IsLetterOrDigit((char)kb.KeyValue)) - { + if (char.IsLetterOrDigit ((char)kb.KeyValue)) { _suspendSuggestions = false; } @@ -85,8 +82,7 @@ namespace Terminal.Gui { /// public override void GenerateSuggestions (AutocompleteContext context) { - if(_suspendSuggestions) - { + if (_suspendSuggestions) { return; } base.GenerateSuggestions (context); @@ -108,14 +104,13 @@ namespace Terminal.Gui { var suggestion = this.Suggestions.ElementAt (this.SelectedIdx); var fragment = suggestion.Replacement.Substring (suggestion.Remove); - int spaceAvailable = textField.Bounds.Width - textField.Text.ConsoleWidth(); - int spaceRequired = fragment.Sum(c=>((Rune)c).ColumnWidth()); + int spaceAvailable = textField.Bounds.Width - textField.Text.ConsoleWidth (); + int spaceRequired = fragment.EnumerateRunes ().Sum (c => c.ColumnWidth ()); - if(spaceAvailable < spaceRequired) - { - fragment = new string( - fragment.TakeWhile(c=> (spaceAvailable -= ((Rune)c).ColumnWidth()) >= 0) - .ToArray() + if (spaceAvailable < spaceRequired) { + fragment = new string ( + fragment.TakeWhile (c => (spaceAvailable -= ((Rune)c).ColumnWidth ()) >= 0) + .ToArray () ); } @@ -138,7 +133,7 @@ namespace Terminal.Gui { newText += insert.Replacement; textField.Text = newText; - this.textField.MoveEnd(); + this.textField.MoveEnd (); this.ClearSuggestions (); return true; diff --git a/Terminal.Gui/Text/TextFormatter.cs b/Terminal.Gui/Text/TextFormatter.cs index 860d87d40..f7388f1df 100644 --- a/Terminal.Gui/Text/TextFormatter.cs +++ b/Terminal.Gui/Text/TextFormatter.cs @@ -226,10 +226,10 @@ namespace Terminal.Gui { return text; // if value is not wide enough - if (text.Sum (c => ((Rune)c).ColumnWidth ()) < width) { + if (text.EnumerateRunes ().Sum (c => c.ColumnWidth ()) < width) { // pad it out with spaces to the given alignment - int toPad = width - (text.Sum (c => ((Rune)c).ColumnWidth ())); + int toPad = width - (text.EnumerateRunes ().Sum (c => c.ColumnWidth ())); return text + new string (' ', toPad); } @@ -670,7 +670,7 @@ namespace Terminal.Gui { /// The text width. public static int GetTextWidth (string text) { - return text.ToRuneList ().Sum (r => Math.Max (r.ColumnWidth (), 1)); + return text.EnumerateRunes ().Sum (r => Math.Max (r.ColumnWidth (), 1)); } /// @@ -687,7 +687,7 @@ namespace Terminal.Gui { for (int i = (startIndex == -1 ? 0 : startIndex); i < (length == -1 ? lines.Count : startIndex + length); i++) { var runes = lines [i]; if (runes.Length > 0) - max += runes.Max (r => Math.Max (((Rune)r).ColumnWidth (), 1)); + max += runes.EnumerateRunes ().Max (r => Math.Max (r.ColumnWidth (), 1)); } return max; } @@ -785,14 +785,14 @@ namespace Terminal.Gui { int ml = 1; int cols = 0; - foreach (var rune in text) { - if (rune == '\n') { + foreach (var rune in text.EnumerateRunes ()) { + if (rune.Value == '\n') { ml++; if (cols > mw) { mw = cols; } cols = 0; - } else if (rune != '\r') { + } else if (rune.Value != '\r') { cols++; var rw = ((Rune)rune).ColumnWidth (); if (rw > 0) { @@ -811,15 +811,15 @@ namespace Terminal.Gui { int vh = 0; int rows = 0; - foreach (var rune in text) { - if (rune == '\n') { + foreach (var rune in text.EnumerateRunes ()) { + if (rune.Value == '\n') { vw++; if (rows > vh) { vh = rows; } rows = 0; cw = 1; - } else if (rune != '\r') { + } else if (rune.Value != '\r') { rows++; var rw = ((Rune)rune).ColumnWidth (); if (cw < rw) { @@ -863,7 +863,7 @@ namespace Terminal.Gui { // TODO: Ignore hot_key of two are provided // TODO: Do not support non-alphanumeric chars that can't be typed int i = 0; - foreach (Rune c in text) { + foreach (Rune c in text.EnumerateRunes ()) { if ((char)c.Value != 0xFFFD) { if (c == hotKeySpecifier) { hot_pos = i; @@ -878,7 +878,7 @@ namespace Terminal.Gui { // Legacy support - use first upper case char if the specifier was not found if (hot_pos == -1 && firstUpperCase) { i = 0; - foreach (Rune c in text) { + foreach (Rune c in text.EnumerateRunes ()) { if ((char)c.Value != 0xFFFD) { if (Rune.IsUpper (c)) { hot_key = c; diff --git a/Terminal.Gui/View/Frame.cs b/Terminal.Gui/View/Frame.cs index 4d73785d2..7a82b1976 100644 --- a/Terminal.Gui/View/Frame.cs +++ b/Terminal.Gui/View/Frame.cs @@ -367,7 +367,7 @@ namespace Terminal.Gui { if (!string.IsNullOrEmpty (title)) { Driver.Move (region.X + 2, region.Y); //Driver.AddRune (' '); - var str = title.Sum (r => Math.Max (((Rune)r).ColumnWidth (), 1)) >= width + var str = title.EnumerateRunes().Sum (r => Math.Max (r.ColumnWidth (), 1)) >= width ? TextFormatter.Format (title, width, false, false) [0] : title; Driver.AddStr (str); } diff --git a/Terminal.Gui/Views/AutocompleteFilepathContext.cs b/Terminal.Gui/Views/AutocompleteFilepathContext.cs index 7c6ed925e..378605f4a 100644 --- a/Terminal.Gui/Views/AutocompleteFilepathContext.cs +++ b/Terminal.Gui/Views/AutocompleteFilepathContext.cs @@ -11,7 +11,7 @@ namespace Terminal.Gui { public FileDialogState State { get; set; } public AutocompleteFilepathContext (string currentLine, int cursorPosition, FileDialogState state) - : base (currentLine.EnumerateRunes().ToList (), cursorPosition) + : base (currentLine.EnumerateRunes ().ToList (), cursorPosition) { this.State = state; } @@ -30,18 +30,17 @@ namespace Terminal.Gui { return Enumerable.Empty (); } - var path = context.CurrentLine.ToString (); + var path = StringExtensions.Make (context.CurrentLine); var last = path.LastIndexOfAny (FileDialog.Separators); - - if(string.IsNullOrWhiteSpace(path) || !Path.IsPathRooted(path)) { + + if (string.IsNullOrWhiteSpace (path) || !Path.IsPathRooted (path)) { return Enumerable.Empty (); } var term = path.Substring (last + 1); - + // If path is /tmp/ then don't just list everything in it - if(string.IsNullOrWhiteSpace(term)) - { + if (string.IsNullOrWhiteSpace (term)) { return Enumerable.Empty (); } @@ -52,7 +51,7 @@ namespace Terminal.Gui { bool isWindows = RuntimeInformation.IsOSPlatform (OSPlatform.Windows); - var suggestions = state.Children.Where(d=> !d.IsParent).Select ( + var suggestions = state.Children.Where (d => !d.IsParent).Select ( e => e.FileSystemInfo is IDirectoryInfo d ? d.Name + System.IO.Path.DirectorySeparatorChar : e.FileSystemInfo.Name) diff --git a/Terminal.Gui/Views/FileDialog.cs b/Terminal.Gui/Views/FileDialog.cs index 434601293..518294f00 100644 --- a/Terminal.Gui/Views/FileDialog.cs +++ b/Terminal.Gui/Views/FileDialog.cs @@ -547,7 +547,7 @@ namespace Terminal.Gui { /// is true. /// public string Path { - get => this.tbPath.Text.ToString (); + get => this.tbPath.Text; set { this.tbPath.Text = value; this.tbPath.MoveEnd (); @@ -598,7 +598,7 @@ namespace Terminal.Gui { base.OnDrawContent (contentArea); if (!string.IsNullOrWhiteSpace (feedback)) { - var feedbackWidth = feedback.Sum (c => ((Rune)c).ColumnWidth ()); + var feedbackWidth = feedback.EnumerateRunes ().Sum (c => c.ColumnWidth ()); var feedbackPadLeft = ((Bounds.Width - feedbackWidth) / 2) - 1; feedbackPadLeft = Math.Min (Bounds.Width, feedbackPadLeft); @@ -800,7 +800,7 @@ namespace Terminal.Gui { return; } - if (!this.IsCompatibleWithOpenMode (this.tbPath.Text.ToString (), out string reason)) { + if (!this.IsCompatibleWithOpenMode (this.tbPath.Text, out string reason)) { if (reason != null) { feedback = reason; SetNeedsDisplay (); diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 4283bfa96..12b0ab42e 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -272,10 +272,10 @@ namespace Terminal.Gui { int GetMenuBarItemLength (string title) { int len = 0; - foreach (var ch in title) { - if (ch == MenuBar.HotKeySpecifier.Value) + foreach (var ch in title.EnumerateRunes ()) { + if (ch == MenuBar.HotKeySpecifier) continue; - len += Math.Max (((Rune)ch).ColumnWidth (), 1); + len += Math.Max (ch.ColumnWidth (), 1); } return len; @@ -1807,7 +1807,7 @@ namespace Terminal.Gui { for (int i = 0; i < Menus.Length; i++) { // TODO: this code is duplicated, hotkey should be part of the MenuBarItem var mi = Menus [i]; - int p = mi.Title.IndexOf (MenuBar.HotKeySpecifier); + int p = mi.Title.IndexOf (MenuBar.HotKeySpecifier.ToString ()); if (p != -1 && p + 1 < mi.Title.RuneCount ()) { if (Char.ToUpperInvariant ((char)mi.Title [p + 1]) == c) { ProcessMenu (i, mi); @@ -1916,7 +1916,7 @@ namespace Terminal.Gui { foreach (var mi in Menus [selected].Children) { if (mi == null) continue; - int p = mi.Title.IndexOf (MenuBar.HotKeySpecifier); + int p = mi.Title.IndexOf (MenuBar.HotKeySpecifier.ToString ()); if (p != -1 && p + 1 < mi.Title.RuneCount ()) { if (mi.Title [p + 1] == c) { Selected (mi); diff --git a/Terminal.Gui/Views/TabView.cs b/Terminal.Gui/Views/TabView.cs index 47fbadd7e..1041f9014 100644 --- a/Terminal.Gui/Views/TabView.cs +++ b/Terminal.Gui/Views/TabView.cs @@ -336,9 +336,9 @@ namespace Terminal.Gui { foreach (var tab in Tabs.Skip (TabScrollOffset)) { // while there is space for the tab - var tabTextWidth = tab.Text.Sum (c => ((Rune)c).ColumnWidth ()); + var tabTextWidth = tab.Text.EnumerateRunes ().Sum (c => c.ColumnWidth ()); - string text = tab.Text.ToString (); + string text = tab.Text; // The maximum number of characters to use for the tab name as specified // by the user (MaxTabTextWidth). But not more than the width of the view @@ -352,7 +352,7 @@ namespace Terminal.Gui { } if (tabTextWidth > maxWidth) { - text = tab.Text.ToString ().Substring (0, (int)maxWidth); + text = tab.Text.Substring (0, (int)maxWidth); tabTextWidth = (int)maxWidth; } diff --git a/Terminal.Gui/Views/TableView/CheckBoxTableSourceWrapper.cs b/Terminal.Gui/Views/TableView/CheckBoxTableSourceWrapper.cs index 14072b7e1..405727955 100644 --- a/Terminal.Gui/Views/TableView/CheckBoxTableSourceWrapper.cs +++ b/Terminal.Gui/Views/TableView/CheckBoxTableSourceWrapper.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Linq; +using System.Text; namespace Terminal.Gui { diff --git a/Terminal.Gui/Views/TableView/ListTableSource.cs b/Terminal.Gui/Views/TableView/ListTableSource.cs index 265a396af..642b9d910 100644 --- a/Terminal.Gui/Views/TableView/ListTableSource.cs +++ b/Terminal.Gui/Views/TableView/ListTableSource.cs @@ -1,5 +1,4 @@ -using NStack; -using System; +using System; using System.Collections; using System.Data; using System.Linq; @@ -136,10 +135,8 @@ namespace Terminal.Gui { int maxLength = 0; foreach (var t in List) { int l; - if (t is ustring u) { - l = TextFormatter.GetTextWidth (u); - } else if (t is string s) { - l = s.Length; + if (t is string s) { + l = TextFormatter.GetTextWidth (s); } else { l = t.ToString ().Length; } diff --git a/Terminal.Gui/Views/TableView/TableView.cs b/Terminal.Gui/Views/TableView/TableView.cs index 35dca3677..19a8d499e 100644 --- a/Terminal.Gui/Views/TableView/TableView.cs +++ b/Terminal.Gui/Views/TableView/TableView.cs @@ -719,10 +719,10 @@ namespace Terminal.Gui { return new string (' ', availableHorizontalSpace); // if value is not wide enough - if (representation.Sum (c => ((Rune)c).ColumnWidth ()) < availableHorizontalSpace) { + if (representation.EnumerateRunes ().Sum (c => c.ColumnWidth ()) < availableHorizontalSpace) { // pad it out with spaces to the given alignment - int toPad = availableHorizontalSpace - (representation.Sum (c => ((Rune)c).ColumnWidth ()) + 1 /*leave 1 space for cell boundary*/); + int toPad = availableHorizontalSpace - (representation.EnumerateRunes ().Sum (c => c.ColumnWidth ()) + 1 /*leave 1 space for cell boundary*/); switch (colStyle?.GetAlignment (originalCellValue) ?? TextAlignment.Left) { @@ -1594,7 +1594,7 @@ namespace Terminal.Gui { /// Invokes the event /// /// - protected virtual void OnCellToggled(CellToggledEventArgs args) + protected virtual void OnCellToggled (CellToggledEventArgs args) { CellToggled?.Invoke (this, args); } @@ -1716,7 +1716,7 @@ namespace Terminal.Gui { /// private int CalculateMaxCellWidth (int col, int rowsToRender, ColumnStyle colStyle) { - int spaceRequired = table.ColumnNames [col].Sum (c => ((Rune)c).ColumnWidth()); + int spaceRequired = table.ColumnNames [col].EnumerateRunes ().Sum (c => c.ColumnWidth ()); // if table has no rows if (RowOffset < 0) @@ -1728,7 +1728,7 @@ namespace Terminal.Gui { //expand required space if cell is bigger than the last biggest cell or header spaceRequired = Math.Max ( spaceRequired, - GetRepresentation (Table [i, col], colStyle).Sum (c => ((Rune)c).ColumnWidth())); + GetRepresentation (Table [i, col], colStyle).EnumerateRunes ().Sum (c => c.ColumnWidth ())); } // Don't require more space than the style allows diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs index 58a752cd4..967e96abb 100644 --- a/Terminal.Gui/Views/TextField.cs +++ b/Terminal.Gui/Views/TextField.cs @@ -79,7 +79,7 @@ namespace Terminal.Gui { /// Initial text contents. public TextField (string text) : base (text) { - Initialize (text, text.RuneCount() + 1); + Initialize (text, text.RuneCount () + 1); } /// @@ -102,7 +102,7 @@ namespace Terminal.Gui { text = ""; this.text = TextModel.ToRunes (text.Split ("\n") [0]); - point = text.RuneCount(); + point = text.RuneCount (); first = point > w + 1 ? point - w + 1 : 0; CanFocus = true; Used = true; @@ -288,7 +288,7 @@ namespace Terminal.Gui { get => base.Frame; set { if (value.Height > 1) { - base.Frame = new Rect(value.X, value.Y, value.Width, 1); + base.Frame = new Rect (value.X, value.Y, value.Width, 1); Height = 1; } else { base.Frame = value; @@ -450,7 +450,7 @@ namespace Terminal.Gui { var roc = GetReadOnlyColor (); for (int idx = p; idx < tcount; idx++) { var rune = text [idx]; - var cols = ((Rune)rune).ColumnWidth(); + var cols = ((Rune)rune).ColumnWidth (); if (idx == point && HasFocus && !Used && length == 0 && !ReadOnly) { Driver.SetAttribute (selColor); } else if (ReadOnly) { @@ -468,7 +468,7 @@ namespace Terminal.Gui { if (!TextModel.SetCol (ref col, width, cols)) { break; } - if (idx + 1 < tcount && col + text[idx + 1].ColumnWidth() > width) { + if (idx + 1 < tcount && col + text [idx + 1].ColumnWidth () > width) { break; } } @@ -508,8 +508,8 @@ namespace Terminal.Gui { Move (0, 0); var render = Caption; - if (render.ConsoleWidth() > Bounds.Width) { - render = render[..Bounds.Width]; + if (render.ConsoleWidth () > Bounds.Width) { + render = render [..Bounds.Width]; } Driver.AddStr (render); @@ -1054,7 +1054,7 @@ namespace Terminal.Gui { int x = PositionCursor (ev); int sbw = x; if (x == text.Count || (x > 0 && (char)text [x - 1].Value != ' ') - || (x > 0 && (char)text[x].Value == ' ')) { + || (x > 0 && (char)text [x].Value == ' ')) { var newPosBw = GetModel ().WordBackward (x, 0); if (newPosBw == null) return true; @@ -1200,11 +1200,11 @@ namespace Terminal.Gui { int selStart = SelectedStart > -1 ? start : point; (var _, var len) = TextModel.DisplaySize (text, 0, selStart, false); (var _, var len2) = TextModel.DisplaySize (text, selStart, selStart + length, false); - (var _, var len3) = TextModel.DisplaySize (text, selStart + length, actualText.RuneCount(), false); - var newText = actualText[..len] + - actualText.Substring(len + len2, len + len2 + len3); + (var _, var len3) = TextModel.DisplaySize (text, selStart + length, actualText.RuneCount (), false); + var newText = actualText [..len] + + actualText.Substring (len + len2, len3); ClearAllSelection (); - point = selStart >= newText.RuneCount() ? newText.RuneCount() : selStart; + point = selStart >= newText.RuneCount () ? newText.RuneCount () : selStart; return newText.ToRuneList (); } @@ -1222,12 +1222,12 @@ namespace Terminal.Gui { string actualText = Text; (int _, int len) = TextModel.DisplaySize (text, 0, selStart, false); (var _, var len2) = TextModel.DisplaySize (text, selStart, selStart + length, false); - (var _, var len3) = TextModel.DisplaySize (text, selStart + length, actualText.RuneCount(), false); + (var _, var len3) = TextModel.DisplaySize (text, selStart + length, actualText.RuneCount (), false); string cbTxt = Clipboard.Contents.Split ("\n") [0] ?? ""; - Text = actualText[..len] + + Text = actualText [..len] + cbTxt + - actualText.Substring (len + len2, len + len2 + len3); - point = selStart + cbTxt.RuneCount(); + actualText.Substring (len + len2, len3); + point = selStart + cbTxt.RuneCount (); ClearAllSelection (); SetNeedsDisplay (); Adjust (); diff --git a/Terminal.Gui/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs index 091a5e06f..480529530 100644 --- a/Terminal.Gui/Views/TextView.cs +++ b/Terminal.Gui/Views/TextView.cs @@ -51,16 +51,17 @@ namespace Terminal.Gui { var lines = new List> (); int start = 0, i = 0; var hasCR = false; + var runes = content.EnumerateRunes ().ToList (); // ASCII code 13 = Carriage Return. // ASCII code 10 = Line Feed. - for (; i < content.Length; i++) { - if (content [i] == 13) { + for (; i < runes.Count; i++) { + if (runes [i].Value == 13) { hasCR = true; continue; } - if (content [i] == 10) { + if (runes [i].Value == 10) { if (i - start > 0) - lines.Add (ToRunes (content.Substring(start, hasCR ? i - 1 : i))); + lines.Add (runes.GetRange (start, hasCR ? i - 1 - start : i - start)); else lines.Add (ToRunes (string.Empty)); start = i + 1; @@ -68,7 +69,7 @@ namespace Terminal.Gui { } } if (i - start >= 0) - lines.Add (ToRunes (content.Substring (start, 0))); + lines.Add (runes.GetRange (start, i - start)); return lines; } @@ -256,8 +257,8 @@ namespace Terminal.Gui { int i = start == -1 ? 0 : start; for (; i < tcount; i++) { var rune = t [i]; - size += rune.ColumnWidth(); - len += rune.RuneLen (); + size += rune.ColumnWidth (); + len += rune.RuneUnicodeLength (Encoding.Unicode); if (rune.Value == '\t') { size += tabWidth + 1; len += tabWidth - 1; @@ -272,7 +273,7 @@ namespace Terminal.Gui { bool IsWideRune (Rune r, int tWidth, out int s, out int l) { s = r.ColumnWidth (); - l = r.RuneLen(); + l = r.RuneUnicodeLength (); if (r.Value == '\t') { s += tWidth + 1; l += tWidth - 1; @@ -296,7 +297,7 @@ namespace Terminal.Gui { for (int i = tcount; i >= 0; i--) { var rune = t [i]; - size += rune.ColumnWidth(); + size += rune.ColumnWidth (); if (rune.Value == '\t') { size += tabWidth + 1; } @@ -407,12 +408,12 @@ namespace Terminal.Gui { { var origTxt = StringExtensions.Make (source); (int _, int len) = TextModel.DisplaySize (source, 0, col, false); - (var _, var len2) = TextModel.DisplaySize (source, col, col + matchText.Length, false); - (var _, var len3) = TextModel.DisplaySize (source, col + matchText.Length, origTxt.RuneCount(), false); + (int _, int len2) = TextModel.DisplaySize (source, col, col + matchText.Length, false); + (int _, int len3) = TextModel.DisplaySize (source, col + matchText.Length, origTxt.RuneCount (), false); - return origTxt[..len] + + return origTxt [..len] + textToReplace + - origTxt.Substring (len + len2, len + len2 + len3); + origTxt.Substring (len + len2, len3); } bool ApplyToFind ((Point current, bool found) foundPos) @@ -517,7 +518,7 @@ namespace Terminal.Gui { if (line.Count > 0) { return line [col > line.Count - 1 ? line.Count - 1 : col]; } else { - return (Rune)0; + return default; } } @@ -544,7 +545,7 @@ namespace Terminal.Gui { return true; } } - rune = (Rune)0; + rune = default; return false; } @@ -558,7 +559,7 @@ namespace Terminal.Gui { return true; } if (row == 0) { - rune = (Rune)0; + rune = default; return false; } while (row > 0) { @@ -570,7 +571,7 @@ namespace Terminal.Gui { return true; } } - rune = (Rune)0; + rune = default; return false; } @@ -1596,7 +1597,7 @@ namespace Terminal.Gui { //historyText.Clear (Text); if (!_multiline && !IsInitialized) { - _currentColumn = Text.RuneCount(); + _currentColumn = Text.RuneCount (); _leftColumn = _currentColumn > Frame.Width + 1 ? _currentColumn - Frame.Width + 1 : 0; } } @@ -2000,7 +2001,7 @@ namespace Terminal.Gui { set { _historyText.Clear (Text); } - } + } /// /// Indicates whatever the text has history changes or not. @@ -2495,9 +2496,9 @@ namespace Terminal.Gui { _selectionStartColumn = foundPos.current.X; _selectionStartRow = foundPos.current.Y; if (!replaceAll) { - _currentColumn = _selectionStartColumn + text.RuneCount(); + _currentColumn = _selectionStartColumn + text.RuneCount (); } else { - _currentColumn = _selectionStartColumn + textToReplace.RuneCount(); + _currentColumn = _selectionStartColumn + textToReplace.RuneCount (); } _currentRow = foundPos.current.Y; if (!_isReadOnly && replace) { @@ -2505,7 +2506,7 @@ namespace Terminal.Gui { ClearSelectedRegion (); InsertAllText (textToReplace); StartSelecting (); - _selectionStartColumn = _currentColumn - textToReplace.RuneCount(); + _selectionStartColumn = _currentColumn - textToReplace.RuneCount (); } else { UpdateWrapModel (); SetNeedsDisplay (); @@ -2774,7 +2775,7 @@ namespace Terminal.Gui { throw new ArgumentNullException (nameof (runes)); int size = 0; foreach (var rune in runes) { - size += RuneExtensions.RuneLen (rune); + size += rune.RuneUnicodeLength (); } var encoded = new byte [size]; int offset = 0; @@ -4180,7 +4181,7 @@ namespace Terminal.Gui { ClearRegion (); } _copyWithoutSelection = false; - InsertText (contents); + InsertAllText (contents); if (_selecting) { _historyText.ReplaceLast (new List> () { new List (GetCurrentLine ()) }, CursorPosition, diff --git a/Terminal.Gui/Views/TreeView/Branch.cs b/Terminal.Gui/Views/TreeView/Branch.cs index fe515ebc7..50680383e 100644 --- a/Terminal.Gui/Views/TreeView/Branch.cs +++ b/Terminal.Gui/Views/TreeView/Branch.cs @@ -154,7 +154,7 @@ namespace Terminal.Gui { } // If body of line is too long - if (lineBody.Sum (l => ((Rune)l).ColumnWidth ()) > availableWidth) { + if (lineBody.EnumerateRunes ().Sum (l => l.ColumnWidth ()) > availableWidth) { // remaining space is zero and truncate the line lineBody = new string (lineBody.TakeWhile (c => (availableWidth -= ((Rune)c).ColumnWidth ()) >= 0).ToArray ()); availableWidth = 0; diff --git a/UICatalog/Scenarios/CharacterMap.cs b/UICatalog/Scenarios/CharacterMap.cs index 94ec95902..dba00d307 100644 --- a/UICatalog/Scenarios/CharacterMap.cs +++ b/UICatalog/Scenarios/CharacterMap.cs @@ -278,13 +278,12 @@ namespace UICatalog.Scenarios { Driver.SetAttribute (GetNormalColor ()); for (int col = 0; col < 16; col++) { uint glyph = (uint)((uint)val + col); - var rune = new Rune (glyph); - //if (rune >= 0x00D800 && rune <= 0x00DFFF) { - // if (col == 0) { - // Driver.AddStr ("Reserved for surrogate pairs."); - // } - // continue; - //} + Rune rune; + if (char.IsSurrogate ((char)glyph)) { + rune = Rune.ReplacementChar; + } else { + rune = new Rune (glyph); + } Move (firstColumnX + (col * COLUMN_WIDTH) + 1, y + 1); if (glyph == SelectedGlyph) { Driver.SetAttribute (HasFocus ? ColorScheme.HotFocus : ColorScheme.HotNormal); diff --git a/UICatalog/Scenarios/Scrolling.cs b/UICatalog/Scenarios/Scrolling.cs index f160478cf..fb37d1c48 100644 --- a/UICatalog/Scenarios/Scrolling.cs +++ b/UICatalog/Scenarios/Scrolling.cs @@ -93,7 +93,7 @@ namespace UICatalog.Scenarios { break; } Driver.AddRune (r); - nw += r.RuneLen (); + nw += r.Utf8SequenceLength; } if (nw > w) w = nw; diff --git a/UICatalog/Scenarios/TreeViewFileSystem.cs b/UICatalog/Scenarios/TreeViewFileSystem.cs index 3e09d1bdf..3b85252bf 100644 --- a/UICatalog/Scenarios/TreeViewFileSystem.cs +++ b/UICatalog/Scenarios/TreeViewFileSystem.cs @@ -51,10 +51,10 @@ namespace UICatalog.Scenarios { Checked = true, CheckType = MenuItemCheckStyle.Checked }, null /*separator*/, - _miPlusMinus = new MenuItem ("_Plus Minus Symbols", "+ -", () => SetExpandableSymbols('+','-')){Checked = true, CheckType = MenuItemCheckStyle.Radio}, - _miArrowSymbols = new MenuItem ("_Arrow Symbols", "> v", () => SetExpandableSymbols('>','v')){Checked = false, CheckType = MenuItemCheckStyle.Radio}, - _miNoSymbols = new MenuItem ("_No Symbols", "", () => SetExpandableSymbols(null,null)){Checked = false, CheckType = MenuItemCheckStyle.Radio}, - _miUnicodeSymbols = new MenuItem ("_Unicode", "ஹ ﷽", () => SetExpandableSymbols('ஹ','﷽')){Checked = false, CheckType = MenuItemCheckStyle.Radio}, + _miPlusMinus = new MenuItem ("_Plus Minus Symbols", "+ -", () => SetExpandableSymbols((Rune)'+',(Rune)'-')){Checked = true, CheckType = MenuItemCheckStyle.Radio}, + _miArrowSymbols = new MenuItem ("_Arrow Symbols", "> v", () => SetExpandableSymbols((Rune)'>',(Rune)'v')){Checked = false, CheckType = MenuItemCheckStyle.Radio}, + _miNoSymbols = new MenuItem ("_No Symbols", "", () => SetExpandableSymbols(default,null)){Checked = false, CheckType = MenuItemCheckStyle.Radio}, + _miUnicodeSymbols = new MenuItem ("_Unicode", "ஹ ﷽", () => SetExpandableSymbols((Rune)'ஹ',(Rune)'﷽')){Checked = false, CheckType = MenuItemCheckStyle.Radio}, null /*separator*/, _miColoredSymbols = new MenuItem ("_Colored Symbols", "", () => ShowColoredExpandableSymbols()){Checked = false, CheckType = MenuItemCheckStyle.Checked}, _miInvertSymbols = new MenuItem ("_Invert Symbols", "", () => InvertExpandableSymbols()){Checked = false, CheckType = MenuItemCheckStyle.Checked}, @@ -254,12 +254,12 @@ namespace UICatalog.Scenarios { treeViewFiles.SetNeedsDisplay (); } - private void SetExpandableSymbols (Rune? expand, Rune? collapse) + private void SetExpandableSymbols (Rune expand, Rune? collapse) { - _miPlusMinus.Checked = expand == '+'; - _miArrowSymbols.Checked = expand == '>'; - _miNoSymbols.Checked = expand == null; - _miUnicodeSymbols.Checked = expand == 'ஹ'; + _miPlusMinus.Checked = expand.Value == '+'; + _miArrowSymbols.Checked = expand.Value == '>'; + _miNoSymbols.Checked = expand.Value == default; + _miUnicodeSymbols.Checked = expand.Value == 'ஹ'; treeViewFiles.Style.ExpandableSymbol = expand; treeViewFiles.Style.CollapseableSymbol = collapse; diff --git a/UnitTests/Text/RuneTests.cs b/UnitTests/Text/RuneTests.cs index 95247d54e..6966d042b 100644 --- a/UnitTests/Text/RuneTests.cs +++ b/UnitTests/Text/RuneTests.cs @@ -34,55 +34,56 @@ namespace Terminal.Gui.TextTests { Assert.Equal (1, a.ColumnWidth ()); Assert.Equal ("a", a.ToString ()); Assert.Equal (1, a.ToString ().Length); - Assert.Equal (1, a.RuneLen ()); + Assert.Equal (1, a.Utf8SequenceLength); Assert.Equal (1, b.ColumnWidth ()); Assert.Equal ("b", b.ToString ()); Assert.Equal (1, b.ToString ().Length); - Assert.Equal (1, b.RuneLen ()); + Assert.Equal (1, b.Utf8SequenceLength); var rl = a < b; Assert.True (rl); Assert.Equal (1, c.ColumnWidth ()); Assert.Equal ("{", c.ToString ()); Assert.Equal (1, c.ToString ().Length); - Assert.Equal (1, c.RuneLen ()); + Assert.Equal (1, c.Utf8SequenceLength); Assert.Equal (2, d.ColumnWidth ()); Assert.Equal ("ᅐ", d.ToString ()); Assert.Equal (1, d.ToString ().Length); - Assert.Equal (3, d.RuneLen ()); + Assert.Equal (3, d.Utf8SequenceLength); Assert.Equal (0, e.ColumnWidth ()); string join = "\u1104\u1161"; Assert.Equal ("따", join); - Assert.Equal (2, join.Sum (x => ((Rune)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.ToRunes () [0].DecodeSurrogatePair (out char [] spair)); + Assert.False (join.DecodeSurrogatePair (out char [] spair)); Assert.Equal (2, join.RuneCount ()); Assert.Equal (2, join.Length); Assert.Equal ("ᅡ", e.ToString ()); Assert.Equal (1, e.ToString ().Length); - Assert.Equal (3, e.RuneLen ()); + Assert.Equal (3, e.Utf8SequenceLength); string joinNormalize = join.Normalize (); Assert.Equal ("따", joinNormalize); - Assert.Equal (2, joinNormalize.Sum (x => ((Rune)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.ToRunes () [0].DecodeSurrogatePair (out spair)); + Assert.False (joinNormalize.DecodeSurrogatePair (out spair)); Assert.Equal (1, joinNormalize.RuneCount ()); Assert.Equal (1, joinNormalize.Length); Assert.Equal (-1, f.ColumnWidth ()); Assert.Equal (1, f.ToString ().Length); - Assert.Equal (1, f.RuneLen ()); + Assert.Equal (1, f.Utf8SequenceLength); Assert.Equal (-1, g.ColumnWidth ()); Assert.Equal (1, g.ToString ().Length); - Assert.Equal (1, g.RuneLen ()); + Assert.Equal (1, g.Utf8SequenceLength); var uh = h; (var runeh, var sizeh) = uh.DecodeRune (); - Assert.Equal (2, runeh.ColumnWidth ()); + Assert.Equal (1, runeh.ColumnWidth ()); Assert.Equal ("🨁", h); Assert.Equal (2, runeh.ToString ().Length); - Assert.Equal (4, runeh.RuneLen ()); - Assert.Equal (sizeh, runeh.RuneLen ()); + Assert.Equal (4, runeh.Utf8SequenceLength); + Assert.Equal (sizeh, runeh.Utf8SequenceLength); for (int x = 0; x < uh.Length - 1; x++) { - Assert.Equal (0, char.ConvertToUtf32 (uh [x], uh [x + 1])); - Assert.False (RuneExtensions.EncodeSurrogatePair (uh [x], uh [x + 1], out _)); + Assert.Equal (0x1FA01, char.ConvertToUtf32 (uh [x], uh [x + 1])); + Assert.True (RuneExtensions.EncodeSurrogatePair (uh [x], uh [x + 1], out result)); + Assert.Equal (0x1FA01, result.Value); } Assert.True (Rune.IsValid (runeh.Value)); Assert.True (RuneExtensions.IsValid (uh.ToByteArray ())); @@ -90,37 +91,38 @@ namespace Terminal.Gui.TextTests { Assert.Equal (1, uh.RuneCount ()); (var runelh, var sizelh) = uh.DecodeLastRune (); - Assert.Equal (2, runelh.ColumnWidth ()); + Assert.Equal (1, runelh.ColumnWidth ()); Assert.Equal (2, runelh.ToString ().Length); - Assert.Equal (4, runelh.RuneLen ()); - Assert.Equal (sizelh, runelh.RuneLen ()); + Assert.Equal (4, runelh.Utf8SequenceLength); + Assert.Equal (sizelh, runelh.Utf8SequenceLength); Assert.True (Rune.IsValid (runelh.Value)); var ui = i; (var runei, var sizei) = ui.DecodeRune (); - Assert.Equal (2, runei.ColumnWidth ()); + Assert.Equal (1, runei.ColumnWidth ()); Assert.Equal ("󠿡", i); Assert.Equal (2, runei.ToString ().Length); - Assert.Equal (4, runei.RuneLen ()); - Assert.Equal (sizei, runei.RuneLen ()); + Assert.Equal (4, runei.Utf8SequenceLength); + Assert.Equal (sizei, runei.Utf8SequenceLength); for (int x = 0; x < ui.Length - 1; x++) { - Assert.Equal (0, char.ConvertToUtf32 (uh [x], uh [x + 1])); - Assert.False (RuneExtensions.EncodeSurrogatePair (ui [x], ui [x + 1], out _)); + Assert.Equal (0xE0FE1, char.ConvertToUtf32 (ui [x], ui [x + 1])); + Assert.True (RuneExtensions.EncodeSurrogatePair (ui [x], ui [x + 1], out result)); + Assert.Equal (0xE0FE1, result.Value); } Assert.True (Rune.IsValid (runei.Value)); Assert.True (RuneExtensions.IsValid (ui.ToByteArray ())); //Assert.True (Rune.FullRune (ui.ToByteArray ())); (var runeli, var sizeli) = ui.DecodeLastRune (); - Assert.Equal (2, runeli.ColumnWidth ()); + Assert.Equal (1, runeli.ColumnWidth ()); Assert.Equal (2, runeli.ToString ().Length); - Assert.Equal (4, runeli.RuneLen ()); - Assert.Equal (sizeli, runeli.RuneLen ()); + Assert.Equal (4, runeli.Utf8SequenceLength); + Assert.Equal (sizeli, runeli.Utf8SequenceLength); Assert.True (Rune.IsValid (runeli.Value)); Assert.Equal (runeh.ColumnWidth (), runei.ColumnWidth ()); Assert.NotEqual (h, i); Assert.Equal (runeh.ToString ().Length, runei.ToString ().Length); - Assert.Equal (runeh.RuneLen (), runei.RuneLen ()); + Assert.Equal (runeh.Utf8SequenceLength, runei.Utf8SequenceLength); var uj = j.ToString (); (var runej, var sizej) = uj.DecodeRune (); Assert.Equal (0, j.ColumnWidth ()); @@ -130,51 +132,51 @@ namespace Terminal.Gui.TextTests { Assert.Equal ("⃐", uj); Assert.Equal (1, j.ToString ().Length); Assert.Equal (1, runej.ToString ().Length); - Assert.Equal (3, j.RuneLen ()); - Assert.Equal (sizej, runej.RuneLen ()); + Assert.Equal (3, j.Utf8SequenceLength); + Assert.Equal (sizej, runej.Utf8SequenceLength); Assert.Equal (1, k.ColumnWidth ()); Assert.Equal ("■", k.ToString ()); Assert.Equal (1, k.ToString ().Length); - Assert.Equal (3, k.RuneLen ()); + Assert.Equal (3, k.Utf8SequenceLength); Assert.Equal (1, l.ColumnWidth ()); Assert.Equal ("□", l.ToString ()); Assert.Equal (1, l.ToString ().Length); - Assert.Equal (3, l.RuneLen ()); + Assert.Equal (3, l.Utf8SequenceLength); Assert.Equal (1, m.ColumnWidth ()); Assert.Equal ("", m.ToString ()); Assert.Equal (1, m.ToString ().Length); - Assert.Equal (3, m.RuneLen ()); - var rn = StringExtensions.Make (n).DecodeRune ().rune; + Assert.Equal (3, m.Utf8SequenceLength); + var rn = StringExtensions.Make (n).DecodeRune ().Rune; Assert.Equal (2, rn.ColumnWidth ()); Assert.Equal ("🍕", rn.ToString ()); Assert.Equal (2, rn.ToString ().Length); - Assert.Equal (4, rn.RuneLen ()); + Assert.Equal (4, rn.Utf8SequenceLength); Assert.Equal (2, o.ColumnWidth ()); Assert.Equal ("🍕", o.ToString ()); Assert.Equal (2, o.ToString ().Length); - Assert.Equal (4, o.RuneLen ()); - var rp = p.DecodeRune ().rune; + Assert.Equal (4, o.Utf8SequenceLength); + var rp = p.DecodeRune ().Rune; Assert.Equal (2, rp.ColumnWidth ()); Assert.Equal ("🍕", p); Assert.Equal (2, p.Length); - Assert.Equal (4, rp.RuneLen ()); + Assert.Equal (4, rp.Utf8SequenceLength); Assert.Equal (1, q.ColumnWidth ()); Assert.Equal ("℃", q.ToString ()); Assert.Equal (1, q.ToString ().Length); - Assert.Equal (3, q.RuneLen ()); - var rq = q.ToString ().DecodeRune ().rune; + Assert.Equal (3, q.Utf8SequenceLength); + var rq = q.ToString ().DecodeRune ().Rune; Assert.Equal (1, rq.ColumnWidth ()); Assert.Equal ("℃", rq.ToString ()); Assert.Equal (1, rq.ToString ().Length); - Assert.Equal (3, rq.RuneLen ()); + Assert.Equal (3, rq.Utf8SequenceLength); Assert.Equal (2, r.ColumnWidth ()); Assert.Equal ("ᄀ", r.ToString ()); Assert.Equal (1, r.ToString ().Length); - Assert.Equal (3, r.RuneLen ()); + Assert.Equal (3, r.Utf8SequenceLength); Assert.Equal (1, s.ColumnWidth ()); Assert.Equal ("━", s.ToString ()); Assert.Equal (1, s.ToString ().Length); - Assert.Equal (3, s.RuneLen ()); + Assert.Equal (3, s.Utf8SequenceLength); var buff = new byte [4]; var sb = ((Rune)'\u2503').EncodeRune (buff); Assert.Equal (1, ((Rune)'\u2503').ColumnWidth ()); @@ -194,49 +196,49 @@ namespace Terminal.Gui.TextTests { Assert.Equal ('\u1100', (uint)rune.Value); string str = "\u2615"; Assert.Equal ("☕", str); - Assert.Equal (2, str.Sum (x => ((Rune)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.Sum (x => ((Rune)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.Sum (x => ((Rune)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.Sum (x => ((Rune)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.Sum (x => ((Rune)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.Sum (x => ((Rune)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); str = "\ud83e\udd16"; Assert.Equal ("🤖", str); - Assert.Equal (2, str.Sum (x => ((Rune)x).ColumnWidth ())); + Assert.Equal (2, str.EnumerateRunes ().Sum (x => x.ColumnWidth ())); Assert.Equal (2, str.ConsoleWidth ()); Assert.Equal (1, str.RuneCount ()); // Here returns 1 because is a valid surrogate pair resulting in only rune >=U+10000..U+10FFFF Assert.Equal (2, str.Length); // String always preserves the originals values of each surrogate pair str = "\U0001f9e0"; Assert.Equal ("🧠", str); - Assert.Equal (2, str.Sum (x => ((Rune)x).ColumnWidth ())); + Assert.Equal (2, str.EnumerateRunes ().Sum (x => x.ColumnWidth ())); Assert.Equal (2, str.ConsoleWidth ()); Assert.Equal (1, str.RuneCount ()); Assert.Equal (2, str.Length); @@ -258,16 +260,16 @@ namespace Terminal.Gui.TextTests { Assert.Equal (1, c.ToString ().Length); Assert.Equal ("a", c.ToString ()); Rune d = new Rune (0x10421); - Assert.Equal (2, d.ColumnWidth ()); + Assert.Equal (1, d.ColumnWidth ()); // Many surrogate pairs only occupies 1 column Assert.Equal (2, d.ToString ().Length); Assert.Equal ("𐐡", d.ToString ()); Assert.False (RuneExtensions.EncodeSurrogatePair ('\ud799', '\udc21', out Rune rune)); Assert.Throws (() => new Rune ('\ud799', '\udc21')); Rune e = new Rune ('\ud801', '\udc21'); - Assert.Equal (2, e.ColumnWidth ()); + Assert.Equal (1, e.ColumnWidth ()); Assert.Equal (2, e.ToString ().Length); Assert.Equal ("𐐡", e.ToString ()); - Assert.False (Rune.IsValid (new Rune ('\ud801').Value)); + Assert.Throws (() => Assert.False (Rune.IsValid (new Rune ('\ud801').Value))); Rune f = new Rune ('\ud83c', '\udf39'); Assert.Equal (2, f.ColumnWidth ()); Assert.Equal (2, f.ToString ().Length); @@ -276,8 +278,8 @@ namespace Terminal.Gui.TextTests { Assert.Null (exception); Rune g = new Rune (0x10ffff); string s = "\U0010ffff"; - Assert.Equal (2, g.ColumnWidth ()); - Assert.Equal (2, s.ConsoleWidth ()); + Assert.Equal (1, g.ColumnWidth ()); + Assert.Equal (1, s.ConsoleWidth ()); Assert.Equal (2, g.ToString ().Length); Assert.Equal (2, s.Length); Assert.Equal ("􏿿", g.ToString ()); @@ -301,11 +303,11 @@ namespace Terminal.Gui.TextTests { Assert.Equal (2, k.ToString ().Length); Assert.Equal ("🐂", k.ToString ()); var l = new Rune ('\ud801', '\udcbb'); - Assert.Equal (2, l.ColumnWidth ()); + Assert.Equal (1, l.ColumnWidth ()); Assert.Equal (2, l.ToString ().Length); Assert.Equal ("𐒻", l.ToString ()); var m = new Rune ('\ud801', '\udccf'); - Assert.Equal (2, m.ColumnWidth ()); + Assert.Equal (1, m.ColumnWidth ()); Assert.Equal (2, m.ToString ().Length); Assert.Equal ("𐓏", m.ToString ()); var n = new Rune ('\u00e1'); @@ -324,26 +326,27 @@ namespace Terminal.Gui.TextTests { Assert.Equal (2, q.ColumnWidth ()); Assert.Equal (1, q.ToString ().Length); Assert.Equal ("〉", q.ToString ()); - var r = "\U0000232a".DecodeRune ().rune; + var r = "\U0000232a".DecodeRune ().Rune; Assert.Equal (2, r.ColumnWidth ()); Assert.Equal (1, r.ToString ().Length); Assert.Equal ("〉", r.ToString ()); PrintTextElementCount ('\u00e1'.ToString (), "á", 1, 1, 1, 1); - PrintTextElementCount (new string ('\u0061', '\u0301'), "á", 1, 2, 2, 1); - PrintTextElementCount (new string ('\u0065', '\u0301'), "é", 1, 2, 2, 1); + PrintTextElementCount (new string (new char [] { '\u0061', '\u0301' }), "á", 1, 2, 2, 1); + PrintTextElementCount (StringExtensions.Make ('\u0061', '\u0301'), "á", 1, 2, 2, 1); + PrintTextElementCount (StringExtensions.Make ('\u0065', '\u0301'), "é", 1, 2, 2, 1); PrintTextElementCount (StringExtensions.Make (new Rune [] { new Rune (0x1f469), new Rune (0x1f3fd), new Rune ('\u200d'), new Rune (0x1f692) }), "👩🏽‍🚒", 6, 4, 7, 1); PrintTextElementCount (StringExtensions.Make (new Rune [] { new Rune (0x1f469), new Rune (0x1f3fd), new Rune ('\u200d'), new Rune (0x1f692) }), "\U0001f469\U0001f3fd\u200d\U0001f692", 6, 4, 7, 1); PrintTextElementCount (StringExtensions.Make (new Rune ('\ud801', '\udccf')), - "\ud801\udccf", 2, 1, 2, 1); + "𐓏", 1, 1, 2, 1); } void PrintTextElementCount (string us, string s, int consoleWidth, int runeCount, int stringCount, int txtElementCount) { - Assert.NotEqual (us.Length, s.Length); - Assert.Equal (us.ToString (), s); + Assert.Equal (us.Length, s.Length); + Assert.Equal (us, s); Assert.Equal (consoleWidth, us.ConsoleWidth ()); Assert.Equal (runeCount, us.RuneCount ()); Assert.Equal (stringCount, s.Length); @@ -368,7 +371,7 @@ namespace Terminal.Gui.TextTests { int CountLettersInString (string s) { int letterCount = 0; - foreach (Rune rune in s) { + foreach (Rune rune in s.EnumerateRunes ()) { if (Rune.IsLetter (rune)) { letterCount++; } } @@ -387,27 +390,37 @@ namespace Terminal.Gui.TextTests { bool ProcessTestStringUseChar (string s) { + char surrogateChar = default; for (int i = 0; i < s.Length; i++) { - Rune r = new Rune (s [i]); - if (!char.IsSurrogate (s [i])) { + Rune r; + if (char.IsSurrogate (s [i])) { + if (surrogateChar != default && char.IsSurrogate (surrogateChar)) { + r = new Rune (surrogateChar, s [i]); + Assert.True (r.IsSurrogatePair ()); + int codePoint = char.ConvertToUtf32 (surrogateChar, s [i]); + RuneExtensions.EncodeSurrogatePair (surrogateChar, s [i], out Rune rune); + Assert.Equal (codePoint, rune.Value); + string sp = new string (new char [] { surrogateChar, s [i] }); + r = (Rune)codePoint; + Assert.Equal (sp, r.ToString ()); + Assert.True (r.IsSurrogatePair ()); + + surrogateChar = default; + } else if (i < s.Length - 1) { + surrogateChar = s [i]; + continue; + } else { + Assert.Throws (() => new Rune (s [i])); + throw new Exception ("String was not well-formed UTF-16."); + } + } else { + r = new Rune (s [i]); var buff = new byte [4]; ((Rune)s [i]).EncodeRune (buff); Assert.Equal ((int)s [i], buff [0]); Assert.Equal (s [i], r.Value); Assert.True (Rune.IsValid (r.Value)); Assert.False (r.IsSurrogatePair ()); - } else if (i + 1 < s.Length && char.IsSurrogatePair (s [i], s [i + 1])) { - int codePoint = char.ConvertToUtf32 (s [i], s [i + 1]); - RuneExtensions.EncodeSurrogatePair (s [i], s [i + 1], out Rune rune); - Assert.Equal (codePoint, rune.Value); - string sp = new string (new char [] { s [i], s [i + 1] }); - r = (Rune)codePoint; - Assert.Equal (sp, r.ToString ()); - Assert.True (r.IsSurrogatePair ()); - i++; // Increment the iterator by the number of surrogate pair - } else { - Assert.False (Rune.IsValid (r.Value)); - throw new Exception ("String was not well-formed UTF-16."); } } return true; @@ -422,14 +435,16 @@ namespace Terminal.Gui.TextTests { int colWidth = 0; for (int i = 0; i < s.Length; i++) { - Rune rune = new Rune (s [i]); - if (Rune.IsValid (rune.Value)) { + Rune rune = default; + if (Rune.IsValid (s [i])) { + rune = new Rune (s [i]); Assert.True (Rune.IsValid (rune.Value)); runes.Add (rune); Assert.Equal (s [i], rune.Value); Assert.False (rune.IsSurrogatePair ()); } else if (i + 1 < s.Length && (RuneExtensions.EncodeSurrogatePair (s [i], s [i + 1], out codePoint))) { - Assert.False (Rune.IsValid (rune.Value)); + Assert.Equal (0, rune.Value); + Assert.False (Rune.IsValid (s [i])); rune = codePoint; runes.Add (rune); string sp = new string (new char [] { s [i], s [i + 1] }); @@ -437,7 +452,7 @@ namespace Terminal.Gui.TextTests { Assert.True (codePoint.IsSurrogatePair ()); i++; // Increment the iterator by the number of surrogate pair } else { - Assert.False (Rune.IsValid (rune.Value)); + Assert.Throws (() => new Rune (s [i])); throw new Exception ("String was not well-formed UTF-16."); } colWidth += rune.ColumnWidth (); // Increment the column width of this Rune @@ -466,7 +481,7 @@ namespace Terminal.Gui.TextTests { Assert.True (Rune.IsValid (new Rune ('\ud83c', '\udf39').Value)); Assert.False (Rune.IsValid ('\ud801')); Assert.False (Rune.IsValid ((uint)'\ud801')); - Assert.False (Rune.IsValid (((Rune)'\ud801').Value)); + Assert.Throws (() => Assert.False (Rune.IsValid (((Rune)'\ud801').Value))); } [Fact] @@ -477,15 +492,18 @@ namespace Terminal.Gui.TextTests { Assert.Equal (4, rune1.EncodeRune (buff1)); Assert.True (RuneExtensions.IsValid (buff1)); Assert.Equal (2, rune1.ToString ().Length); - Assert.Equal (4, rune1.RuneLen ()); - var rune2 = (Rune)'\ud801'; // To avoid throwing an exception set as uint instead a Rune instance. - var buff2 = new byte [4]; - Assert.Equal (3, rune2.EncodeRune (buff2)); - Assert.False (RuneExtensions.IsValid (buff2)); // To avoid throwing an exception pass as uint parameter instead Rune. - Assert.Equal (5, rune2.ToString ().Length); // Invalid string. It returns the decimal 55297 representation of the 0xd801 hexadecimal. - Assert.Equal (-1, rune2.RuneLen ()); - Assert.Equal (3, new Rune ('\ud801').EncodeRune (buff2)); // error - Assert.Equal (new byte [] { 0xef, 0x3f, 0x3d, 0 }, buff2); // error + Assert.Equal (4, rune1.Utf8SequenceLength); + var c = '\ud801'; + var buff2 = Encoding.UTF8.GetBytes (new char [] { c }); + //var buff2 = new byte [4]; + Assert.Equal (3, buff2.Length); + var str = Encoding.UTF8.GetString (buff2); + Assert.Equal ("�", str); + Assert.False (RuneExtensions.IsValid (buff2)); + Assert.Equal (1, str.Length); + Assert.Throws (() => (Rune)'\ud801'); + Assert.Equal (new byte [] { 0xef, 0xbf, 0xbd }, buff2); + Assert.Equal (Rune.ReplacementChar.ToString (), str); } [Fact] @@ -493,17 +511,17 @@ namespace Terminal.Gui.TextTests { { Rune l = (Rune)'\u0370'; Assert.False (l.IsNonSpacingChar ()); - Assert.Equal (1, l.ColumnWidth()); - Assert.Equal (1, StringExtensions.Make (l).ConsoleWidth()); + Assert.Equal (1, l.ColumnWidth ()); + Assert.Equal (1, StringExtensions.Make (l).ConsoleWidth ()); Rune ns = (Rune)'\u302a'; - Assert.False (ns.IsNonSpacingChar()); - Assert.Equal (2, ns.ColumnWidth()); - Assert.Equal (2, StringExtensions.Make(ns).ConsoleWidth()); + Assert.False (ns.IsNonSpacingChar ()); + Assert.Equal (2, ns.ColumnWidth ()); + Assert.Equal (2, StringExtensions.Make (ns).ConsoleWidth ()); l = (Rune)'\u006f'; ns = (Rune)'\u0302'; var s = "\u006f\u0302"; - Assert.Equal (1, l.ColumnWidth()); - Assert.Equal (0, ns.ColumnWidth()); + Assert.Equal (1, l.ColumnWidth ()); + Assert.Equal (0, ns.ColumnWidth ()); var ul = StringExtensions.Make (l); Assert.Equal ("o", ul); var uns = StringExtensions.Make (ns); @@ -511,8 +529,8 @@ namespace Terminal.Gui.TextTests { var f = $"{l}{ns}"; Assert.Equal ("ô", f); Assert.Equal (f, s); - Assert.Equal (1, f.ConsoleWidth()); - Assert.Equal (1, s.Sum (c => ((Rune)c).ColumnWidth ())); + Assert.Equal (1, f.ConsoleWidth ()); + Assert.Equal (1, s.EnumerateRunes().Sum (c => c.ColumnWidth ())); Assert.Equal (2, s.Length); (var rune, var size) = f.DecodeRune (); Assert.Equal (rune, l); @@ -520,8 +538,8 @@ namespace Terminal.Gui.TextTests { l = (Rune)'\u0041'; ns = (Rune)'\u0305'; s = "\u0041\u0305"; - Assert.Equal (1, l.ColumnWidth()); - Assert.Equal (0, ns.ColumnWidth()); + Assert.Equal (1, l.ColumnWidth ()); + Assert.Equal (0, ns.ColumnWidth ()); ul = StringExtensions.Make (l); Assert.Equal ("A", ul); uns = StringExtensions.Make (ns); @@ -529,8 +547,8 @@ namespace Terminal.Gui.TextTests { f = $"{l}{ns}"; Assert.Equal ("A̅", f); Assert.Equal (f, s); - Assert.Equal (1, f.ConsoleWidth()); - Assert.Equal (1, s.Sum (c => ((Rune)c).ColumnWidth ())); + Assert.Equal (1, f.ConsoleWidth ()); + Assert.Equal (1, s.EnumerateRunes().Sum(c => c.ColumnWidth())); Assert.Equal (2, s.Length); (rune, size) = f.DecodeRune (); Assert.Equal (rune, l); @@ -539,7 +557,7 @@ namespace Terminal.Gui.TextTests { ns = (Rune)'\u0308'; s = "\u0061\u0308"; Assert.Equal (1, l.ColumnWidth ()); - Assert.Equal (0, ns.ColumnWidth()); + Assert.Equal (0, ns.ColumnWidth ()); ul = StringExtensions.Make (l); Assert.Equal ("a", ul); uns = StringExtensions.Make (ns); @@ -547,8 +565,8 @@ namespace Terminal.Gui.TextTests { f = $"{l}{ns}"; Assert.Equal ("ä", f); Assert.Equal (f, s); - Assert.Equal (1, f.ConsoleWidth()); - Assert.Equal (1, s.Sum (c => ((Rune)c).ColumnWidth())); + Assert.Equal (1, f.ConsoleWidth ()); + Assert.Equal (1, s.EnumerateRunes().Sum(c => c.ColumnWidth())); Assert.Equal (2, s.Length); (rune, size) = f.DecodeRune (); Assert.Equal (rune, l); @@ -556,8 +574,8 @@ namespace Terminal.Gui.TextTests { l = (Rune)'\u4f00'; ns = (Rune)'\u302a'; s = "\u4f00\u302a"; - Assert.Equal (2, l.ColumnWidth()); - Assert.Equal (2, ns.ColumnWidth()); + Assert.Equal (2, l.ColumnWidth ()); + Assert.Equal (2, ns.ColumnWidth ()); ul = StringExtensions.Make (l); Assert.Equal ("伀", ul); uns = StringExtensions.Make (ns); @@ -565,8 +583,8 @@ namespace Terminal.Gui.TextTests { f = $"{l}{ns}"; Assert.Equal ("伀〪", f); // Occupies 4 columns. Assert.Equal (f, s); - Assert.Equal (4, f.ConsoleWidth()); - Assert.Equal (4, s.Sum (c => ((Rune)c).ColumnWidth())); + Assert.Equal (4, f.ConsoleWidth ()); + Assert.Equal (4, s.EnumerateRunes().Sum(c => c.ColumnWidth())); Assert.Equal (2, s.Length); (rune, size) = f.DecodeRune (); Assert.Equal (rune, l); @@ -577,8 +595,8 @@ namespace Terminal.Gui.TextTests { public void Test_IsWideChar () { Assert.True (((Rune)0x115e).IsWideChar ()); - Assert.Equal (2, ((Rune)0x115e).ColumnWidth()); - Assert.False (((Rune)0x116f).IsWideChar()); + Assert.Equal (2, ((Rune)0x115e).ColumnWidth ()); + Assert.False (((Rune)0x116f).IsWideChar ()); } [Fact] @@ -595,32 +613,32 @@ namespace Terminal.Gui.TextTests { const int end = 0x10ffff; for (int i = start; i <= end; i++) { - Rune r = new Rune ((uint)i); - if (!r.IsValid()) { + if (char.IsSurrogate ((char)i)) { continue; } + Rune r = new Rune ((uint)i); string us = StringExtensions.Make (r); string hex = i.ToString ("x6"); int v = int.Parse (hex, System.Globalization.NumberStyles.HexNumber); string s = char.ConvertFromUtf32 (v); - if (!r.IsSurrogatePair()) { + if (!r.IsSurrogatePair ()) { Assert.Equal (r.ToString (), us); Assert.Equal (us, s); if (r.ColumnWidth () < 0) { - Assert.NotEqual (r.ColumnWidth (), us.ConsoleWidth()); - Assert.NotEqual (s.Sum (c => ((Rune)c).ColumnWidth ()), us.ConsoleWidth()); + Assert.NotEqual (r.ColumnWidth (), us.ConsoleWidth ()); + Assert.NotEqual (s.EnumerateRunes().Sum (c => c.ColumnWidth ()), us.ConsoleWidth ()); } else { - Assert.Equal (r.ColumnWidth (), us.ConsoleWidth()); - Assert.Equal (s.Sum (c => ((Rune)c).ColumnWidth ()), us.ConsoleWidth()); + Assert.Equal (r.ColumnWidth (), us.ConsoleWidth ()); + Assert.Equal (s.EnumerateRunes().Sum (c => c.ColumnWidth ()), us.ConsoleWidth ()); } - Assert.Equal (us.RuneCount(), s.Length); + Assert.Equal (us.RuneCount (), s.Length); } else { - Assert.Equal (r.ToString (), us.ToString ()); - Assert.Equal (us.ToString (), s); - Assert.Equal (r.ColumnWidth (), us.ConsoleWidth()); - Assert.Equal (s.Sum (c => ((Rune)c).ColumnWidth ()), us.ConsoleWidth()); - Assert.Equal (1, us.RuneCount()); // Here returns 1 because is a valid surrogate pair resulting in only rune >=U+10000..U+10FFFF + Assert.Equal (r.ToString (), us); + Assert.Equal (us, s); + Assert.Equal (r.ColumnWidth (), us.ConsoleWidth ()); + Assert.Equal (s.ConsoleWidth (), us.ConsoleWidth ()); + Assert.Equal (1, us.RuneCount ()); // Here returns 1 because is a valid surrogate pair resulting in only rune >=U+10000..U+10FFFF Assert.Equal (2, s.Length); // String always preserves the originals values of each surrogate pair } } @@ -635,17 +653,17 @@ namespace Terminal.Gui.TextTests { Rune r9b = (Rune)0x02009b; Assert.Equal (2, r0.ColumnWidth ()); - Assert.Equal (2, r7.ColumnWidth()); - Assert.Equal (2, r1b.ColumnWidth()); - Assert.Equal (2, r9b.ColumnWidth()); + Assert.Equal (2, r7.ColumnWidth ()); + Assert.Equal (2, r1b.ColumnWidth ()); + Assert.Equal (2, r9b.ColumnWidth ()); - "𐨁".DecodeSurrogatePair (out char [] chars); + "𠀀".DecodeSurrogatePair (out char [] chars); var rtl = new Rune (chars [0], chars [1]); - var rtlp = new Rune ('\ud802', '\ude01'); - var s = "\U00010a01"; + var rtlp = new Rune ('\ud840', '\udc00'); + var s = "\U00020000"; - Assert.Equal (2, rtl.ColumnWidth()); - Assert.Equal (2, rtlp.ColumnWidth()); + Assert.Equal (2, rtl.ColumnWidth ()); + Assert.Equal (2, rtlp.ColumnWidth ()); Assert.Equal (2, s.Length); } @@ -662,45 +680,47 @@ namespace Terminal.Gui.TextTests { int v = int.Parse (hex, System.Globalization.NumberStyles.HexNumber); string s = char.ConvertFromUtf32 (v); - if (!r.IsSurrogatePair()) { + if (!r.IsSurrogatePair ()) { Assert.Equal (r.ToString (), us); Assert.Equal (us, s); - Assert.Equal (r.ColumnWidth (), us.ConsoleWidth()); - Assert.Equal (us.RuneCount(), s.Length); // For not surrogate pairs string.RuneCount is always equal to String.Length + Assert.Equal (r.ColumnWidth (), us.ConsoleWidth ()); + Assert.Equal (us.RuneCount (), s.Length); // For not surrogate pairs string.RuneCount is always equal to String.Length } else { Assert.Equal (r.ToString (), us); Assert.Equal (us, s); - Assert.Equal (r.ColumnWidth (), us.ConsoleWidth()); - Assert.Equal (1, us.RuneCount()); // Here returns 1 because is a valid surrogate pair resulting in only rune >=U+10000..U+10FFFF + Assert.Equal (r.ColumnWidth (), us.ConsoleWidth ()); + Assert.Equal (1, us.RuneCount ()); // Here returns 1 because is a valid surrogate pair resulting in only rune >=U+10000..U+10FFFF Assert.Equal (2, s.Length); // String always preserves the originals values of each surrogate pair } - Assert.Equal (s.Sum (c => ((Rune)c).ColumnWidth ()), us.ConsoleWidth()); + Assert.Equal (s.ConsoleWidth (), us.ConsoleWidth ()); } } [Fact] public void Test_IsSurrogate () { - Rune r = (Rune)'\ue0fd'; - Assert.False (r.IsSurrogate()); - Assert.False (char.IsSurrogate (r.ToString (), 0)); - r = (Rune)0x927C0; - Assert.False (r.IsSurrogate()); - Assert.False (char.IsSurrogate (r.ToString (), 0)); - - r = (Rune)'\ud800'; - Assert.True (r.IsSurrogate()); + char c = '\ue0fd'; + Assert.False (char.IsSurrogate (c.ToString (), 0)); + Rune r = (Rune)0x927C0; + Assert.True (r.IsSurrogatePair ()); + Assert.True (r.IsSurrogatePair ()); Assert.True (char.IsSurrogate (r.ToString (), 0)); - r = (Rune)'\udfff'; - Assert.True (r.IsSurrogate()); - Assert.True (char.IsSurrogate(r.ToString(), 0)); + Assert.True (char.IsSurrogate (r.ToString (), 1)); + Assert.True (char.IsSurrogatePair (r.ToString (), 0)); + + c = '\ud800'; + Assert.True (char.IsSurrogate (c.ToString (), 0)); + c = '\udfff'; + Assert.True (char.IsSurrogate (c.ToString (), 0)); } [Fact] public void Test_EncodeSurrogatePair () { Assert.False (RuneExtensions.EncodeSurrogatePair (unchecked((char)0x40D7C0), (char)0xDC20, out Rune rune)); - Assert.False (RuneExtensions.EncodeSurrogatePair ((char)0x0065, (char)0x0301, out _)); + Assert.Equal (0, rune.Value); + Assert.False (RuneExtensions.EncodeSurrogatePair ((char)0x0065, (char)0x0301, out rune)); + Assert.Equal (0, rune.Value); Assert.True (RuneExtensions.EncodeSurrogatePair ('\ud83c', '\udf56', out rune)); Assert.Equal (0x1F356, rune.Value); Assert.Equal ("🍖", rune.ToString ()); @@ -732,38 +752,21 @@ namespace Terminal.Gui.TextTests { Assert.True (v >= 0x10000 && v <= RuneExtensions.MaxRune.Value); Assert.Equal (r.ToString (), us); Assert.Equal (us, s); - Assert.Equal (r.ColumnWidth (), us.ConsoleWidth()); - Assert.Equal (s.Sum (c => ((Rune)c).ColumnWidth ()), us.ConsoleWidth()); - Assert.Equal (1, us.RuneCount()); // Here returns 1 because is a valid surrogate pair resulting in only rune >=U+10000..U+10FFFF + Assert.Equal (r.ColumnWidth (), us.ConsoleWidth ()); + Assert.Equal (s.ConsoleWidth (), us.ConsoleWidth ()); + Assert.Equal (1, us.RuneCount ()); // Here returns 1 because is a valid surrogate pair resulting in only rune >=U+10000..U+10FFFF Assert.Equal (2, s.Length); // String always preserves the originals values of each surrogate pair } } } - //[Fact] - //public void Test_ExpectedSizeFromFirstByte () - //{ - // Assert.Equal (-1, Rune.ExpectedSizeFromFirstByte (255)); - // Assert.Equal (1, Rune.ExpectedSizeFromFirstByte (127)); - // Assert.Equal (4, Rune.ExpectedSizeFromFirstByte (240)); - //} - - [Fact] - public void Test_FullRune_Extension () - { - string us = "Hello, 世界"; - //Assert.True (us.FullRune ()); - us = $"Hello, {StringExtensions.Make (new byte [] { 228 })}界"; - //Assert.False (us.FullRune ()); - } - [Fact] public void Test_DecodeRune_Extension () { string us = "Hello, 世界"; List runes = new List (); int tSize = 0; - for (int i = 0; i < us.RuneCount(); i++) { + for (int i = 0; i < us.RuneCount (); i++) { (Rune rune, int size) = us.Substring (i, 1).DecodeRune (); runes.Add (rune); tSize += size; @@ -779,7 +782,7 @@ namespace Terminal.Gui.TextTests { string us = "Hello, 世界"; List runes = new List (); int tSize = 0; - for (int i = us.RuneCount() - 1; i >= 0; i--) { + for (int i = us.RuneCount () - 1; i >= 0; i--) { (Rune rune, int size) = us.Substring (i, 1).DecodeLastRune (); runes.Add (rune); tSize += size; @@ -789,37 +792,17 @@ namespace Terminal.Gui.TextTests { Assert.Equal (13, tSize); } - //[Fact] - //public void Test_InvalidIndex_Extension () - //{ - // string us = "Hello, 世界"; - // Assert.Equal (-1, us.InvalidIndex ()); - // us = string.Make (new byte [] { 0xff, 0xfe, 0xfd }); - // Assert.Equal (0, us.InvalidIndex ()); - //} - [Fact] public void Test_Valid_Extension () { string us = "Hello, 世界"; - Assert.True (RuneExtensions.IsValid (us.ToByteArray())); + Assert.True (RuneExtensions.IsValid (us.ToByteArray ())); us = StringExtensions.Make (new byte [] { 0xff, 0xfe, 0xfd }); - Assert.False (RuneExtensions.IsValid(us.ToByteArray())); + Assert.False (RuneExtensions.IsValid (us.ToByteArray ())); } - //[Fact] - //public void Test_ExpectedSizeFromFirstByte_Extension () - //{ - // string us = StringExtensions.Make (255); - // Assert.Equal (-1, us.ExpectedSizeFromFirstByte ()); - // us = StringExtensions.Make (127); - // Assert.Equal (1, us.ExpectedSizeFromFirstByte ()); - // us = StringExtensions.Make (240); - // Assert.Equal (4, us.ExpectedSizeFromFirstByte ()); - //} - [Fact] - public void Equals_Tests () + public void Equals_ToRuneList () { var a = new List> () { "First line.".ToRuneList () }; var b = new List> () { "First line.".ToRuneList (), "Second line.".ToRuneList () }; @@ -866,7 +849,7 @@ namespace Terminal.Gui.TextTests { int sumConsoleWidth = 0; for (uint i = 0; i < 32; i++) { sumRuneWidth += ((Rune)i).ColumnWidth (); - sumConsoleWidth += StringExtensions.Make (i).ConsoleWidth(); + sumConsoleWidth += StringExtensions.Make (i).ConsoleWidth (); } Assert.Equal (-32, sumRuneWidth); @@ -878,33 +861,139 @@ namespace Terminal.Gui.TextTests { { string us = "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; Assert.Equal (200, us.Length); - Assert.Equal (200, us.RuneCount()); - Assert.Equal (200, us.ConsoleWidth()); - int sumRuneWidth = us.Sum (x => ((Rune)x).ColumnWidth ()); + Assert.Equal (200, us.RuneCount ()); + Assert.Equal (200, us.ConsoleWidth ()); + 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.Sum (x => ((Rune)x).ColumnWidth ()); + Assert.Equal (201, us.RuneCount ()); + Assert.Equal (200, us.ConsoleWidth ()); + sumRuneWidth = us.EnumerateRunes().Sum(x => x.ColumnWidth()); Assert.Equal (199, sumRuneWidth); } [Fact] public void Rune_IsHighSurrogate_IsLowSurrogate () { - Rune r = (Rune)'\ud800'; - Assert.True (r.IsHighSurrogate()); + char c = '\ud800'; + Assert.True (char.IsHighSurrogate (c)); - r = (Rune)'\udbff'; - Assert.True (r.IsHighSurrogate()); + c = '\udbff'; + Assert.True (char.IsHighSurrogate (c)); - r = (Rune)'\udc00'; - Assert.True (r.IsLowSurrogate()); + c = '\udc00'; + Assert.True (char.IsLowSurrogate (c)); - r = (Rune)'\udfff'; - Assert.True (r.IsLowSurrogate()); + c = '\udfff'; + Assert.True (char.IsLowSurrogate (c)); + } + + [Fact] + public void Rune_ToRunes () + { + var str = "First line."; + var runes = str.ToRunes (); + for (int i = 0; i < runes.Length; i++) { + Assert.Equal (str [i], runes [i].Value); + } + } + + [Fact] + public void System_Rune_ColumnWidth () + { + var r = new Rune ('a'); + Assert.Equal (1, r.ColumnWidth ()); + Assert.Equal (1, r.ToString ().ConsoleWidth ()); + Assert.Equal (1, r.ToString ().Length); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (1, r.Utf8SequenceLength); + + r = new Rune ('b'); + Assert.Equal (1, r.ColumnWidth ()); + Assert.Equal (1, r.ToString ().ConsoleWidth ()); + Assert.Equal (1, r.ToString ().Length); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (1, r.Utf8SequenceLength); + + r = new Rune (123); + Assert.Equal (1, r.ColumnWidth ()); + Assert.Equal (1, r.ToString ().ConsoleWidth ()); + Assert.Equal (1, r.ToString ().Length); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (1, r.Utf8SequenceLength); + + r = new Rune ('\u1150'); + Assert.Equal (2, r.ColumnWidth ()); // 0x1150 ᅐ Unicode Technical Report #11 + Assert.Equal (2, r.ToString ().ConsoleWidth ()); + Assert.Equal (1, r.ToString ().Length); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (3, r.Utf8SequenceLength); + + r = new Rune ('\u1161'); + Assert.Equal (0, r.ColumnWidth ()); // 0x1161 ᅡ column width of 0 + Assert.Equal (0, r.ToString ().ConsoleWidth ()); + Assert.Equal (1, r.ToString ().Length); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (3, r.Utf8SequenceLength); + + r = new Rune (31); + Assert.Equal (-1, r.ColumnWidth ()); // non printable character + Assert.Equal (0, r.ToString ().ConsoleWidth ());// ConsoleWidth only returns zero or greater than zero + Assert.Equal (1, r.ToString ().Length); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (1, r.Utf8SequenceLength); + + r = new Rune (127); + Assert.Equal (-1, r.ColumnWidth ()); // non printable character + Assert.Equal (0, r.ToString ().ConsoleWidth ()); + Assert.Equal (1, r.ToString ().Length); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (1, r.Utf8SequenceLength); + + r = new Rune (0x16fe0); + Assert.Equal (2, r.ColumnWidth ()); // non printable character + Assert.Equal (2, r.ToString ().ConsoleWidth ()); + Assert.Equal (2, r.ToString ().Length); + Assert.Equal (2, r.Utf16SequenceLength); + Assert.Equal (4, r.Utf8SequenceLength); + } + + [Fact] + public void System_Text_Rune () + { + var r = new System.Text.Rune ('a'); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (1, r.Utf8SequenceLength); + + r = new System.Text.Rune ('b'); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (1, r.Utf8SequenceLength); + + r = new System.Text.Rune (123); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (1, r.Utf8SequenceLength); + + r = new System.Text.Rune ('\u1150'); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (3, r.Utf8SequenceLength); // 0x1150 ᅐ Unicode Technical Report #11 + + r = new System.Text.Rune ('\u1161'); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (3, r.Utf8SequenceLength); // 0x1161 ᅡ column width of 0 + + r = new System.Text.Rune (31); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (1, r.Utf8SequenceLength); // non printable character + + r = new System.Text.Rune (127); + Assert.Equal (1, r.Utf16SequenceLength); + Assert.Equal (1, r.Utf8SequenceLength); // non printable character + + r = new System.Text.Rune (0x16fe0); + Assert.Equal (2, r.Utf16SequenceLength); + Assert.Equal (4, r.Utf8SequenceLength); } } } diff --git a/UnitTests/Text/TextFormatterTests.cs b/UnitTests/Text/TextFormatterTests.cs index 55196749c..1964c2a25 100644 --- a/UnitTests/Text/TextFormatterTests.cs +++ b/UnitTests/Text/TextFormatterTests.cs @@ -1565,7 +1565,7 @@ namespace Terminal.Gui.TextTests { width = text.RuneCount () - 1; wrappedLines = TextFormatter.WordWrapText (text, width); Assert.Equal (2, wrappedLines.Count); - Assert.Equal (text[..(text.RuneCount () - 1)], wrappedLines [0]); + Assert.Equal (text [..(text.RuneCount () - 1)], wrappedLines [0]); Assert.Equal ("e", wrappedLines [1]); width = text.RuneCount () - 2; @@ -3524,70 +3524,6 @@ namespace Terminal.Gui.TextTests { Assert.Equal ("\u2460\u2461\u2462\u2463\u2464", list [1]); } - [Fact] - public void System_Rune_ColumnWidth () - { - var c = new Rune ('a'); - Assert.Equal (1, c.ColumnWidth ()); - Assert.Equal (1, c.ToString ().ConsoleWidth ()); - Assert.Equal (1, c.ToString ().Length); - - c = new Rune ('b'); - Assert.Equal (1, c.ColumnWidth ()); - Assert.Equal (1, c.ToString ().ConsoleWidth ()); - Assert.Equal (1, c.ToString ().Length); - - c = new Rune (123); - Assert.Equal (1, c.ColumnWidth ()); - Assert.Equal (1, c.ToString ().ConsoleWidth ()); - Assert.Equal (1, c.ToString ().Length); - - c = new Rune ('\u1150'); - Assert.Equal (2, c.ColumnWidth ()); // 0x1150 ᅐ Unicode Technical Report #11 - Assert.Equal (2, c.ToString ().ConsoleWidth ()); - Assert.Equal (3, c.ToString ().Length); - - c = new Rune ('\u1161'); - Assert.Equal (0, c.ColumnWidth ()); // 0x1161 ᅡ column width of 0 - Assert.Equal (0, c.ToString ().ConsoleWidth ()); - Assert.Equal (3, c.ToString ().Length); - - c = new Rune (31); - Assert.Equal (-1, c.ColumnWidth ()); // non printable character - Assert.Equal (0, c.ToString ().ConsoleWidth ());// ConsoleWidth only returns zero or greater than zero - Assert.Equal (1, c.ToString ().Length); - - c = new Rune (127); - Assert.Equal (-1, c.ColumnWidth ()); // non printable character - Assert.Equal (0, c.ToString ().ConsoleWidth ()); - Assert.Equal (1, c.ToString ().Length); - } - - [Fact] - public void System_Text_Rune () - { - var c = new System.Text.Rune ('a'); - Assert.Equal (1, c.Utf8SequenceLength); - - c = new System.Text.Rune ('b'); - Assert.Equal (1, c.Utf8SequenceLength); - - c = new System.Text.Rune (123); - Assert.Equal (1, c.Utf8SequenceLength); - - c = new System.Text.Rune ('\u1150'); - Assert.Equal (3, c.Utf8SequenceLength); // 0x1150 ᅐ Unicode Technical Report #11 - - c = new System.Text.Rune ('\u1161'); - Assert.Equal (3, c.Utf8SequenceLength); // 0x1161 ᅡ column width of 0 - - c = new System.Text.Rune (31); - Assert.Equal (1, c.Utf8SequenceLength); // non printable character - - c = new System.Text.Rune (127); - Assert.Equal (1, c.Utf8SequenceLength); // non printable character - } - [Fact] public void Format_WordWrap_PreserveTrailingSpaces () { @@ -3877,29 +3813,27 @@ namespace Terminal.Gui.TextTests { } [Fact] - public void Ustring_Array_Is_Not_Equal_ToRunes_Array_And_String_Array () + public void String_Array_Is_Not_Always_Equal_ToRunes_Array () { - var text = "New Test 你"; - string us = text; - string s = text; - Assert.Equal (10, us.RuneCount ()); - Assert.Equal (10, s.Length); - // The reason is string index is related to byte length and not rune length - Assert.Equal (12, us.Length); - Assert.NotEqual (20320, us [9]); - Assert.Equal (20320, s [9]); - Assert.Equal (228, us [9]); - Assert.Equal ("ä", us [9].ToString ()); - Assert.Equal ("你", s [9].ToString ()); - - // Rune array is equal to string array - var usToRunes = us.ToRunes (); + string s = "New Test 你"; + // Rune array length is equal to string array + var usToRunes = s.ToRunes (); Assert.Equal (10, usToRunes.Length); Assert.Equal (10, s.Length); Assert.Equal (20320, usToRunes [9].Value); Assert.Equal (20320, s [9]); Assert.Equal ("你", usToRunes [9].ToString ()); Assert.Equal ("你", s [9].ToString ()); + + s = "New Test \U0001d539"; + // Rune array length isn't equal to string array + usToRunes = s.ToRunes (); + Assert.Equal (10, usToRunes.Length); + Assert.Equal (11, s.Length); + Assert.Equal (120121, usToRunes [9].Value); + Assert.Equal (55349, s [9]); + Assert.Equal ("𝔹", usToRunes [9].ToString ()); + Assert.Equal ("𝔹", new string (new char [] { s [9], s [10] })); } } } \ No newline at end of file diff --git a/UnitTests/Views/TableViewTests.cs b/UnitTests/Views/TableViewTests.cs index 070ee5685..6a83f3993 100644 --- a/UnitTests/Views/TableViewTests.cs +++ b/UnitTests/Views/TableViewTests.cs @@ -156,13 +156,13 @@ namespace Terminal.Gui.ViewsTests { [Fact] public void Test_SumColumnWidth_UnicodeLength () { - Assert.Equal (11, "hello there".Sum (c => ((Rune)c).ColumnWidth ())); + Assert.Equal (11, "hello there".EnumerateRunes ().Sum (c => c.ColumnWidth ())); // Creates a string with the peculiar (french?) r symbol String surrogate = "Les Mise" + Char.ConvertFromUtf32 (Int32.Parse ("0301", NumberStyles.HexNumber)) + "rables"; // The unicode width of this string is shorter than the string length! - Assert.Equal (14, surrogate.Sum (c => ((Rune)c).ColumnWidth ())); + Assert.Equal (14, surrogate.EnumerateRunes ().Sum (c => c.ColumnWidth ())); Assert.Equal (15, surrogate.Length); } diff --git a/UnitTests/Views/TextFieldTests.cs b/UnitTests/Views/TextFieldTests.cs index d317ed238..4b8fb5c79 100644 --- a/UnitTests/Views/TextFieldTests.cs +++ b/UnitTests/Views/TextFieldTests.cs @@ -94,9 +94,9 @@ namespace Terminal.Gui.ViewsTests { { _textField.SelectedStart = 19; _textField.CursorPosition = 12; - Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between text fields.", _textField.Text); _textField.ProcessKey (new KeyEvent ((Key)0x75, new KeyModifiers ())); // u - Assert.Equal ("TAB to jump u text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump u text fields.", _textField.Text); } [Fact] @@ -610,13 +610,13 @@ namespace Terminal.Gui.ViewsTests { _textField.CursorPosition = 24; _textField.Copy (); Assert.Equal ("text", _textField.SelectedText); - Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between text fields.", _textField.Text); _textField.Paste (); - Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between text fields.", _textField.Text); _textField.SelectedStart = 20; _textField.Cut (); _textField.Paste (); - Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between text fields.", _textField.Text); } [Fact] @@ -627,17 +627,17 @@ namespace Terminal.Gui.ViewsTests { _textField.CursorPosition = 24; _textField.Copy (); Assert.Equal ("text", _textField.SelectedText); - Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between text fields.", _textField.Text); _textField.SelectedStart = -1; _textField.Paste (); - Assert.Equal ("TAB to jump between texttext fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between texttext fields.", _textField.Text); _textField.SelectedStart = 24; _textField.Cut (); Assert.Null (_textField.SelectedText); - Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between text fields.", _textField.Text); _textField.SelectedStart = -1; _textField.Paste (); - Assert.Equal ("TAB to jump between texttext fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between texttext fields.", _textField.Text); } [Fact] @@ -684,10 +684,10 @@ namespace Terminal.Gui.ViewsTests { }; _textField.Text = "changing"; - Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between text fields.", _textField.Text); cancel = false; _textField.Text = "changing"; - Assert.Equal ("changing", _textField.Text.ToString ()); + Assert.Equal ("changing", _textField.Text); } [Fact] @@ -699,7 +699,7 @@ namespace Terminal.Gui.ViewsTests { }; _textField.Text = "changed"; - Assert.Equal ("changed", _textField.Text.ToString ()); + Assert.Equal ("changed", _textField.Text); } [Fact] @@ -707,15 +707,15 @@ namespace Terminal.Gui.ViewsTests { public void Used_Is_True_By_Default () { _textField.CursorPosition = 10; - Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between text fields.", _textField.Text); _textField.ProcessKey (new KeyEvent ((Key)0x75, new KeyModifiers ())); // u - Assert.Equal ("TAB to jumup between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jumup between text fields.", _textField.Text); _textField.ProcessKey (new KeyEvent ((Key)0x73, new KeyModifiers ())); // s - Assert.Equal ("TAB to jumusp between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jumusp between text fields.", _textField.Text); _textField.ProcessKey (new KeyEvent ((Key)0x65, new KeyModifiers ())); // e - Assert.Equal ("TAB to jumusep between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jumusep between text fields.", _textField.Text); _textField.ProcessKey (new KeyEvent ((Key)0x64, new KeyModifiers ())); // d - Assert.Equal ("TAB to jumusedp between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jumusedp between text fields.", _textField.Text); } [Fact] @@ -724,15 +724,15 @@ namespace Terminal.Gui.ViewsTests { { _textField.Used = false; _textField.CursorPosition = 10; - Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between text fields.", _textField.Text); _textField.ProcessKey (new KeyEvent ((Key)0x75, new KeyModifiers ())); // u - Assert.Equal ("TAB to jumu between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jumu between text fields.", _textField.Text); _textField.ProcessKey (new KeyEvent ((Key)0x73, new KeyModifiers ())); // s - Assert.Equal ("TAB to jumusbetween text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jumusbetween text fields.", _textField.Text); _textField.ProcessKey (new KeyEvent ((Key)0x65, new KeyModifiers ())); // e - Assert.Equal ("TAB to jumuseetween text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jumuseetween text fields.", _textField.Text); _textField.ProcessKey (new KeyEvent ((Key)0x64, new KeyModifiers ())); // d - Assert.Equal ("TAB to jumusedtween text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jumusedtween text fields.", _textField.Text); } [Fact] @@ -740,22 +740,22 @@ namespace Terminal.Gui.ViewsTests { { var tf = new TextField ("ABC"); tf.EnsureFocus (); - Assert.Equal ("ABC", tf.Text.ToString ()); + Assert.Equal ("ABC", tf.Text); Assert.Equal (3, tf.CursorPosition); // now delete the C tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())); - Assert.Equal ("AB", tf.Text.ToString ()); + Assert.Equal ("AB", tf.Text); Assert.Equal (2, tf.CursorPosition); // then delete the B tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())); - Assert.Equal ("A", tf.Text.ToString ()); + Assert.Equal ("A", tf.Text); Assert.Equal (1, tf.CursorPosition); // then delete the A tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())); - Assert.Equal ("", tf.Text.ToString ()); + Assert.Equal ("", tf.Text); Assert.Equal (0, tf.CursorPosition); } @@ -765,24 +765,24 @@ namespace Terminal.Gui.ViewsTests { var tf = new TextField ("ABC"); tf.EnsureFocus (); tf.CursorPosition = 2; - Assert.Equal ("ABC", tf.Text.ToString ()); + Assert.Equal ("ABC", tf.Text); // now delete the B tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())); - Assert.Equal ("AC", tf.Text.ToString ()); + Assert.Equal ("AC", tf.Text); // then delete the A tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())); - Assert.Equal ("C", tf.Text.ToString ()); + Assert.Equal ("C", tf.Text); // then delete nothing tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())); - Assert.Equal ("C", tf.Text.ToString ()); + Assert.Equal ("C", tf.Text); // now delete the C tf.CursorPosition = 1; tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())); - Assert.Equal ("", tf.Text.ToString ()); + Assert.Equal ("", tf.Text); } [Fact] @@ -791,19 +791,19 @@ namespace Terminal.Gui.ViewsTests { var tf = new TextField (); tf.EnsureFocus (); tf.ProcessKey (new KeyEvent (Key.A, new KeyModifiers ())); - Assert.Equal ("A", tf.Text.ToString ()); + Assert.Equal ("A", tf.Text); // cancel the next keystroke tf.TextChanging += (s, e) => e.Cancel = e.NewText == "AB"; tf.ProcessKey (new KeyEvent (Key.B, new KeyModifiers ())); // B was canceled so should just be A - Assert.Equal ("A", tf.Text.ToString ()); + Assert.Equal ("A", tf.Text); // now delete the A tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())); - Assert.Equal ("", tf.Text.ToString ()); + Assert.Equal ("", tf.Text); } [Fact] @@ -811,11 +811,11 @@ namespace Terminal.Gui.ViewsTests { public void Text_Replaces_Tabs_With_Empty_String () { _textField.Text = "\t\tTAB to jump between text fields."; - Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between text fields.", _textField.Text); _textField.Text = ""; Clipboard.Contents = "\t\tTAB to jump between text fields."; _textField.Paste (); - Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ()); + Assert.Equal ("TAB to jump between text fields.", _textField.Text); } [Fact] @@ -923,201 +923,201 @@ namespace Terminal.Gui.ViewsTests { Assert.False (tf.ReadOnly); Assert.True (tf.ProcessKey (new KeyEvent (Key.DeleteChar, new KeyModifiers ()))); - Assert.Equal ("This is a test.", tf.Text.ToString ()); + Assert.Equal ("This is a test.", tf.Text); tf.CursorPosition = 0; Assert.True (tf.ProcessKey (new KeyEvent (Key.DeleteChar, new KeyModifiers ()))); - Assert.Equal ("his is a test.", tf.Text.ToString ()); + Assert.Equal ("his is a test.", tf.Text); tf.ReadOnly = true; Assert.True (tf.ProcessKey (new KeyEvent (Key.D | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("his is a test.", tf.Text.ToString ()); + Assert.Equal ("his is a test.", tf.Text); Assert.True (tf.ProcessKey (new KeyEvent (Key.Delete, new KeyModifiers ()))); - Assert.Equal ("his is a test.", tf.Text.ToString ()); + Assert.Equal ("his is a test.", tf.Text); tf.ReadOnly = false; tf.CursorPosition = 1; Assert.True (tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); tf.CursorPosition = 5; Assert.True (tf.ProcessKey (new KeyEvent (Key.Home | Key.ShiftMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal ("is is", tf.SelectedText); tf.CursorPosition = 5; tf.SelectedStart = -1; Assert.Null (tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.Home | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal ("is is", tf.SelectedText); tf.CursorPosition = 5; tf.SelectedStart = -1; Assert.Null (tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.A | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal ("is is", tf.SelectedText); tf.CursorPosition = 5; tf.SelectedStart = -1; Assert.Null (tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.End | Key.ShiftMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal (" a test.", tf.SelectedText); tf.CursorPosition = 5; tf.SelectedStart = -1; Assert.Null (tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.End | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal (" a test.", tf.SelectedText); tf.CursorPosition = 5; tf.SelectedStart = -1; Assert.Null (tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.E | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal (" a test.", tf.SelectedText); tf.CursorPosition = 5; tf.SelectedStart = -1; Assert.Null (tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.Home, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal (0, tf.CursorPosition); tf.CursorPosition = 5; Assert.Null (tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.Home | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal (0, tf.CursorPosition); tf.CursorPosition = 5; Assert.Null (tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.A | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal (0, tf.CursorPosition); tf.CursorPosition = 5; tf.SelectedStart = -1; Assert.Null (tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft | Key.ShiftMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal ("s", tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorUp | Key.ShiftMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal ("is", tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorRight | Key.ShiftMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal ("s", tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorDown | Key.ShiftMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Null (tf.SelectedText); tf.CursorPosition = 7; tf.SelectedStart = -1; Assert.Null (tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal ("a", tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorUp | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal ("is a", tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent ((Key)((int)'B' + Key.ShiftMask | Key.AltMask), new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal ("is is a", tf.SelectedText); tf.CursorPosition = 3; tf.SelectedStart = -1; Assert.Null (tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorRight | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal ("is ", tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorDown | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal ("is a ", tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent ((Key)((int)'F' + Key.ShiftMask | Key.AltMask), new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal ("is a test.", tf.SelectedText); Assert.Equal (13, tf.CursorPosition); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Null (tf.SelectedText); Assert.Equal (12, tf.CursorPosition); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal (11, tf.CursorPosition); Assert.True (tf.ProcessKey (new KeyEvent (Key.End, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal (13, tf.CursorPosition); tf.CursorPosition = 0; Assert.True (tf.ProcessKey (new KeyEvent (Key.End | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal (13, tf.CursorPosition); tf.CursorPosition = 0; Assert.True (tf.ProcessKey (new KeyEvent (Key.E | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal (13, tf.CursorPosition); tf.CursorPosition = 0; Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal (1, tf.CursorPosition); Assert.True (tf.ProcessKey (new KeyEvent (Key.F | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.Equal (2, tf.CursorPosition); tf.CursorPosition = 9; tf.ReadOnly = true; Assert.True (tf.ProcessKey (new KeyEvent (Key.K | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); tf.ReadOnly = false; Assert.True (tf.ProcessKey (new KeyEvent (Key.K | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a t", tf.Text.ToString ()); - Assert.Equal ("est.", Clipboard.Contents.ToString ()); + Assert.Equal ("is is a t", tf.Text); + Assert.Equal ("est.", Clipboard.Contents); Assert.True (tf.ProcessKey (new KeyEvent (Key.Z | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.True (tf.ProcessKey (new KeyEvent (Key.Y | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a t", tf.Text.ToString ()); + Assert.Equal ("is is a t", tf.Text); Assert.True (tf.ProcessKey (new KeyEvent (Key.Backspace | Key.AltMask, new KeyModifiers ()))); - Assert.Equal ("is is a test.", tf.Text.ToString ()); + Assert.Equal ("is is a test.", tf.Text); Assert.True (tf.ProcessKey (new KeyEvent (Key.Y | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a t", tf.Text.ToString ()); + Assert.Equal ("is is a t", tf.Text); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a t", tf.Text.ToString ()); + Assert.Equal ("is is a t", tf.Text); Assert.Equal (8, tf.CursorPosition); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorUp | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a t", tf.Text.ToString ()); + Assert.Equal ("is is a t", tf.Text); Assert.Equal (6, tf.CursorPosition); Assert.True (tf.ProcessKey (new KeyEvent ((Key)((int)'B' + Key.AltMask), new KeyModifiers ()))); - Assert.Equal ("is is a t", tf.Text.ToString ()); + Assert.Equal ("is is a t", tf.Text); Assert.Equal (3, tf.CursorPosition); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorRight | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a t", tf.Text.ToString ()); + Assert.Equal ("is is a t", tf.Text); Assert.Equal (6, tf.CursorPosition); Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorDown | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a t", tf.Text.ToString ()); + Assert.Equal ("is is a t", tf.Text); Assert.Equal (8, tf.CursorPosition); Assert.True (tf.ProcessKey (new KeyEvent ((Key)((int)'F' + Key.AltMask), new KeyModifiers ()))); - Assert.Equal ("is is a t", tf.Text.ToString ()); + Assert.Equal ("is is a t", tf.Text); Assert.Equal (9, tf.CursorPosition); Assert.True (tf.Used); Assert.True (tf.ProcessKey (new KeyEvent (Key.InsertChar, new KeyModifiers ()))); - Assert.Equal ("is is a t", tf.Text.ToString ()); + Assert.Equal ("is is a t", tf.Text); Assert.Equal (9, tf.CursorPosition); Assert.False (tf.Used); tf.SelectedStart = 3; tf.CursorPosition = 7; Assert.Equal ("is a", tf.SelectedText); - Assert.Equal ("est.", Clipboard.Contents.ToString ()); + Assert.Equal ("est.", Clipboard.Contents); Assert.True (tf.ProcessKey (new KeyEvent (Key.C | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a t", tf.Text.ToString ()); - Assert.Equal ("is a", Clipboard.Contents.ToString ()); + Assert.Equal ("is is a t", tf.Text); + Assert.Equal ("is a", Clipboard.Contents); Assert.True (tf.ProcessKey (new KeyEvent (Key.X | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is t", tf.Text.ToString ()); - Assert.Equal ("is a", Clipboard.Contents.ToString ()); + Assert.Equal ("is t", tf.Text); + Assert.Equal ("is a", Clipboard.Contents); Assert.True (tf.ProcessKey (new KeyEvent (Key.V | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("is is a t", tf.Text.ToString ()); - Assert.Equal ("is a", Clipboard.Contents.ToString ()); + Assert.Equal ("is is a t", tf.Text); + Assert.Equal ("is a", Clipboard.Contents); Assert.Equal (7, tf.CursorPosition); Assert.True (tf.ProcessKey (new KeyEvent (Key.K | Key.AltMask, new KeyModifiers ()))); - Assert.Equal (" t", tf.Text.ToString ()); - Assert.Equal ("is is a", Clipboard.Contents.ToString ()); + Assert.Equal (" t", tf.Text); + Assert.Equal ("is is a", Clipboard.Contents); tf.Text = "TAB to jump between text fields."; Assert.Equal (0, tf.CursorPosition); Assert.True (tf.ProcessKey (new KeyEvent (Key.DeleteChar | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("to jump between text fields.", tf.Text.ToString ()); + Assert.Equal ("to jump between text fields.", tf.Text); tf.CursorPosition = tf.Text.Length; Assert.True (tf.ProcessKey (new KeyEvent (Key.Backspace | Key.CtrlMask, new KeyModifiers ()))); - Assert.Equal ("to jump between text fields", tf.Text.ToString ()); + Assert.Equal ("to jump between text fields", tf.Text); Assert.True (tf.ProcessKey (new KeyEvent (Key.T | Key.CtrlMask, new KeyModifiers ()))); Assert.Equal ("to jump between text fields", tf.SelectedText); Assert.True (tf.ProcessKey (new KeyEvent (Key.D | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()))); - Assert.Equal ("", tf.Text.ToString ()); + Assert.Equal ("", tf.Text); } [Fact] @@ -1150,13 +1150,13 @@ namespace Terminal.Gui.ViewsTests { var oldText = ""; var tf = new TextField () { Width = 10, Text = "-1" }; - tf.TextChanging += (s, e) => newText = e.NewText.ToString (); - tf.TextChanged += (s, e) => oldText = e.OldValue.ToString (); + tf.TextChanging += (s, e) => newText = e.NewText; + tf.TextChanged += (s, e) => oldText = e.OldValue; Application.Top.Add (tf); Application.Begin (Application.Top); - Assert.Equal ("-1", tf.Text.ToString ()); + Assert.Equal ("-1", tf.Text); // InsertText tf.SelectedStart = 1; @@ -1166,7 +1166,7 @@ namespace Terminal.Gui.ViewsTests { Assert.True (tf.ProcessKey (new KeyEvent (Key.D2, new KeyModifiers ()))); Assert.Equal ("-2", newText); Assert.Equal ("-1", oldText); - Assert.Equal ("-2", tf.Text.ToString ()); + Assert.Equal ("-2", tf.Text); // DeleteCharLeft tf.SelectedStart = 1; @@ -1176,7 +1176,7 @@ namespace Terminal.Gui.ViewsTests { Assert.True (tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()))); Assert.Equal ("-", newText); Assert.Equal ("-2", oldText); - Assert.Equal ("-", tf.Text.ToString ()); + Assert.Equal ("-", tf.Text); // DeleteCharRight tf.Text = "-1"; @@ -1187,7 +1187,7 @@ namespace Terminal.Gui.ViewsTests { Assert.True (tf.ProcessKey (new KeyEvent (Key.DeleteChar, new KeyModifiers ()))); Assert.Equal ("-", newText); Assert.Equal ("-1", oldText); - Assert.Equal ("-", tf.Text.ToString ()); + Assert.Equal ("-", tf.Text); // Cut tf.Text = "-1"; @@ -1198,7 +1198,7 @@ namespace Terminal.Gui.ViewsTests { Assert.True (tf.ProcessKey (new KeyEvent (Key.X | Key.CtrlMask, new KeyModifiers ()))); Assert.Equal ("-", newText); Assert.Equal ("-1", oldText); - Assert.Equal ("-", tf.Text.ToString ()); + Assert.Equal ("-", tf.Text); // Delete word with accented char tf.Text = "Les Misérables movie."; @@ -1213,7 +1213,7 @@ namespace Terminal.Gui.ViewsTests { Assert.True (tf.ProcessKey (new KeyEvent (Key.Delete, new KeyModifiers ()))); Assert.Equal ("Les movie.", newText); Assert.Equal ("Les Misérables movie.", oldText); - Assert.Equal ("Les movie.", tf.Text.ToString ()); + Assert.Equal ("Les movie.", tf.Text); } [Fact] @@ -1228,17 +1228,17 @@ namespace Terminal.Gui.ViewsTests { Application.Begin (Application.Top); Application.Driver.SendKeys ('a', ConsoleKey.A, false, false, false); - Assert.Equal ("a", tf.Text.ToString ()); + Assert.Equal ("a", tf.Text); // SuppressKey suppresses the 'j' key Application.Driver.SendKeys ('j', ConsoleKey.A, false, false, false); - Assert.Equal ("a", tf.Text.ToString ()); + Assert.Equal ("a", tf.Text); Application.RootKeyEvent -= SuppressKey; // Now that the delegate has been removed we can type j again Application.Driver.SendKeys ('j', ConsoleKey.A, false, false, false); - Assert.Equal ("aj", tf.Text.ToString ()); + Assert.Equal ("aj", tf.Text); } [Fact] [AutoInitShutdown] @@ -1254,7 +1254,7 @@ namespace Terminal.Gui.ViewsTests { Application.Begin (Application.Top); var processMouseEventMethod = typeof (Application).GetMethod ("ProcessMouseEvent", BindingFlags.Static | BindingFlags.NonPublic) - ?? throw new Exception ("Expected private method not found 'ProcessMouseEvent', this method was used for testing mouse behaviours"); + ?? throw new Exception ("Expected private method not found 'ProcessMouseEvent', this method was used for testing mouse behaviours"); var mouseEvent = new MouseEvent { Flags = MouseFlags.Button1Clicked, @@ -1372,7 +1372,7 @@ namespace Terminal.Gui.ViewsTests { var runes = tf.Text.ToRuneList (); Assert.Equal (21, runes.Count); - Assert.Equal (22, tf.Text.Length); + Assert.Equal (21, tf.Text.Length); for (int i = 0; i < runes.Count; i++) { var cs = text [i]; @@ -1503,7 +1503,7 @@ Les Miśerables", output); var caption = "Mise" + Char.ConvertFromUtf32 (Int32.Parse ("0301", NumberStyles.HexNumber)) + "rables"; Assert.Equal (11, caption.Length); - Assert.Equal (10, caption.Sum (c => ((Rune)c).ColumnWidth ())); + Assert.Equal (10, caption.EnumerateRunes ().Sum (c => c.ColumnWidth ())); var tf = GetTextFieldsInView (); diff --git a/UnitTests/Views/TextViewTests.cs b/UnitTests/Views/TextViewTests.cs index d6e9d3a93..ef9d22ba1 100644 --- a/UnitTests/Views/TextViewTests.cs +++ b/UnitTests/Views/TextViewTests.cs @@ -32,10 +32,7 @@ namespace Terminal.Gui.ViewsTests { // 1 2 3 // 01234567890123456789012345678901=32 (Length) - var buff = new byte [txt.Length]; - for (int i = 0; i < txt.Length; i++) { - buff [i] = (byte)txt [i]; - } + var buff = Encoding.Unicode.GetBytes(txt); var ms = new System.IO.MemoryStream (buff).ToArray (); _textView = new TextView () { Width = 30, Height = 10 }; _textView.Text = Encoding.Unicode.GetString (ms);