diff --git a/Directory.Packages.props b/Directory.Packages.props index d62a1d2982..2fdb4633e7 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -18,7 +18,7 @@ - + diff --git a/Examples/UICatalog/Scenarios/CombiningMarks.cs b/Examples/UICatalog/Scenarios/CombiningMarks.cs index 7d8437a230..c1bd73ecf2 100644 --- a/Examples/UICatalog/Scenarios/CombiningMarks.cs +++ b/Examples/UICatalog/Scenarios/CombiningMarks.cs @@ -16,7 +16,8 @@ public override void Main () Application.Top!.SetNeedsDraw (); var i = -1; - top.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616."); + top.Move (0, ++i); + top.AddStr ("Terminal.Gui supports all combining sequences that can be rendered as an unique grapheme."); top.Move (0, ++i); top.AddStr ("\u0301<- \"\\u0301\" using AddStr."); top.Move (0, ++i); @@ -38,7 +39,7 @@ public override void Main () top.AddRune ('\u0301'); top.AddRune ('\u0328'); top.AddRune (']'); - top.AddStr ("<- \"[a\\u0301\\u0301\\u0328]\" using AddRune for each."); + top.AddStr ("<- \"[a\\u0301\\u0301\\u0328]\" using AddRune for each. Avoid use AddRune for combining sequences because may result with empty blocks at end."); top.Move (0, ++i); top.AddStr ("[a\u0301\u0301\u0328]<- \"[a\\u0301\\u0301\\u0328]\" using AddStr."); top.Move (0, ++i); @@ -82,6 +83,16 @@ public override void Main () top.AddStr ("[\U0001F468\U0001F469\U0001F9D2]<- \"[\\U0001F468\\U0001F469\\U0001F9D2]\" using AddStr."); top.Move (0, ++i); top.AddStr ("[\U0001F468\u200D\U0001F469\u200D\U0001F9D2]<- \"[\\U0001F468\\u200D\\U0001F469\\u200D\\U0001F9D2]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466]<- \"[\\U0001F468\\u200D\\U0001F469\\u200D\\U0001F467\\u200D\\U0001F466]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\u0e32\u0e33]<- \"[\\u0e32\\u0e33]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\U0001F469\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468]<- \"[\\U0001F469\\u200D\\u2764\\uFE0F\\u200D\\U0001F48B\\u200D\\U0001F468]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\u0061\uFE20\u0065\uFE21]<- \"[\\u0061\\uFE20\\u0065\\uFE21]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\u1100\uD7B0]<- \"[\\u1100\\uD7B0]\" using AddStr."); }; Application.Run (top); diff --git a/Examples/UICatalog/Scenarios/LineDrawing.cs b/Examples/UICatalog/Scenarios/LineDrawing.cs index cbc8dd27bb..217aea27b1 100644 --- a/Examples/UICatalog/Scenarios/LineDrawing.cs +++ b/Examples/UICatalog/Scenarios/LineDrawing.cs @@ -284,7 +284,7 @@ protected override bool OnDrawingContent () SetCurrentAttribute (c.Value.Value.Attribute ?? GetAttributeForRole (VisualRole.Normal)); // TODO: #2616 - Support combining sequences that don't normalize - AddRune (c.Key.X, c.Key.Y, c.Value.Value.Rune); + AddStr (c.Key.X, c.Key.Y, c.Value.Value.Grapheme); } } } diff --git a/Examples/UICatalog/Scenarios/Sliders.cs b/Examples/UICatalog/Scenarios/Sliders.cs index fae50c015d..8d954d1005 100644 --- a/Examples/UICatalog/Scenarios/Sliders.cs +++ b/Examples/UICatalog/Scenarios/Sliders.cs @@ -86,17 +86,17 @@ public void MakeSliders (View v, List options) { if (single.Orientation == Orientation.Horizontal) { - single.Style.SpaceChar = new () { Rune = Glyphs.HLine }; - single.Style.OptionChar = new () { Rune = Glyphs.HLine }; + single.Style.SpaceChar = new () { Grapheme = Glyphs.HLine.ToString () }; + single.Style.OptionChar = new () { Grapheme = Glyphs.HLine.ToString () }; } else { - single.Style.SpaceChar = new () { Rune = Glyphs.VLine }; - single.Style.OptionChar = new () { Rune = Glyphs.VLine }; + single.Style.SpaceChar = new () { Grapheme = Glyphs.VLine.ToString () }; + single.Style.OptionChar = new () { Grapheme = Glyphs.VLine.ToString () }; } }; - single.Style.SetChar = new () { Rune = Glyphs.ContinuousMeterSegment }; - single.Style.DragChar = new () { Rune = Glyphs.ContinuousMeterSegment }; + single.Style.SetChar = new () { Grapheme = Glyphs.ContinuousMeterSegment.ToString () }; + single.Style.DragChar = new () { Grapheme = Glyphs.ContinuousMeterSegment.ToString () }; v.Add (single); @@ -257,7 +257,7 @@ public override void Main () { s.Orientation = Orientation.Horizontal; - s.Style.SpaceChar = new () { Rune = Glyphs.HLine }; + s.Style.SpaceChar = new () { Grapheme = Glyphs.HLine.ToString () }; if (prev == null) { @@ -275,7 +275,7 @@ public override void Main () { s.Orientation = Orientation.Vertical; - s.Style.SpaceChar = new () { Rune = Glyphs.VLine }; + s.Style.SpaceChar = new () { Grapheme = Glyphs.VLine.ToString () }; if (prev == null) { diff --git a/Examples/UICatalog/Scenarios/SyntaxHighlighting.cs b/Examples/UICatalog/Scenarios/SyntaxHighlighting.cs index 7b0c054628..ad9f934605 100644 --- a/Examples/UICatalog/Scenarios/SyntaxHighlighting.cs +++ b/Examples/UICatalog/Scenarios/SyntaxHighlighting.cs @@ -152,12 +152,12 @@ public override void Main () ), null, new ( - "_Load Rune Cells", + "_Load Text Cells", "", () => ApplyLoadCells () ), new ( - "_Save Rune Cells", + "_Save Text Cells", "", () => SaveCells () ), @@ -240,12 +240,9 @@ private void ApplyLoadCells () { string csName = color.Key; - foreach (Rune rune in csName.EnumerateRunes ()) - { - cells.Add (new () { Rune = rune, Attribute = color.Value.Normal }); - } + cells.AddRange (Cell.ToCellList (csName, color.Value.Normal)); - cells.Add (new () { Rune = (Rune)'\n', Attribute = color.Value.Focus }); + cells.Add (new () { Grapheme = "\n", Attribute = color.Value.Focus }); } if (File.Exists (_path)) diff --git a/Terminal.Gui/App/Application.cs b/Terminal.Gui/App/Application.cs index bd3ccf7a3f..92730e7118 100644 --- a/Terminal.Gui/App/Application.cs +++ b/Terminal.Gui/App/Application.cs @@ -89,26 +89,14 @@ public static string ToString (IDriver? driver) { for (var c = 0; c < driver.Cols; c++) { - Rune rune = contents [r, c].Rune; + string text = contents [r, c].Grapheme; - if (rune.DecodeSurrogatePair (out char []? sp)) - { - sb.Append (sp); - } - else - { - sb.Append ((char)rune.Value); - } + sb.Append (text); - if (rune.GetColumns () > 1) + if (text.GetColumns () > 1) { c++; } - - // See Issue #2616 - //foreach (var combMark in contents [r, c].CombiningMarks) { - // sb.Append ((char)combMark.Value); - //} } sb.AppendLine (); diff --git a/Terminal.Gui/Drawing/Cell.cs b/Terminal.Gui/Drawing/Cell.cs index e72a7837ee..ff5610551b 100644 --- a/Terminal.Gui/Drawing/Cell.cs +++ b/Terminal.Gui/Drawing/Cell.cs @@ -1,81 +1,114 @@ #nullable enable - namespace Terminal.Gui.Drawing; /// /// Represents a single row/column in a Terminal.Gui rendering surface (e.g. and /// ). /// -public record struct Cell (Attribute? Attribute = null, bool IsDirty = false, Rune Rune = default) +public record struct Cell (Attribute? Attribute = null, bool IsDirty = false, string Grapheme = "") { /// The attributes to use when drawing the Glyph. public Attribute? Attribute { get; set; } = Attribute; /// - /// Gets or sets a value indicating whether this has been modified since the + /// Gets or sets a value indicating whether this has been modified since the /// last time it was drawn. /// public bool IsDirty { get; set; } = IsDirty; - private Rune _rune = Rune; + private string _grapheme = Grapheme; - /// The character to display. If is , then is ignored. - public Rune Rune + /// + /// The single grapheme cluster to display from this cell. If is or + /// , then is ignored. + /// + public string Grapheme { - get => _rune; + readonly get => _grapheme; set { - _combiningMarks?.Clear (); - _rune = value; - } - } + if (GraphemeHelper.GetGraphemes(value).ToArray().Length > 1) + { + throw new InvalidOperationException ($"Only a single {nameof (Grapheme)} cluster is allowed per Cell."); + } - private List? _combiningMarks; + if (!string.IsNullOrEmpty (value) && value.Length == 1 && char.IsSurrogate (value [0])) + { + throw new ArgumentException ($"Only valid Unicode scalar values are allowed in a single {nameof (Grapheme)} cluster."); + } - /// - /// The combining marks for that when combined makes this Cell a combining sequence. If - /// empty, then is ignored. - /// - /// - /// Only valid in the rare case where is a combining sequence that could not be normalized to a - /// single Rune. - /// - internal IReadOnlyList CombiningMarks - { - // PERFORMANCE: Downside of the interface return type is that List struct enumerator cannot be utilized, i.e. enumerator is allocated. - // If enumeration is used heavily in the future then might be better to expose the List Enumerator directly via separate mechanism. - get - { - // Avoid unnecessary list allocation. - if (_combiningMarks == null) + try { - return Array.Empty (); + if (!string.IsNullOrEmpty (value) && !value.IsNormalized (NormalizationForm.FormC)) + { + _grapheme = value.Normalize (NormalizationForm.FormC); + } + else + { + _grapheme = value; + } + } + catch (ArgumentException) + { + // leave text unnormalized + _grapheme = value; } - return _combiningMarks; } } /// - /// Adds combining mark to the cell. + /// The rune for or runes for that when combined makes this Cell a combining sequence. /// - /// The combining mark to add to the cell. - internal void AddCombiningMark (Rune combiningMark) + /// + /// In the case where has more than one rune it is a combining sequence that is normalized to a + /// single Text which may occupies 1 or 2 columns. + /// + public IReadOnlyList Runes => string.IsNullOrEmpty (Grapheme) ? [] : Grapheme.EnumerateRunes ().ToList (); + + /// + public override string ToString () { - _combiningMarks ??= []; - _combiningMarks.Add (combiningMark); + string visibleText = EscapeControlAndInvisible (Grapheme); + + return $"[\"{visibleText}\":{Attribute}]"; } - /// - /// Clears combining marks of the cell. - /// - internal void ClearCombiningMarks () + private static string EscapeControlAndInvisible (string text) { - _combiningMarks?.Clear (); - } + if (string.IsNullOrEmpty (text)) + { + return ""; + } - /// - public override string ToString () { return $"['{Rune}':{Attribute}]"; } + var sb = new StringBuilder (); + + foreach (var rune in text.EnumerateRunes ()) + { + switch (rune.Value) + { + case '\0': sb.Append ("␀"); break; + case '\t': sb.Append ("\\t"); break; + case '\r': sb.Append ("\\r"); break; + case '\n': sb.Append ("\\n"); break; + case '\f': sb.Append ("\\f"); break; + case '\v': sb.Append ("\\v"); break; + default: + if (char.IsControl ((char)rune.Value)) + { + // show as \uXXXX + sb.Append ($"\\u{rune.Value:X4}"); + } + else + { + sb.Append (rune.ToString ()); + } + break; + } + } + + return sb.ToString (); + } /// Converts the string into a . /// The string to convert. @@ -83,12 +116,8 @@ internal void ClearCombiningMarks () /// public static List ToCellList (string str, Attribute? attribute = null) { - List cells = new (); - - foreach (Rune rune in str.EnumerateRunes ()) - { - cells.Add (new () { Rune = rune, Attribute = attribute }); - } + List cells = []; + cells.AddRange (GraphemeHelper.GetGraphemes (str).Select (grapheme => new Cell { Grapheme = grapheme, Attribute = attribute })); return cells; } @@ -101,9 +130,7 @@ public static List ToCellList (string str, Attribute? attribute = null) /// A for each line. public static List> StringToLinesOfCells (string content, Attribute? attribute = null) { - List cells = content.EnumerateRunes () - .Select (x => new Cell { Rune = x, Attribute = attribute }) - .ToList (); + List cells = ToCellList (content, attribute); return SplitNewLines (cells); } @@ -113,14 +140,14 @@ public static List> StringToLinesOfCells (string content, Attribute? /// public static string ToString (IEnumerable cells) { - var str = string.Empty; + StringBuilder sb = new (); foreach (Cell cell in cells) { - str += cell.Rune.ToString (); + sb.Append (cell.Grapheme); } - return str; + return sb.ToString (); } /// Converts a generic collection into a string. @@ -148,26 +175,19 @@ public static string ToString (List> cellsList) internal static List StringToCells (string str, Attribute? attribute = null) { - List cells = []; - - foreach (Rune rune in str.ToRunes ()) - { - cells.Add (new () { Rune = rune, Attribute = attribute }); - } - - return cells; + return ToCellList (str, attribute); } - internal static List ToCells (IEnumerable runes, Attribute? attribute = null) + internal static List ToCells (IEnumerable strings, Attribute? attribute = null) { - List cells = new (); + StringBuilder sb = new (); - foreach (Rune rune in runes) + foreach (string str in strings) { - cells.Add (new () { Rune = rune, Attribute = attribute }); + sb.Append (str); } - return cells; + return ToCellList (sb.ToString (), attribute); } private static List> SplitNewLines (List cells) @@ -180,14 +200,15 @@ private static List> SplitNewLines (List cells) // ASCII code 10 = Line Feed. for (; i < cells.Count; i++) { - if (cells [i].Rune.Value == 13) + if (cells [i].Grapheme.Length == 1 && cells [i].Grapheme [0] == 13) { hasCR = true; continue; } - if (cells [i].Rune.Value == 10) + if ((cells [i].Grapheme.Length == 1 && cells [i].Grapheme [0] == 10) + || cells [i].Grapheme == "\r\n") { if (i - start > 0) { diff --git a/Terminal.Gui/Drawing/GraphemeHelper.cs b/Terminal.Gui/Drawing/GraphemeHelper.cs new file mode 100644 index 0000000000..4ae00148c7 --- /dev/null +++ b/Terminal.Gui/Drawing/GraphemeHelper.cs @@ -0,0 +1,49 @@ +using System.Globalization; + +namespace Terminal.Gui.Drawing; + +/// +/// Provides utility methods for enumerating Unicode grapheme clusters (user-perceived characters) +/// in a string. A grapheme cluster may consist of one or more values, +/// including combining marks or zero-width joiner (ZWJ) sequences such as emoji family groups. +/// +/// +/// +/// This helper uses to enumerate +/// text elements according to the Unicode Standard Annex #29 (UAX #29) rules for +/// extended grapheme clusters. +/// +/// +/// On legacy Windows consoles (e.g., cmd.exe, conhost.exe), complex grapheme +/// sequences such as ZWJ emoji or combining marks may not render correctly, even though +/// the underlying string data is valid. +/// +/// +/// For most accurate visual rendering, prefer modern terminals such as Windows Terminal +/// or Linux-based terminals with full Unicode and font support. +/// +/// +public static class GraphemeHelper +{ + /// + /// Enumerates extended grapheme clusters from a string. + /// Handles surrogate pairs, combining marks, and basic ZWJ sequences. + /// Safe for legacy consoles; memory representation is correct. + /// + public static IEnumerable GetGraphemes (string text) + { + if (string.IsNullOrEmpty (text)) + { + yield break; + } + + TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator (text); + + while (enumerator.MoveNext ()) + { + string element = enumerator.GetTextElement (); + + yield return element; + } + } +} diff --git a/Terminal.Gui/Drawing/LineCanvas/LineCanvas.cs b/Terminal.Gui/Drawing/LineCanvas/LineCanvas.cs index 637b61861e..80f87a8e92 100644 --- a/Terminal.Gui/Drawing/LineCanvas/LineCanvas.cs +++ b/Terminal.Gui/Drawing/LineCanvas/LineCanvas.cs @@ -174,7 +174,7 @@ public void Clear () intersectionsBufferList.Clear (); foreach (var line in _lines) { - if (line.Intersects (x, y) is IntersectionDefinition intersect) + if (line.Intersects (x, y) is { } intersect) { intersectionsBufferList.Add (intersect); } @@ -218,9 +218,8 @@ public Dictionary GetMap (Rectangle inArea) for (int x = inArea.X; x < inArea.X + inArea.Width; x++) { IntersectionDefinition [] intersects = _lines - // ! nulls are filtered out by the next Where filter - .Select (l => l.Intersects (x, y)!) - .Where (i => i is not null) + .Select (l => l.Intersects (x, y)) + .OfType () // automatically filters nulls and casts .ToArray (); Rune? rune = GetRuneForIntersects (Application.Driver, intersects); @@ -414,7 +413,7 @@ private void ConfigurationManager_Applied (object? sender, ConfigurationManagerE if (rune.HasValue) { - cell.Rune = rune.Value; + cell.Grapheme = rune.ToString ()!; } cell.Attribute = GetAttributeForIntersects (intersects); diff --git a/Terminal.Gui/Drivers/DriverImpl.cs b/Terminal.Gui/Drivers/DriverImpl.cs index db19184590..583615a240 100644 --- a/Terminal.Gui/Drivers/DriverImpl.cs +++ b/Terminal.Gui/Drivers/DriverImpl.cs @@ -332,8 +332,8 @@ public virtual string GetVersionInfo () /// public bool IsRuneSupported (Rune rune) { return Rune.IsValid (rune.Value); } - /// Tests whether the specified coordinate are valid for drawing the specified Rune. - /// Used to determine if one or two columns are required. + /// Tests whether the specified coordinate are valid for drawing the specified Text. + /// Used to determine if one or two columns are required. /// The column. /// The row. /// @@ -341,7 +341,7 @@ public virtual string GetVersionInfo () /// . /// otherwise. /// - public bool IsValidLocation (Rune rune, int col, int row) { return OutputBuffer.IsValidLocation (rune, col, row); } + public bool IsValidLocation (string text, int col, int row) { return OutputBuffer.IsValidLocation (text, col, row); } /// /// Updates and to the specified column and row in diff --git a/Terminal.Gui/Drivers/IDriver.cs b/Terminal.Gui/Drivers/IDriver.cs index 32af99b05e..93e0bf62d9 100644 --- a/Terminal.Gui/Drivers/IDriver.cs +++ b/Terminal.Gui/Drivers/IDriver.cs @@ -125,8 +125,8 @@ public interface IDriver /// bool IsRuneSupported (Rune rune); - /// Tests whether the specified coordinate are valid for drawing the specified Rune. - /// Used to determine if one or two columns are required. + /// Tests whether the specified coordinate are valid for drawing the specified Text. + /// Used to determine if one or two columns are required. /// The column. /// The row. /// @@ -134,7 +134,7 @@ public interface IDriver /// . /// otherwise. /// - bool IsValidLocation (Rune rune, int col, int row); + bool IsValidLocation (string text, int col, int row); /// /// Updates and to the specified column and row in diff --git a/Terminal.Gui/Drivers/IOutputBuffer.cs b/Terminal.Gui/Drivers/IOutputBuffer.cs index 2b8991593f..8e2deba2c4 100644 --- a/Terminal.Gui/Drivers/IOutputBuffer.cs +++ b/Terminal.Gui/Drivers/IOutputBuffer.cs @@ -85,15 +85,15 @@ public interface IOutputBuffer void FillRect (Rectangle rect, char rune); /// - /// Tests whether the specified coordinate is valid for drawing the specified Rune. + /// Tests whether the specified coordinate is valid for drawing the specified Text. /// - /// Used to determine if one or two columns are required. + /// Used to determine if one or two columns are required. /// The column. /// The row. /// - /// True if the coordinate is valid for the Rune; false otherwise. + /// True if the coordinate is valid for the Text; false otherwise. /// - bool IsValidLocation (Rune rune, int col, int row); + bool IsValidLocation (string text, int col, int row); /// /// The first cell index on left of screen - basically always 0. diff --git a/Terminal.Gui/Drivers/OutputBase.cs b/Terminal.Gui/Drivers/OutputBase.cs index ac43dc93d3..e210564a84 100644 --- a/Terminal.Gui/Drivers/OutputBase.cs +++ b/Terminal.Gui/Drivers/OutputBase.cs @@ -32,9 +32,6 @@ public virtual void Write (IOutputBuffer buffer) CursorVisibility? savedVisibility = _cachedCursorVisibility; SetCursorVisibility (CursorVisibility.Invisible); - const int MAX_CHARS_PER_RUNE = 2; - Span runeBuffer = stackalloc char [MAX_CHARS_PER_RUNE]; - for (int row = top; row < rows; row++) { if (!SetCursorPositionImpl (0, row)) @@ -94,28 +91,8 @@ public virtual void Write (IOutputBuffer buffer) outputWidth++; - // Avoid Rune.ToString() by appending the rune chars. - Rune rune = buffer.Contents [row, col].Rune; - int runeCharsWritten = rune.EncodeToUtf16 (runeBuffer); - ReadOnlySpan runeChars = runeBuffer [..runeCharsWritten]; - output.Append (runeChars); - - if (buffer.Contents [row, col].CombiningMarks.Count > 0) - { - // AtlasEngine does not support NON-NORMALIZED combining marks in a way - // compatible with the driver architecture. Any CMs (except in the first col) - // are correctly combined with the base char, but are ALSO treated as 1 column - // width codepoints E.g. `echo "[e`u{0301}`u{0301}]"` will output `[é ]`. - // - // For now, we just ignore the list of CMs. - //foreach (var combMark in Contents [row, col].CombiningMarks) { - // output.Append (combMark); - } - else if (rune.IsSurrogatePair () && rune.GetColumns () < 2) - { - WriteToConsole (output, ref lastCol, row, ref outputWidth); - SetCursorPositionImpl (col - 1, row); - } + string text = buffer.Contents [row, col].Grapheme; + output.Append (text); buffer.Contents [row, col].IsDirty = false; } diff --git a/Terminal.Gui/Drivers/OutputBufferImpl.cs b/Terminal.Gui/Drivers/OutputBufferImpl.cs index ee2493d602..ee573789b7 100644 --- a/Terminal.Gui/Drivers/OutputBufferImpl.cs +++ b/Terminal.Gui/Drivers/OutputBufferImpl.cs @@ -66,7 +66,9 @@ public int Cols /// The topmost row in the terminal. public virtual int Top { get; set; } = 0; - /// + /// + /// Indicates which lines have been modified and need to be redrawn. + /// public bool [] DirtyLines { get; set; } = []; // QUESTION: When non-full screen apps are supported, will this represent the app size, or will that be in Application? @@ -113,85 +115,50 @@ public Region? Clip /// will be added instead. /// /// - /// Rune to add. - public void AddRune (Rune rune) - { - int runeWidth = -1; - bool validLocation = IsValidLocation (rune, Col, Row); - - if (Contents is null) - { - return; - } - - Clip ??= new (Screen); + /// Text to add. + public void AddRune (Rune rune) { AddStr (rune.ToString ()); } - Rectangle clipRect = Clip!.GetBounds (); + /// + /// Adds the specified to the display at the current cursor position. This method is a + /// convenience method that calls with the constructor. + /// + /// Character to add. + public void AddRune (char c) { AddRune (new Rune (c)); } - if (validLocation) + /// Adds the to the display at the cursor position. + /// + /// + /// When the method returns, will be incremented by the number of columns + /// required, unless the new column value is outside the or screen + /// dimensions defined by . + /// + /// If requires more columns than are available, the output will be clipped. + /// + /// String. + public void AddStr (string str) + { + foreach (string grapheme in GraphemeHelper.GetGraphemes (str)) { - rune = rune.MakePrintable (); - runeWidth = rune.GetColumns (); + string text = grapheme; - lock (Contents) - { - if (runeWidth == 0 && rune.IsCombiningMark ()) - { - // AtlasEngine does not support NON-NORMALIZED combining marks in a way - // compatible with the driver architecture. Any CMs (except in the first col) - // are correctly combined with the base char, but are ALSO treated as 1 column - // width codepoints E.g. `echo "[e`u{0301}`u{0301}]"` will output `[é ]`. - // - // Until this is addressed (see Issue #), we do our best by - // a) Attempting to normalize any CM with the base char to it's left - // b) Ignoring any CMs that don't normalize - if (Col > 0) - { - if (Contents [Row, Col - 1].CombiningMarks.Count > 0) - { - // Just add this mark to the list - Contents [Row, Col - 1].AddCombiningMark (rune); - - // Ignore. Don't move to next column (let the driver figure out what to do). - } - else - { - // Attempt to normalize the cell to our left combined with this mark - string combined = Contents [Row, Col - 1].Rune + rune.ToString (); + int textWidth = -1; + bool validLocation = IsValidLocation (text, Col, Row); - // Normalize to Form C (Canonical Composition) - string normalized = combined.Normalize (NormalizationForm.FormC); + if (Contents is null) + { + return; + } - if (normalized.Length == 1) - { - // It normalized! We can just set the Cell to the left with the - // normalized codepoint - Contents [Row, Col - 1].Rune = (Rune)normalized [0]; + Clip ??= new (Screen); - // Ignore. Don't move to next column because we're already there - } - else - { - // It didn't normalize. Add it to the Cell to left's CM list - Contents [Row, Col - 1].AddCombiningMark (rune); + Rectangle clipRect = Clip!.GetBounds (); - // Ignore. Don't move to next column (let the driver figure out what to do). - } - } + if (validLocation) + { + text = text.MakePrintable (); + textWidth = text.GetColumns (); - Contents [Row, Col - 1].Attribute = CurrentAttribute; - Contents [Row, Col - 1].IsDirty = true; - } - else - { - // Most drivers will render a combining mark at col 0 as the mark - Contents [Row, Col].Rune = rune; - Contents [Row, Col].Attribute = CurrentAttribute; - Contents [Row, Col].IsDirty = true; - Col++; - } - } - else + lock (Contents) { Contents [Row, Col].Attribute = CurrentAttribute; Contents [Row, Col].IsDirty = true; @@ -199,49 +166,45 @@ public void AddRune (Rune rune) if (Col > 0) { // Check if cell to left has a wide glyph - if (Contents [Row, Col - 1].Rune.GetColumns () > 1) + if (Contents [Row, Col - 1].Grapheme.GetColumns () > 1) { // Invalidate cell to left - Contents [Row, Col - 1].Rune = Rune.ReplacementChar; + Contents [Row, Col - 1].Grapheme = Rune.ReplacementChar.ToString (); Contents [Row, Col - 1].IsDirty = true; } } - if (runeWidth < 1) - { - Contents [Row, Col].Rune = Rune.ReplacementChar; - } - else if (runeWidth == 1) + if (textWidth is 0 or 1) { - Contents [Row, Col].Rune = rune; + Contents [Row, Col].Grapheme = text; if (Col < clipRect.Right - 1) { Contents [Row, Col + 1].IsDirty = true; } } - else if (runeWidth == 2) + else if (textWidth == 2) { if (!Clip.Contains (Col + 1, Row)) { // We're at the right edge of the clip, so we can't display a wide character. // TODO: Figure out if it is better to show a replacement character or ' ' - Contents [Row, Col].Rune = Rune.ReplacementChar; + Contents [Row, Col].Grapheme = Rune.ReplacementChar.ToString (); } else if (!Clip.Contains (Col, Row)) { // Our 1st column is outside the clip, so we can't display a wide character. - Contents [Row, Col + 1].Rune = Rune.ReplacementChar; + Contents [Row, Col + 1].Grapheme = Rune.ReplacementChar.ToString (); } else { - Contents [Row, Col].Rune = rune; + Contents [Row, Col].Grapheme = text; if (Col < clipRect.Right - 1) { // Invalidate cell to right so that it doesn't get drawn // TODO: Figure out if it is better to show a replacement character or ' ' - Contents [Row, Col + 1].Rune = Rune.ReplacementChar; + Contents [Row, Col + 1].Grapheme = Rune.ReplacementChar.ToString (); Contents [Row, Col + 1].IsDirty = true; } } @@ -249,67 +212,37 @@ public void AddRune (Rune rune) else { // This is a non-spacing character, so we don't need to do anything - Contents [Row, Col].Rune = (Rune)' '; + Contents [Row, Col].Grapheme = " "; Contents [Row, Col].IsDirty = false; } DirtyLines [Row] = true; } } - } - if (runeWidth is < 0 or > 0) - { Col++; - } - if (runeWidth > 1) - { - Debug.Assert (runeWidth <= 2); - - if (validLocation && Col < clipRect.Right) + if (textWidth > 1) { - lock (Contents!) + Debug.Assert (textWidth <= 2); + + if (validLocation && Col < clipRect.Right) { - // This is a double-width character, and we are not at the end of the line. - // Col now points to the second column of the character. Ensure it doesn't - // Get rendered. - Contents [Row, Col].IsDirty = false; - Contents [Row, Col].Attribute = CurrentAttribute; + lock (Contents!) + { + // This is a double-width character, and we are not at the end of the line. + // Col now points to the second column of the character. Ensure it doesn't + // Get rendered. + Contents [Row, Col].IsDirty = false; + Contents [Row, Col].Attribute = CurrentAttribute; - // TODO: Determine if we should wipe this out (for now now) - //Contents [Row, Col].Rune = (Rune)' '; + // TODO: Determine if we should wipe this out (for now now) + //Contents [Row, Col].Text = (Text)' '; + } } - } - Col++; - } - } - - /// - /// Adds the specified to the display at the current cursor position. This method is a - /// convenience method that calls with the constructor. - /// - /// Character to add. - public void AddRune (char c) { AddRune (new Rune (c)); } - - /// Adds the to the display at the cursor position. - /// - /// - /// When the method returns, will be incremented by the number of columns - /// required, unless the new column value is outside of the or screen - /// dimensions defined by . - /// - /// If requires more columns than are available, the output will be clipped. - /// - /// String. - public void AddStr (string str) - { - List runes = str.EnumerateRunes ().ToList (); - - for (var i = 0; i < runes.Count; i++) - { - AddRune (runes [i]); + Col++; + } } } @@ -332,7 +265,7 @@ public void ClearContents () { Contents [row, c] = new () { - Rune = (Rune)' ', + Grapheme = " ", Attribute = new Attribute (Color.White, Color.Black), IsDirty = true }; @@ -346,22 +279,19 @@ public void ClearContents () //ClearedContents?.Invoke (this, EventArgs.Empty); } - /// Tests whether the specified coordinate are valid for drawing the specified Rune. - /// Used to determine if one or two columns are required. + /// Tests whether the specified coordinate are valid for drawing the specified Text. + /// Used to determine if one or two columns are required. /// The column. /// The row. /// /// if the coordinate is outside the screen bounds or outside of . /// otherwise. /// - public bool IsValidLocation (Rune rune, int col, int row) + public bool IsValidLocation (string text, int col, int row) { - if (rune.GetColumns () < 2) - { - return col >= 0 && row >= 0 && col < Cols && row < Rows && Clip!.Contains (col, row); - } + int textWidth = text.GetColumns (); - return Clip!.Contains (col, row) || Clip!.Contains (col + 1, row); + return col >= 0 && row >= 0 && col + textWidth <= Cols && row < Rows && Clip!.Contains (col, row); } /// @@ -384,14 +314,14 @@ public void FillRect (Rectangle rect, Rune rune) { for (int c = rect.X; c < rect.X + rect.Width; c++) { - if (!IsValidLocation (rune, c, r)) + if (!IsValidLocation (rune.ToString (), c, r)) { continue; } Contents [r, c] = new () { - Rune = rune != default (Rune) ? rune : (Rune)' ', + Grapheme = rune != default (Rune) ? rune.ToString () : " ", Attribute = CurrentAttribute, IsDirty = true }; } diff --git a/Terminal.Gui/Text/StringExtensions.cs b/Terminal.Gui/Text/StringExtensions.cs index e379cf3da6..b866d0f34f 100644 --- a/Terminal.Gui/Text/StringExtensions.cs +++ b/Terminal.Gui/Text/StringExtensions.cs @@ -55,8 +55,9 @@ public static (Rune Rune, int Size) DecodeRune (this string str, int start = 0, /// Gets the number of columns the string occupies in the terminal. /// This is a Terminal.Gui extension method to to support TUI text manipulation. /// The string to measure. + /// Indicates whether to ignore values ​​less than zero, such as control keys. /// - public static int GetColumns (this string str) + public static int GetColumns (this string str, bool ignoreLessThanZero = true) { if (string.IsNullOrEmpty (str)) { @@ -64,17 +65,31 @@ public static int GetColumns (this string str) } var total = 0; - TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator (str); - while (enumerator.MoveNext ()) + foreach (string grapheme in GraphemeHelper.GetGraphemes (str)) { - string element = enumerator.GetTextElement (); - // Get the maximum rune width within this grapheme cluster - int width = element - .EnumerateRunes () - .Max (r => Math.Max (r.GetColumns (), 0)); - total += width; + int clusterWidth = 0; + + foreach (var rune in grapheme.EnumerateRunes ()) + { + int width = rune.GetColumns (); + + if (ignoreLessThanZero && width < 0) + { + width = 0; + } + + clusterWidth += width; + } + + // Clamp to realistic max display width + if (clusterWidth > 2) + { + clusterWidth = 2; + } + + total += clusterWidth; } return total; @@ -95,7 +110,7 @@ public static int GetColumns (this string str) /// A indicating if all elements of the are ASCII digits ( /// ) or not ( /// - public static bool IsAllAsciiDigits (this ReadOnlySpan stringSpan) { return stringSpan.ToString ().All (char.IsAsciiDigit); } + public static bool IsAllAsciiDigits (this ReadOnlySpan stringSpan) { return !stringSpan.IsEmpty && stringSpan.ToString ().All (char.IsAsciiDigit); } /// /// Determines if this of is composed entirely of ASCII @@ -106,7 +121,7 @@ public static int GetColumns (this string str) /// A indicating if all elements of the are ASCII digits ( /// ) or not ( /// - public static bool IsAllAsciiHexDigits (this ReadOnlySpan stringSpan) { return stringSpan.ToString ().All (char.IsAsciiHexDigit); } + public static bool IsAllAsciiHexDigits (this ReadOnlySpan stringSpan) { return !stringSpan.IsEmpty && stringSpan.ToString ().All (char.IsAsciiHexDigit); } /// Repeats the string times. /// This is a Terminal.Gui extension method to to support TUI text manipulation. @@ -207,4 +222,60 @@ public static string ToString (IEnumerable bytes, Encoding? encoding = nul return encoding.GetString (bytes.ToArray ()); } + + /// Converts a generic collection into a string. + /// The enumerable string to convert. + /// + public static string ToString (IEnumerable strings) { return string.Concat (strings); } + + /// Converts the string into a . + /// This is a Terminal.Gui extension method to to support TUI text manipulation. + /// The string to convert. + /// + public static List ToStringList (this string str) + { + List strings = []; + + foreach (string grapheme in GraphemeHelper.GetGraphemes (str)) + { + strings.Add (grapheme); + } + + return strings; + } + + /// Reports whether a string is a surrogate code point. + /// This is a Terminal.Gui extension method to to support TUI text manipulation. + /// The string to probe. + /// if the string is a surrogate code point; otherwise. + public static bool IsSurrogatePair (this string str) + { + if (str.Length != 2) + { + return false; + } + + Rune rune = Rune.GetRuneAt (str, 0); + + return rune.IsSurrogatePair (); + } + + /// + /// Ensures the text is not a control character and can be displayed by translating characters below 0x20 to + /// equivalent, printable, Unicode chars. + /// + /// This is a Terminal.Gui extension method to to support TUI text manipulation. + /// The text. + /// + public static string MakePrintable (this string str) + { + if (str.Length > 1) + { + return str; + } + + char ch = str [0]; + + return char.IsControl (ch) ? new ((char)(ch + 0x2400), 1) : str; + } } diff --git a/Terminal.Gui/Text/TextFormatter.cs b/Terminal.Gui/Text/TextFormatter.cs index 70636c018b..532f348008 100644 --- a/Terminal.Gui/Text/TextFormatter.cs +++ b/Terminal.Gui/Text/TextFormatter.cs @@ -126,9 +126,10 @@ public void Draw ( break; } - Rune [] runes = linesFormatted [line].ToRunes (); + string strings = linesFormatted [line]; + string[] graphemes = GraphemeHelper.GetGraphemes (strings).ToArray (); - // When text is justified, we lost left or right, so we use the direction to align. + // When text is justified, we lost left or right, so we use the direction to align. int x = 0, y = 0; @@ -143,7 +144,7 @@ public void Draw ( } else { - int runesWidth = StringExtensions.ToString (runes).GetColumns (); + int runesWidth = strings.GetColumns (); x = screen.Right - runesWidth; CursorPosition = screen.Width - runesWidth + (_hotKeyPos > -1 ? _hotKeyPos : 0); } @@ -199,7 +200,7 @@ public void Draw ( } else { - int runesWidth = StringExtensions.ToString (runes).GetColumns (); + int runesWidth = strings.GetColumns (); x = screen.Left + (screen.Width - runesWidth) / 2; CursorPosition = (screen.Width - runesWidth) / 2 + (_hotKeyPos > -1 ? _hotKeyPos : 0); @@ -217,7 +218,7 @@ public void Draw ( { if (isVertical) { - y = screen.Bottom - runes.Length; + y = screen.Bottom - graphemes.Length; } else { @@ -253,7 +254,7 @@ public void Draw ( { if (isVertical) { - int s = (screen.Height - runes.Length) / 2; + int s = (screen.Height - graphemes.Length) / 2; y = screen.Top + s; } else @@ -274,14 +275,14 @@ public void Draw ( int size = isVertical ? screen.Height : screen.Width; int current = start + colOffset; List lastZeroWidthPos = null!; - Rune rune = default; - int zeroLengthCount = isVertical ? runes.Sum (r => r.GetColumns () == 0 ? 1 : 0) : 0; + string text = default; + int zeroLengthCount = isVertical ? strings.EnumerateRunes ().Sum (r => r.GetColumns () == 0 ? 1 : 0) : 0; for (int idx = (isVertical ? start - y : start - x) + colOffset; current < start + size + zeroLengthCount; idx++) { - Rune lastRuneUsed = rune; + string lastTextUsed = text; if (lastZeroWidthPos is null) { @@ -295,17 +296,17 @@ public void Draw ( continue; } - if (!FillRemaining && idx > runes.Length - 1) + if (!FillRemaining && idx > graphemes.Length - 1) { break; } if ((!isVertical && (current - start > maxScreen.Left + maxScreen.Width - screen.X + colOffset - || (idx < runes.Length && runes [idx].GetColumns () > screen.Width))) + || (idx < graphemes.Length && graphemes [idx].GetColumns () > screen.Width))) || (isVertical && ((current > start + size + zeroLengthCount && idx > maxScreen.Top + maxScreen.Height - screen.Y) - || (idx < runes.Length && runes [idx].GetColumns () > screen.Width)))) + || (idx < graphemes.Length && graphemes [idx].GetColumns () > screen.Width)))) { break; } @@ -316,13 +317,13 @@ public void Draw ( // break; - rune = (Rune)' '; + text = " "; if (isVertical) { - if (idx >= 0 && idx < runes.Length) + if (idx >= 0 && idx < graphemes.Length) { - rune = runes [idx]; + text = graphemes [idx]; } if (lastZeroWidthPos is null) @@ -338,7 +339,7 @@ public void Draw ( if (foundIdx > -1) { - if (rune.IsCombiningMark ()) + if (Rune.GetRuneAt (text, 0).IsCombiningMark ()) { lastZeroWidthPos [foundIdx] = new Point ( @@ -351,7 +352,7 @@ public void Draw ( current ); } - else if (!rune.IsCombiningMark () && lastRuneUsed.IsCombiningMark ()) + else if (!Rune.GetRuneAt (text, 0).IsCombiningMark () && Rune.GetRuneAt (lastTextUsed, 0).IsCombiningMark ()) { current++; driver?.Move (x, current); @@ -371,13 +372,13 @@ public void Draw ( { driver?.Move (current, y); - if (idx >= 0 && idx < runes.Length) + if (idx >= 0 && idx < graphemes.Length) { - rune = runes [idx]; + text = graphemes [idx]; } } - int runeWidth = GetRuneWidth (rune, TabWidth); + int runeWidth = GetTextWidth (text, TabWidth); if (HotKeyPos > -1 && idx == HotKeyPos) { @@ -387,7 +388,7 @@ public void Draw ( } driver?.SetAttribute (hotColor); - driver?.AddRune (rune); + driver?.AddStr (text); driver?.SetAttribute (normalColor); } else @@ -416,7 +417,7 @@ public void Draw ( } } - driver?.AddRune (rune); + driver?.AddStr (text); } if (isVertical) @@ -431,11 +432,11 @@ public void Draw ( current += runeWidth; } - int nextRuneWidth = idx + 1 > -1 && idx + 1 < runes.Length - ? runes [idx + 1].GetColumns () + int nextRuneWidth = idx + 1 > -1 && idx + 1 < graphemes.Length + ? graphemes [idx + 1].GetColumns () : 0; - if (!isVertical && idx + 1 < runes.Length && current + nextRuneWidth > start + size) + if (!isVertical && idx + 1 < graphemes.Length && current + nextRuneWidth > start + size) { break; } @@ -933,9 +934,10 @@ public Region GetDrawRegion (Rectangle screen, Rectangle maximum = default) break; } - Rune [] runes = linesFormatted [line].ToRunes (); + string strings = linesFormatted [line]; + string [] graphemes = GraphemeHelper.GetGraphemes (strings).ToArray (); - // When text is justified, we lost left or right, so we use the direction to align. + // When text is justified, we lost left or right, so we use the direction to align. int x = 0, y = 0; switch (Alignment) @@ -950,17 +952,17 @@ public Region GetDrawRegion (Rectangle screen, Rectangle maximum = default) } case Alignment.End: { - int runesWidth = StringExtensions.ToString (runes).GetColumns (); - x = screen.Right - runesWidth; + int stringsWidth = strings.GetColumns (); + x = screen.Right - stringsWidth; break; } case Alignment.Start when isVertical: { - int runesWidth = line > 0 - ? GetColumnsRequiredForVerticalText (linesFormatted, 0, line, TabWidth) - : 0; - x = screen.Left + runesWidth; + int stringsWidth = line > 0 + ? GetColumnsRequiredForVerticalText (linesFormatted, 0, line, TabWidth) + : 0; + x = screen.Left + stringsWidth; break; } @@ -970,7 +972,7 @@ public Region GetDrawRegion (Rectangle screen, Rectangle maximum = default) break; case Alignment.Fill when isVertical: { - int runesWidth = GetColumnsRequiredForVerticalText (linesFormatted, 0, linesFormatted.Count, TabWidth); + int stringsWidth = GetColumnsRequiredForVerticalText (linesFormatted, 0, linesFormatted.Count, TabWidth); int prevLineWidth = line > 0 ? GetColumnsRequiredForVerticalText (linesFormatted, line - 1, 1, TabWidth) : 0; int firstLineWidth = GetColumnsRequiredForVerticalText (linesFormatted, 0, 1, TabWidth); int lastLineWidth = GetColumnsRequiredForVerticalText (linesFormatted, linesFormatted.Count - 1, 1, TabWidth); @@ -979,7 +981,7 @@ public Region GetDrawRegion (Rectangle screen, Rectangle maximum = default) x = line == 0 ? screen.Left : line < linesFormatted.Count - 1 - ? screen.Width - runesWidth <= lastLineWidth ? screen.Left + prevLineWidth : screen.Left + line * interval + ? screen.Width - stringsWidth <= lastLineWidth ? screen.Left + prevLineWidth : screen.Left + line * interval : screen.Right - lastLineWidth; break; @@ -990,16 +992,16 @@ public Region GetDrawRegion (Rectangle screen, Rectangle maximum = default) break; case Alignment.Center when isVertical: { - int runesWidth = GetColumnsRequiredForVerticalText (linesFormatted, 0, linesFormatted.Count, TabWidth); + int stringsWidth = GetColumnsRequiredForVerticalText (linesFormatted, 0, linesFormatted.Count, TabWidth); int linesWidth = GetColumnsRequiredForVerticalText (linesFormatted, 0, line, TabWidth); - x = screen.Left + linesWidth + (screen.Width - runesWidth) / 2; + x = screen.Left + linesWidth + (screen.Width - stringsWidth) / 2; break; } case Alignment.Center: { - int runesWidth = StringExtensions.ToString (runes).GetColumns (); - x = screen.Left + (screen.Width - runesWidth) / 2; + int stringsWidth = strings.GetColumns (); + x = screen.Left + (screen.Width - stringsWidth) / 2; break; } @@ -1013,7 +1015,7 @@ public Region GetDrawRegion (Rectangle screen, Rectangle maximum = default) { // Vertical Alignment case Alignment.End when isVertical: - y = screen.Bottom - runes.Length; + y = screen.Bottom - graphemes.Length; break; case Alignment.End: @@ -1043,7 +1045,7 @@ public Region GetDrawRegion (Rectangle screen, Rectangle maximum = default) } case Alignment.Center when isVertical: { - int s = (screen.Height - runes.Length) / 2; + int s = (screen.Height - graphemes.Length) / 2; y = screen.Top + s; break; @@ -1065,7 +1067,7 @@ public Region GetDrawRegion (Rectangle screen, Rectangle maximum = default) int start = isVertical ? screen.Top : screen.Left; int size = isVertical ? screen.Height : screen.Width; int current = start + colOffset; - int zeroLengthCount = isVertical ? runes.Sum (r => r.GetColumns () == 0 ? 1 : 0) : 0; + int zeroLengthCount = isVertical ? strings.EnumerateRunes ().Sum (r => r.GetColumns () == 0 ? 1 : 0) : 0; int lineX = x, lineY = y, lineWidth = 0, lineHeight = 1; @@ -1083,23 +1085,23 @@ public Region GetDrawRegion (Rectangle screen, Rectangle maximum = default) continue; } - if (!FillRemaining && idx > runes.Length - 1) + if (!FillRemaining && idx > graphemes.Length - 1) { break; } if ((!isVertical && (current - start > maxScreen.Left + maxScreen.Width - screen.X + colOffset - || (idx < runes.Length && runes [idx].GetColumns () > screen.Width))) + || (idx < graphemes.Length && graphemes [idx].GetColumns () > screen.Width))) || (isVertical && ((current > start + size + zeroLengthCount && idx > maxScreen.Top + maxScreen.Height - screen.Y) - || (idx < runes.Length && runes [idx].GetColumns () > screen.Width)))) + || (idx < graphemes.Length && graphemes [idx].GetColumns () > screen.Width)))) { break; } - Rune rune = idx >= 0 && idx < runes.Length ? runes [idx] : (Rune)' '; - int runeWidth = GetRuneWidth (rune, TabWidth); + string text = idx >= 0 && idx < graphemes.Length ? graphemes [idx] : " "; + int runeWidth = GetStringWidth (text, TabWidth); if (isVertical) { @@ -1118,11 +1120,11 @@ public Region GetDrawRegion (Rectangle screen, Rectangle maximum = default) current += isVertical && runeWidth > 0 ? 1 : runeWidth; - int nextRuneWidth = idx + 1 > -1 && idx + 1 < runes.Length - ? runes [idx + 1].GetColumns () + int nextStringWidth = idx + 1 > -1 && idx + 1 < graphemes.Length + ? graphemes [idx + 1].GetColumns () : 0; - if (!isVertical && idx + 1 < runes.Length && current + nextRuneWidth > start + size) + if (!isVertical && idx + 1 < graphemes.Length && current + nextStringWidth > start + size) { break; } @@ -1335,33 +1337,34 @@ private static string ReplaceTABWithSpaces (string str, int tabWidth) /// A list of text without the newline characters. public static List SplitNewLine (string text) { - List runes = text.ToRuneList (); + List graphemes = GraphemeHelper.GetGraphemes (text).ToList (); List lines = new (); var start = 0; - for (var i = 0; i < runes.Count; i++) + for (var i = 0; i < graphemes.Count; i++) { int end = i; - switch (runes [i].Value) + switch (graphemes [i]) { - case '\n': - lines.Add (StringExtensions.ToString (runes.GetRange (start, end - start))); + case "\n": + case "\r\n": + lines.Add (StringExtensions.ToString (graphemes.GetRange (start, end - start))); i++; start = i; break; - case '\r': - if (i + 1 < runes.Count && runes [i + 1].Value == '\n') + case "\r": + if (i + 1 < graphemes.Count && graphemes [i + 1] == "\n") { - lines.Add (StringExtensions.ToString (runes.GetRange (start, end - start))); + lines.Add (StringExtensions.ToString (graphemes.GetRange (start, end - start))); i += 2; start = i; } else { - lines.Add (StringExtensions.ToString (runes.GetRange (start, end - start))); + lines.Add (StringExtensions.ToString (graphemes.GetRange (start, end - start))); i++; start = i; } @@ -1370,14 +1373,14 @@ public static List SplitNewLine (string text) } } - switch (runes.Count) + switch (graphemes.Count) { case > 0 when lines.Count == 0: - lines.Add (StringExtensions.ToString (runes)); + lines.Add (StringExtensions.ToString (graphemes)); break; - case > 0 when start < runes.Count: - lines.Add (StringExtensions.ToString (runes.GetRange (start, runes.Count - start))); + case > 0 when start < graphemes.Count: + lines.Add (StringExtensions.ToString (graphemes.GetRange (start, graphemes.Count - start))); break; default: @@ -1405,16 +1408,19 @@ public static string ClipOrPad (string text, int width) } // if value is not wide enough - if (text.EnumerateRunes ().Sum (c => c.GetColumns ()) < width) + string [] graphemes = GraphemeHelper.GetGraphemes (text).ToArray (); + int totalColumns = graphemes.Sum (s => s.GetColumns ()); + + if (totalColumns < width) { // pad it out with spaces to the given Alignment - int toPad = width - text.EnumerateRunes ().Sum (c => c.GetColumns ()); + int toPad = width - totalColumns; return text + new string (' ', toPad); } // value is too wide - return new (text.TakeWhile (c => (width -= ((Rune)c).GetColumns ()) >= 0).ToArray ()); + return string.Concat (graphemes.TakeWhile (t => (width -= t.GetColumns ()) >= 0)); } /// Formats the provided text to fit within the width provided using word wrapping. @@ -1455,18 +1461,18 @@ public static List WordWrapText ( return lines; } - List runes = StripCRLF (text).ToRuneList (); + List graphemes = GraphemeHelper.GetGraphemes (StripCRLF (text)).ToList (); int start = Math.Max ( - !runes.Contains ((Rune)' ') && textFormatter is { VerticalAlignment: Alignment.End } && IsVerticalDirection (textDirection) - ? runes.Count - width + !graphemes.Contains (" ") && textFormatter is { VerticalAlignment: Alignment.End } && IsVerticalDirection (textDirection) + ? graphemes.Count - width : 0, 0); int end; if (preserveTrailingSpaces) { - while ((end = start) < runes.Count) + while ((end = start) < graphemes.Count) { end = GetNextWhiteSpace (start, width, out bool incomplete); @@ -1477,7 +1483,7 @@ public static List WordWrapText ( break; } - lines.Add (StringExtensions.ToString (runes.GetRange (start, end - start))); + lines.Add (StringExtensions.ToString (graphemes.GetRange (start, end - start))); start = end; if (incomplete) @@ -1494,14 +1500,14 @@ public static List WordWrapText ( { while ((end = start + GetLengthThatFits ( - runes.GetRange (start, runes.Count - start), + string.Concat (graphemes.GetRange (start, graphemes.Count - start)), width, tabWidth, textDirection )) - < runes.Count) + < graphemes.Count) { - while (runes [end].Value != ' ' && end > start) + while (graphemes [end] != " " && end > start) { end--; } @@ -1510,22 +1516,22 @@ public static List WordWrapText ( { end = start + GetLengthThatFits ( - runes.GetRange (end, runes.Count - end), + string.Concat (graphemes.GetRange (end, graphemes.Count - end)), width, tabWidth, textDirection ); } - var str = StringExtensions.ToString (runes.GetRange (start, end - start)); + var str = StringExtensions.ToString (graphemes.GetRange (start, end - start)); int zeroLength = text.EnumerateRunes ().Sum (r => r.GetColumns () == 0 ? 1 : 0); - if (end > start && GetRuneWidth (str, tabWidth, textDirection) <= width + zeroLength) + if (end > start && GetTextWidth (str, tabWidth, textDirection) <= width + zeroLength) { lines.Add (str); start = end; - if (runes [end].Value == ' ') + if (graphemes [end] == " ") { start++; } @@ -1539,9 +1545,9 @@ public static List WordWrapText ( } else { - while ((end = start + width) < runes.Count) + while ((end = start + width) < graphemes.Count) { - while (runes [end].Value != ' ' && end > start) + while (graphemes [end] != " " && end > start) { end--; } @@ -1553,11 +1559,11 @@ public static List WordWrapText ( var zeroLength = 0; - for (int i = end; i < runes.Count - start; i++) + for (int i = end; i < graphemes.Count - start; i++) { - Rune r = runes [i]; + string s = graphemes [i]; - if (r.GetColumns () == 0) + if (s.GetColumns () == 0) { zeroLength++; } @@ -1569,7 +1575,7 @@ public static List WordWrapText ( lines.Add ( StringExtensions.ToString ( - runes.GetRange ( + graphemes.GetRange ( start, end - start + zeroLength ) @@ -1578,7 +1584,7 @@ public static List WordWrapText ( end += zeroLength; start = end; - if (runes [end].Value == ' ') + if (graphemes [end] == " ") { start++; } @@ -1592,13 +1598,13 @@ int GetNextWhiteSpace (int from, int cWidth, out bool incomplete, int cLength = int length = cLength; incomplete = false; - while (length < cWidth && to < runes.Count) + while (length < cWidth && to < graphemes.Count) { - Rune rune = runes [to]; + string grapheme = graphemes [to]; if (IsHorizontalDirection (textDirection)) { - length += rune.GetColumns (); + length += grapheme.GetColumns (false); } else { @@ -1607,7 +1613,7 @@ int GetNextWhiteSpace (int from, int cWidth, out bool incomplete, int cLength = if (length > cWidth) { - if (to >= runes.Count || (length > 1 && cWidth <= 1)) + if (to >= graphemes.Count || (length > 1 && cWidth <= 1)) { incomplete = true; } @@ -1615,15 +1621,15 @@ int GetNextWhiteSpace (int from, int cWidth, out bool incomplete, int cLength = return to; } - switch (rune.Value) + switch (grapheme) { - case ' ' when length == cWidth: + case " " when length == cWidth: return to + 1; - case ' ' when length > cWidth: + case " " when length > cWidth: return to; - case ' ': + case " ": return GetNextWhiteSpace (to + 1, cWidth, out incomplete, length); - case '\t': + case "\t": { length += tabWidth + 1; @@ -1648,8 +1654,8 @@ int GetNextWhiteSpace (int from, int cWidth, out bool incomplete, int cLength = return cLength switch { - > 0 when to < runes.Count && runes [to].Value != ' ' && runes [to].Value != '\t' => from, - > 0 when to < runes.Count && (runes [to].Value == ' ' || runes [to].Value == '\t') => from, + > 0 when to < graphemes.Count && graphemes [to] != " " && graphemes [to] != "\t" => from, + > 0 when to < graphemes.Count && (graphemes [to] == " " || graphemes [to] == "\t") => from, _ => to }; } @@ -1657,7 +1663,7 @@ int GetNextWhiteSpace (int from, int cWidth, out bool incomplete, int cLength = if (start < text.GetRuneCount ()) { string str = ReplaceTABWithSpaces ( - StringExtensions.ToString (runes.GetRange (start, runes.Count - start)), + StringExtensions.ToString (graphemes.GetRange (start, graphemes.Count - start)), tabWidth ); @@ -1721,42 +1727,42 @@ public static string ClipAndJustify ( } text = ReplaceTABWithSpaces (text, tabWidth); - List runes = text.ToRuneList (); - int zeroLength = runes.Sum (r => r.GetColumns () == 0 ? 1 : 0); + List graphemes = GraphemeHelper.GetGraphemes (text).ToList (); + int zeroLength = graphemes.Sum (s => s.EnumerateRunes ().Sum (r => r.GetColumns() == 0 ? 1 : 0)); - if (runes.Count - zeroLength > width) + if (graphemes.Count - zeroLength > width) { if (IsHorizontalDirection (textDirection)) { if (textFormatter is { Alignment: Alignment.End }) { - return GetRangeThatFits (runes, runes.Count - width, text, width, tabWidth, textDirection); + return GetRangeThatFits (graphemes, graphemes.Count - width, text, width, tabWidth, textDirection); } if (textFormatter is { Alignment: Alignment.Center }) { - return GetRangeThatFits (runes, Math.Max ((runes.Count - width - zeroLength) / 2, 0), text, width, tabWidth, textDirection); + return GetRangeThatFits (graphemes, Math.Max ((graphemes.Count - width - zeroLength) / 2, 0), text, width, tabWidth, textDirection); } - return GetRangeThatFits (runes, 0, text, width, tabWidth, textDirection); + return GetRangeThatFits (graphemes, 0, text, width, tabWidth, textDirection); } if (IsVerticalDirection (textDirection)) { if (textFormatter is { VerticalAlignment: Alignment.End }) { - return GetRangeThatFits (runes, runes.Count - width, text, width, tabWidth, textDirection); + return GetRangeThatFits (graphemes, graphemes.Count - width, text, width, tabWidth, textDirection); } if (textFormatter is { VerticalAlignment: Alignment.Center }) { - return GetRangeThatFits (runes, Math.Max ((runes.Count - width - zeroLength) / 2, 0), text, width, tabWidth, textDirection); + return GetRangeThatFits (graphemes, Math.Max ((graphemes.Count - width - zeroLength) / 2, 0), text, width, tabWidth, textDirection); } - return GetRangeThatFits (runes, 0, text, width, tabWidth, textDirection); + return GetRangeThatFits (graphemes, 0, text, width, tabWidth, textDirection); } - return StringExtensions.ToString (runes.GetRange (0, width + zeroLength)); + return StringExtensions.ToString (graphemes.GetRange (0, width + zeroLength)); } if (justify) @@ -1768,18 +1774,18 @@ public static string ClipAndJustify ( { if (textFormatter is { Alignment: Alignment.End }) { - if (GetRuneWidth (text, tabWidth, textDirection) > width) + if (GetTextWidth (text, tabWidth, textDirection) > width) { - return GetRangeThatFits (runes, runes.Count - width, text, width, tabWidth, textDirection); + return GetRangeThatFits (graphemes, graphemes.Count - width, text, width, tabWidth, textDirection); } } else if (textFormatter is { Alignment: Alignment.Center }) { - return GetRangeThatFits (runes, Math.Max ((runes.Count - width - zeroLength) / 2, 0), text, width, tabWidth, textDirection); + return GetRangeThatFits (graphemes, Math.Max ((graphemes.Count - width - zeroLength) / 2, 0), text, width, tabWidth, textDirection); } - else if (GetRuneWidth (text, tabWidth, textDirection) > width) + else if (GetTextWidth (text, tabWidth, textDirection) > width) { - return GetRangeThatFits (runes, 0, text, width, tabWidth, textDirection); + return GetRangeThatFits (graphemes, 0, text, width, tabWidth, textDirection); } } @@ -1787,28 +1793,28 @@ public static string ClipAndJustify ( { if (textFormatter is { VerticalAlignment: Alignment.End }) { - if (runes.Count - zeroLength > width) + if (graphemes.Count - zeroLength > width) { - return GetRangeThatFits (runes, runes.Count - width, text, width, tabWidth, textDirection); + return GetRangeThatFits (graphemes, graphemes.Count - width, text, width, tabWidth, textDirection); } } else if (textFormatter is { VerticalAlignment: Alignment.Center }) { - return GetRangeThatFits (runes, Math.Max ((runes.Count - width - zeroLength) / 2, 0), text, width, tabWidth, textDirection); + return GetRangeThatFits (graphemes, Math.Max ((graphemes.Count - width - zeroLength) / 2, 0), text, width, tabWidth, textDirection); } - else if (runes.Count - zeroLength > width) + else if (graphemes.Count - zeroLength > width) { - return GetRangeThatFits (runes, 0, text, width, tabWidth, textDirection); + return GetRangeThatFits (graphemes, 0, text, width, tabWidth, textDirection); } } return text; } - private static string GetRangeThatFits (List runes, int index, string text, int width, int tabWidth, TextDirection textDirection) + private static string GetRangeThatFits (List strings, int index, string text, int width, int tabWidth, TextDirection textDirection) { return StringExtensions.ToString ( - runes.GetRange ( + strings.GetRange ( Math.Max (index, 0), GetLengthThatFits (text, width, tabWidth, textDirection) ) @@ -1846,7 +1852,7 @@ public static string Justify ( if (IsHorizontalDirection (textDirection)) { - textCount = words.Sum (arg => GetRuneWidth (arg, tabWidth, textDirection)); + textCount = words.Sum (arg => GetTextWidth (arg, tabWidth, textDirection)); } else { @@ -2141,11 +2147,11 @@ public static int GetColumnsRequiredForVerticalText ( i < (linesCount == -1 ? lines.Count : startLine + linesCount); i++) { - string runes = lines [i]; + string strings = lines [i]; - if (runes.Length > 0) + if (strings.Length > 0) { - max += runes.EnumerateRunes ().Max (r => GetRuneWidth (r, tabWidth)); + max += strings.EnumerateRunes ().Max (r => GetRuneWidth (r, tabWidth)); } } @@ -2167,7 +2173,7 @@ public static int GetWidestLineLength (string text, int tabWidth = 0) { List result = SplitNewLine (text); - return result.Max (x => GetRuneWidth (x, tabWidth)); + return result.Max (x => GetTextWidth (x, tabWidth)); } /// @@ -2186,13 +2192,13 @@ public static int GetWidestLineLength (string text, int tabWidth = 0) public static int GetSumMaxCharWidth (string text, int startIndex = -1, int length = -1, int tabWidth = 0) { var max = 0; - Rune [] runes = text.ToRunes (); + string [] graphemes = GraphemeHelper.GetGraphemes (text).ToArray (); for (int i = startIndex == -1 ? 0 : startIndex; - i < (length == -1 ? runes.Length : startIndex + length); + i < (length == -1 ? graphemes.Length : startIndex + length); i++) { - max += GetRuneWidth (runes [i], tabWidth); + max += GetStringWidth (graphemes [i], tabWidth); } return max; @@ -2210,51 +2216,38 @@ public static int GetSumMaxCharWidth (string text, int startIndex = -1, int leng /// The index of the text that fit the width. public static int GetLengthThatFits (string text, int width, int tabWidth = 0, TextDirection textDirection = TextDirection.LeftRight_TopBottom) { - return GetLengthThatFits (text?.ToRuneList () ?? [], width, tabWidth, textDirection); - } - - /// Gets the number of the Runes in a list of Runes that will fit in . - /// - /// This API will return incorrect results if the text includes glyphs whose width is dependent on surrounding - /// glyphs (e.g. Arabic). - /// - /// The list of runes. - /// The width. - /// The width used for a tab. - /// The text direction. - /// The index of the last Rune in that fit in . - public static int GetLengthThatFits (List runes, int width, int tabWidth = 0, TextDirection textDirection = TextDirection.LeftRight_TopBottom) - { - if (runes is null || runes.Count == 0) + if (string.IsNullOrEmpty (text)) { return 0; } - var runesLength = 0; - var runeIdx = 0; + var textLength = 0; + var stringIdx = 0; - for (; runeIdx < runes.Count; runeIdx++) + foreach (string grapheme in GraphemeHelper.GetGraphemes (text)) { - int runeWidth = GetRuneWidth (runes [runeIdx], tabWidth, textDirection); + int textWidth = GetStringWidth (grapheme, tabWidth, textDirection); - if (runesLength + runeWidth > width) + if (textLength + textWidth > width) { break; } - runesLength += runeWidth; + textLength += textWidth; + stringIdx++; } - return runeIdx; + return stringIdx; } - private static int GetRuneWidth (string str, int tabWidth, TextDirection textDirection = TextDirection.LeftRight_TopBottom) + private static int GetTextWidth (string str, int tabWidth, TextDirection textDirection = TextDirection.LeftRight_TopBottom) { int runesWidth = 0; - foreach (Rune rune in str.EnumerateRunes ()) + foreach (string grapheme in GraphemeHelper.GetGraphemes (str)) { - runesWidth += GetRuneWidth (rune, tabWidth, textDirection); + runesWidth += GetStringWidth (grapheme, tabWidth, textDirection); } + return runesWidth; } @@ -2275,6 +2268,23 @@ private static int GetRuneWidth (Rune rune, int tabWidth, TextDirection textDire return runeWidth; } + private static int GetStringWidth (string str, int tabWidth, TextDirection textDirection = TextDirection.LeftRight_TopBottom) + { + int textWidth = IsHorizontalDirection (textDirection) ? str.GetColumns (false) : str.GetColumns () == 0 ? 0 : 1; + + if (str == "\t") + { + return tabWidth; + } + + if (textWidth is < 0 or > 0) + { + return Math.Max (textWidth, 1); + } + + return textWidth; + } + /// Gets the index position from the list based on the . /// /// This API will return incorrect results if the text includes glyphs whose width is dependent on surrounding @@ -2286,23 +2296,23 @@ private static int GetRuneWidth (Rune rune, int tabWidth, TextDirection textDire /// The index of the list that fit the width. public static int GetMaxColsForWidth (List lines, int width, int tabWidth = 0) { - var runesLength = 0; + var textLength = 0; var lineIdx = 0; for (; lineIdx < lines.Count; lineIdx++) { - List runes = lines [lineIdx].ToRuneList (); + string [] graphemes = GraphemeHelper.GetGraphemes (lines [lineIdx]).ToArray (); - int maxRruneWidth = runes.Count > 0 - ? runes.Max (r => GetRuneWidth (r, tabWidth)) + int maxTextWidth = graphemes.Length > 0 + ? graphemes.Max (r => GetStringWidth (r, tabWidth)) : 1; - if (runesLength + maxRruneWidth > width) + if (textLength + maxTextWidth > width) { break; } - runesLength += maxRruneWidth; + textLength += maxTextWidth; } return lineIdx; diff --git a/Terminal.Gui/ViewBase/Adornment/ShadowView.cs b/Terminal.Gui/ViewBase/Adornment/ShadowView.cs index 151aa149ca..b9c2e4274c 100644 --- a/Terminal.Gui/ViewBase/Adornment/ShadowView.cs +++ b/Terminal.Gui/ViewBase/Adornment/ShadowView.cs @@ -100,7 +100,7 @@ private void DrawHorizontalShadowTransparent (Rectangle viewport) if (c < ScreenContents?.GetLength (1) && r < ScreenContents?.GetLength (0)) { - AddRune (ScreenContents [r, c].Rune); + AddStr (ScreenContents [r, c].Grapheme); } } } @@ -134,7 +134,7 @@ private void DrawVerticalShadowTransparent (Rectangle viewport) if (ScreenContents is { } && screen.X < ScreenContents.GetLength (1) && r < ScreenContents.GetLength (0)) { - AddRune (ScreenContents [r, c].Rune); + AddStr (ScreenContents [r, c].Grapheme); } } } @@ -142,7 +142,7 @@ private void DrawVerticalShadowTransparent (Rectangle viewport) private Attribute GetAttributeUnderLocation (Point location) { - if (SuperView is not Adornment adornment + if (SuperView is not Adornment || location.X < 0 || location.X >= Application.Screen.Width || location.Y < 0 @@ -170,8 +170,8 @@ private Attribute GetAttributeUnderLocation (Point location) // use the Normal attribute from the View under the shadow. if (newAttribute.Background == Color.DarkGray) { - List currentViewsUnderMouse = View.GetViewsUnderLocation (location, ViewportSettingsFlags.Transparent); - View? underView = currentViewsUnderMouse!.LastOrDefault (); + List currentViewsUnderMouse = GetViewsUnderLocation (location, ViewportSettingsFlags.Transparent); + View? underView = currentViewsUnderMouse.LastOrDefault (); attr = underView?.GetAttributeForRole (VisualRole.Normal) ?? Attribute.Default; newAttribute = new ( diff --git a/Terminal.Gui/ViewBase/View.Drawing.Primitives.cs b/Terminal.Gui/ViewBase/View.Drawing.Primitives.cs index d9d9333ee2..c81ffdbd30 100644 --- a/Terminal.Gui/ViewBase/View.Drawing.Primitives.cs +++ b/Terminal.Gui/ViewBase/View.Drawing.Primitives.cs @@ -32,7 +32,6 @@ public void AddRune (Rune rune) Driver?.AddRune (rune); } - /// /// Adds the specified to the display at the current cursor position. This method is a /// convenience method that calls with the constructor. @@ -72,6 +71,25 @@ public void AddStr (string str) { Driver?.AddStr (str); } + + /// Draws the specified in the specified viewport-relative column and row of the View. + /// + /// If the provided coordinates are outside the visible content area, this method does nothing. + /// + /// + /// The top-left corner of the visible content area is ViewPort.Location. + /// + /// Column (viewport-relative). + /// Row (viewport-relative). + /// The Text. + public void AddStr (int col, int row, string str) + { + if (Move (col, row)) + { + Driver?.AddStr (str); + } + } + /// Utility function to draw strings that contain a hotkey. /// String to display, the hotkey specifier before a letter flags the next letter as the hotkey. /// Hot color. diff --git a/Terminal.Gui/ViewBase/View.Drawing.cs b/Terminal.Gui/ViewBase/View.Drawing.cs index 1f27561238..82c1dc421e 100644 --- a/Terminal.Gui/ViewBase/View.Drawing.cs +++ b/Terminal.Gui/ViewBase/View.Drawing.cs @@ -195,11 +195,11 @@ internal void DoDrawAdornments (Region? originalClip) else { // Set the clip to be just the thicknesses of the adornments - // TODO: Put this union logic in a method on View? + // TODO: Put this union logic in a method on View? Region? clipAdornments = Margin!.Thickness.AsRegion (Margin!.FrameToScreen ()); - clipAdornments?.Combine (Border!.Thickness.AsRegion (Border!.FrameToScreen ()), RegionOp.Union); - clipAdornments?.Combine (Padding!.Thickness.AsRegion (Padding!.FrameToScreen ()), RegionOp.Union); - clipAdornments?.Combine (originalClip, RegionOp.Intersect); + clipAdornments.Combine (Border!.Thickness.AsRegion (Border!.FrameToScreen ()), RegionOp.Union); + clipAdornments.Combine (Padding!.Thickness.AsRegion (Padding!.FrameToScreen ()), RegionOp.Union); + clipAdornments.Combine (originalClip, RegionOp.Intersect); SetClip (clipAdornments); } @@ -240,7 +240,7 @@ public void DrawAdornments () { // We do not attempt to draw Margin. It is drawn in a separate pass. - // Each of these renders lines to this View's LineCanvas + // Each of these renders lines to this View's LineCanvas // Those lines will be finally rendered in OnRenderLineCanvas if (Border is { } && Border.Thickness != Thickness.Empty) { @@ -446,7 +446,7 @@ public void DrawText (DrawContext? context = null) // Report the drawn area to the context context?.AddDrawnRegion (textRegion); - TextFormatter?.Draw ( + TextFormatter.Draw ( drawRect, HasFocus ? GetAttributeForRole (VisualRole.Focus) : GetAttributeForRole (VisualRole.Normal), HasFocus ? GetAttributeForRole (VisualRole.HotFocus) : GetAttributeForRole (VisualRole.HotNormal), @@ -658,7 +658,7 @@ public void RenderLineCanvas () Driver.Move (p.Key.X, p.Key.Y); // TODO: #2616 - Support combining sequences that don't normalize - AddRune (p.Value.Value.Rune); + AddStr (p.Value.Value.Grapheme); } } @@ -685,7 +685,7 @@ private void DoDrawComplete (DrawContext? context) context!.ClipDrawnRegion (ViewportToScreen (Viewport)); // Exclude the drawn region from the clip - ExcludeFromClip (context!.GetDrawnRegion ()); + ExcludeFromClip (context.GetDrawnRegion ()); // Exclude the Border and Padding from the clip ExcludeFromClip (Border?.Thickness.AsRegion (Border.FrameToScreen ())); diff --git a/Terminal.Gui/Views/Autocomplete/AutocompleteFilepathContext.cs b/Terminal.Gui/Views/Autocomplete/AutocompleteFilepathContext.cs index 6c3e12c34d..d5d8240fa5 100644 --- a/Terminal.Gui/Views/Autocomplete/AutocompleteFilepathContext.cs +++ b/Terminal.Gui/Views/Autocomplete/AutocompleteFilepathContext.cs @@ -11,16 +11,16 @@ internal class AutocompleteFilepathContext (string currentLine, int cursorPositi internal class FilepathSuggestionGenerator : ISuggestionGenerator { - private FileDialogState state; + private FileDialogState _state; public IEnumerable GenerateSuggestions (AutocompleteContext context) { if (context is AutocompleteFilepathContext fileState) { - state = fileState.State; + _state = fileState.State; } - if (state is null) + if (_state is null) { return Enumerable.Empty (); } @@ -41,7 +41,7 @@ public IEnumerable GenerateSuggestions (AutocompleteContext context) return Enumerable.Empty (); } - if (term.Equals (state?.Directory?.Name)) + if (term.Equals (_state?.Directory?.Name)) { // Clear suggestions return Enumerable.Empty (); @@ -49,13 +49,13 @@ public IEnumerable GenerateSuggestions (AutocompleteContext context) bool isWindows = RuntimeInformation.IsOSPlatform (OSPlatform.Windows); - string [] suggestions = state.Children.Where (d => !d.IsParent) - .Select ( - e => e.FileSystemInfo is IDirectoryInfo d - ? d.Name + Path.DirectorySeparatorChar - : e.FileSystemInfo.Name - ) - .ToArray (); + string [] suggestions = _state!.Children.Where (d => !d.IsParent) + .Select ( + e => e.FileSystemInfo is IDirectoryInfo d + ? d.Name + Path.DirectorySeparatorChar + : e.FileSystemInfo.Name + ) + .ToArray (); string [] validSuggestions = suggestions .Where ( @@ -81,9 +81,9 @@ public IEnumerable GenerateSuggestions (AutocompleteContext context) .ToList (); } - public bool IsWordChar (Rune rune) + public bool IsWordChar (string text) { - if (rune.Value == '\n') + if (text == "\n") { return false; } diff --git a/Terminal.Gui/Views/Autocomplete/ISuggestionGenerator.cs b/Terminal.Gui/Views/Autocomplete/ISuggestionGenerator.cs index 08fd17c9a2..9f6c1dd45e 100644 --- a/Terminal.Gui/Views/Autocomplete/ISuggestionGenerator.cs +++ b/Terminal.Gui/Views/Autocomplete/ISuggestionGenerator.cs @@ -7,9 +7,9 @@ public interface ISuggestionGenerator IEnumerable GenerateSuggestions (AutocompleteContext context); /// - /// Returns if is a character that would continue autocomplete + /// Returns if is a character that would continue autocomplete /// suggesting. Returns if it is a 'breaking' character (i.e. terminating current word /// boundary) /// - bool IsWordChar (Rune rune); + bool IsWordChar (string text); } diff --git a/Terminal.Gui/Views/Autocomplete/PopupAutocomplete.cs b/Terminal.Gui/Views/Autocomplete/PopupAutocomplete.cs index 602a849d7f..dc912e4271 100644 --- a/Terminal.Gui/Views/Autocomplete/PopupAutocomplete.cs +++ b/Terminal.Gui/Views/Autocomplete/PopupAutocomplete.cs @@ -189,7 +189,7 @@ public override bool OnMouseEvent (MouseEventArgs me, bool fromHost = false) /// trueif the key can be handled falseotherwise. public override bool ProcessKey (Key key) { - if (SuggestionGenerator.IsWordChar ((Rune)key)) + if (SuggestionGenerator.IsWordChar (key.AsRune.ToString ())) { Visible = true; _closed = false; diff --git a/Terminal.Gui/Views/Autocomplete/SingleWordSuggestionGenerator.cs b/Terminal.Gui/Views/Autocomplete/SingleWordSuggestionGenerator.cs index 1accda9222..77d11acdeb 100644 --- a/Terminal.Gui/Views/Autocomplete/SingleWordSuggestionGenerator.cs +++ b/Terminal.Gui/Views/Autocomplete/SingleWordSuggestionGenerator.cs @@ -17,10 +17,10 @@ public IEnumerable GenerateSuggestions (AutocompleteContext context) // if there is nothing to pick from if (AllSuggestions.Count == 0) { - return Enumerable.Empty (); + return []; } - List line = context.CurrentLine.Select (c => c.Rune).ToList (); + List line = context.CurrentLine.Select (c => c.Grapheme).ToList (); string currentWord = IdxToWord (line, context.CursorPosition, out int startIdx); context.CursorPosition = startIdx < 1 ? startIdx : Math.Min (startIdx + 1, line.Count); @@ -43,9 +43,13 @@ public IEnumerable GenerateSuggestions (AutocompleteContext context) /// Return true if the given symbol should be considered part of a word and can be contained in matches. Base /// behavior is to use /// - /// The rune. + /// The text. /// - public virtual bool IsWordChar (Rune rune) { return char.IsLetterOrDigit ((char)rune.Value); } + public virtual bool IsWordChar (string text) + { + return !string.IsNullOrEmpty (text) + && Rune.IsLetterOrDigit (text.EnumerateRunes ().First ()); + } /// /// @@ -64,7 +68,7 @@ public IEnumerable GenerateSuggestions (AutocompleteContext context) /// The start index of the word. /// /// - protected virtual string IdxToWord (List line, int idx, out int startIdx, int columnOffset = 0) + protected virtual string IdxToWord (List line, int idx, out int startIdx, int columnOffset = 0) { var sb = new StringBuilder (); startIdx = idx; @@ -93,7 +97,7 @@ protected virtual string IdxToWord (List line, int idx, out int startIdx, { if (IsWordChar (line [startIdx])) { - sb.Insert (0, (char)line [startIdx].Value); + sb.Insert (0, line [startIdx]); } else { diff --git a/Terminal.Gui/Views/CharMap/CharMap.cs b/Terminal.Gui/Views/CharMap/CharMap.cs index 02308ac1e0..0750c8fe98 100644 --- a/Terminal.Gui/Views/CharMap/CharMap.cs +++ b/Terminal.Gui/Views/CharMap/CharMap.cs @@ -148,10 +148,8 @@ private void RebuildVisibleRows () break; } - var rune = new Rune (cp); - Span utf16 = new char [2]; - rune.EncodeToUtf16 (utf16); - UnicodeCategory cat = CharUnicodeInfo.GetUnicodeCategory (utf16 [0]); + string grapheme = new Rune (cp).ToString (); + UnicodeCategory cat = CharUnicodeInfo.GetUnicodeCategory (cp); if (cat == ShowUnicodeCategory.Value) { anyVisible = true; @@ -685,7 +683,7 @@ protected override bool OnDrawingContent () // Don't render out-of-range scalars if (scalar > MAX_CODE_POINT) { - AddRune (' '); + AddStr (" "); if (visibleRow == selectedRowIndex && col == selectedCol) { SetAttributeForRole (VisualRole.Normal); @@ -693,22 +691,20 @@ protected override bool OnDrawingContent () continue; } - var rune = (Rune)'?'; + string grapheme = "?"; if (Rune.IsValid (scalar)) { - rune = new (scalar); + grapheme = new Rune (scalar).ToString (); } - int width = rune.GetColumns (); + int width = grapheme.GetColumns (); // Compute visibility based on ShowUnicodeCategory bool isVisible = Rune.IsValid (scalar); if (isVisible && ShowUnicodeCategory.HasValue) { - Span filterUtf16 = new char [2]; - rune.EncodeToUtf16 (filterUtf16); - UnicodeCategory cat = CharUnicodeInfo.GetUnicodeCategory (filterUtf16 [0]); + UnicodeCategory cat = CharUnicodeInfo.GetUnicodeCategory (scalar); isVisible = cat == ShowUnicodeCategory.Value; } @@ -717,11 +713,11 @@ protected override bool OnDrawingContent () // Glyph row if (isVisible) { - RenderRune (rune, width); + RenderGrapheme (grapheme, width, scalar); } else { - AddRune (' '); + AddStr (" "); } } else @@ -736,7 +732,7 @@ protected override bool OnDrawingContent () } else { - AddRune (' '); + AddStr (" "); } } @@ -750,21 +746,18 @@ protected override bool OnDrawingContent () return true; - void RenderRune (Rune rune, int width) + void RenderGrapheme (string grapheme, int width, int scalar) { // Get the UnicodeCategory - Span utf16 = new char [2]; - int charCount = rune.EncodeToUtf16 (utf16); - // Get the bidi class for the first code unit // For most bidi characters, the first code unit is sufficient - UnicodeCategory category = CharUnicodeInfo.GetUnicodeCategory (utf16 [0]); + UnicodeCategory category = CharUnicodeInfo.GetUnicodeCategory (scalar); switch (category) { case UnicodeCategory.OtherNotAssigned: SetAttributeForRole (VisualRole.Highlight); - AddRune (Rune.ReplacementChar); + AddStr (Rune.ReplacementChar.ToString ()); SetAttributeForRole (VisualRole.Normal); break; @@ -773,7 +766,7 @@ void RenderRune (Rune rune, int width) // These report width of 0 and don't render on their own. case UnicodeCategory.Format: SetAttributeForRole (VisualRole.Highlight); - AddRune ('F'); + AddStr ("F"); SetAttributeForRole (VisualRole.Normal); break; @@ -786,36 +779,7 @@ void RenderRune (Rune rune, int width) case UnicodeCategory.EnclosingMark: if (width > 0) { - AddRune (rune); - } - else - { - if (rune.IsCombiningMark ()) - { - // This is a hack to work around the fact that combining marks - // a) can't be rendered on their own - // b) that don't normalize are not properly supported in - // any known terminal (esp Windows/AtlasEngine). - // See Issue #2616 - var sb = new StringBuilder (); - sb.Append ('a'); - sb.Append (rune); - - // Try normalizing after combining with 'a'. If it normalizes, at least - // it'll show on the 'a'. If not, just show the replacement char. - string normal = sb.ToString ().Normalize (NormalizationForm.FormC); - - if (normal.Length == 1) - { - AddRune ((Rune)normal [0]); - } - else - { - SetAttributeForRole (VisualRole.Highlight); - AddRune ('M'); - SetAttributeForRole (VisualRole.Normal); - } - } + AddStr (grapheme); } break; @@ -825,20 +789,28 @@ void RenderRune (Rune rune, int width) case UnicodeCategory.LineSeparator: case UnicodeCategory.ParagraphSeparator: case UnicodeCategory.Surrogate: - AddRune (rune); + AddStr (grapheme); break; + case UnicodeCategory.OtherLetter: + AddStr (grapheme); + if (width == 0) + { + AddStr (" "); + } + + break; default: // Draw the rune if (width > 0) { - AddRune (rune); + AddStr (grapheme); } else { - throw new InvalidOperationException ($"The Rune \"{rune}\" (U+{rune.Value:x6}) has zero width and no special-case UnicodeCategory logic applies."); + throw new InvalidOperationException ($"The Rune \"{grapheme}\" (U+{Rune.GetRuneAt (grapheme, 0).Value:x6}) has zero width and no special-case UnicodeCategory logic applies."); } break; diff --git a/Terminal.Gui/Views/Slider/Slider.cs b/Terminal.Gui/Views/Slider/Slider.cs index ff0308a560..e064e46d23 100644 --- a/Terminal.Gui/Views/Slider/Slider.cs +++ b/Terminal.Gui/Views/Slider/Slider.cs @@ -73,13 +73,13 @@ private void SetDefaultStyle () switch (_config._sliderOrientation) { case Orientation.Horizontal: - Style.SpaceChar = new () { Rune = Glyphs.HLine }; // '─' - Style.OptionChar = new () { Rune = Glyphs.BlackCircle }; // '┼●🗹□⏹' + Style.SpaceChar = new () { Grapheme = Glyphs.HLine.ToString () }; // '─' + Style.OptionChar = new () { Grapheme = Glyphs.BlackCircle.ToString () }; // '┼●🗹□⏹' break; case Orientation.Vertical: - Style.SpaceChar = new () { Rune = Glyphs.VLine }; - Style.OptionChar = new () { Rune = Glyphs.BlackCircle }; + Style.SpaceChar = new () { Grapheme = Glyphs.VLine.ToString () }; + Style.OptionChar = new () { Grapheme = Glyphs.BlackCircle.ToString () }; break; } @@ -104,12 +104,12 @@ private void SetDefaultStyle () */ _config._legendsOrientation = _config._sliderOrientation; - Style.EmptyChar = new () { Rune = new (' ') }; - Style.SetChar = new () { Rune = Glyphs.ContinuousMeterSegment }; // ■ - Style.RangeChar = new () { Rune = Glyphs.Stipple }; // ░ ▒ ▓ // Medium shade not blinking on curses. - Style.StartRangeChar = new () { Rune = Glyphs.ContinuousMeterSegment }; - Style.EndRangeChar = new () { Rune = Glyphs.ContinuousMeterSegment }; - Style.DragChar = new () { Rune = Glyphs.Diamond }; + Style.EmptyChar = new () { Grapheme = " " }; + Style.SetChar = new () { Grapheme = Glyphs.ContinuousMeterSegment.ToString () }; // ■ + Style.RangeChar = new () { Grapheme = Glyphs.Stipple.ToString () }; // ░ ▒ ▓ // Medium shade not blinking on curses. + Style.StartRangeChar = new () { Grapheme = Glyphs.ContinuousMeterSegment.ToString () }; + Style.EndRangeChar = new () { Grapheme = Glyphs.ContinuousMeterSegment.ToString () }; + Style.DragChar = new () { Grapheme = Glyphs.Diamond.ToString () }; // TODO: Support left & right (top/bottom) // First = '├', @@ -255,11 +255,11 @@ public void OnOrientationChanged (Orientation newOrientation) switch (_config._sliderOrientation) { case Orientation.Horizontal: - Style.SpaceChar = new () { Rune = Glyphs.HLine }; // '─' + Style.SpaceChar = new () { Grapheme = Glyphs.HLine.ToString () }; // '─' break; case Orientation.Vertical: - Style.SpaceChar = new () { Rune = Glyphs.VLine }; + Style.SpaceChar = new () { Grapheme = Glyphs.VLine.ToString () }; break; } @@ -798,7 +798,7 @@ protected override bool OnDrawingContent () if (_dragPosition.HasValue && _moveRenderPosition.HasValue) { - AddRune (_moveRenderPosition.Value.X, _moveRenderPosition.Value.Y, Style.DragChar.Rune); + AddStr (_moveRenderPosition.Value.X, _moveRenderPosition.Value.Y, Style.DragChar.Grapheme); } return true; @@ -874,11 +874,11 @@ private void DrawSlider () ? Style.RangeChar.Attribute ?? normalAttr : Style.SpaceChar.Attribute ?? normalAttr ); - Rune rune = isSet && _config._type == SliderType.LeftRange ? Style.RangeChar.Rune : Style.SpaceChar.Rune; + string text = isSet && _config._type == SliderType.LeftRange ? Style.RangeChar.Grapheme : Style.SpaceChar.Grapheme; for (var i = 0; i < _config._startSpacing; i++) { - MoveAndAdd (x, y, rune); + MoveAndAdd (x, y, text); if (isVertical) { @@ -896,7 +896,7 @@ private void DrawSlider () for (var i = 0; i < _config._startSpacing; i++) { - MoveAndAdd (x, y, Style.EmptyChar.Rune); + MoveAndAdd (x, y, Style.EmptyChar.Grapheme); if (isVertical) { @@ -950,25 +950,25 @@ private void DrawSlider () drawRange ? Style.RangeChar.Attribute ?? setAttr : Style.OptionChar.Attribute ?? normalAttr ); - Rune rune = drawRange ? Style.RangeChar.Rune : Style.OptionChar.Rune; + string text = drawRange ? Style.RangeChar.Grapheme : Style.OptionChar.Grapheme; if (isSet) { if (_setOptions [0] == i) { - rune = Style.StartRangeChar.Rune; + text = Style.StartRangeChar.Grapheme; } else if (_setOptions.Count > 1 && _setOptions [1] == i) { - rune = Style.EndRangeChar.Rune; + text = Style.EndRangeChar.Grapheme; } else if (_setOptions.Contains (i)) { - rune = Style.SetChar.Rune; + text = Style.SetChar.Grapheme; } } - MoveAndAdd (x, y, rune); + MoveAndAdd (x, y, text); if (isVertical) { @@ -991,7 +991,7 @@ private void DrawSlider () for (var s = 0; s < _config._cachedInnerSpacing; s++) { - MoveAndAdd (x, y, drawRange && isSet ? Style.RangeChar.Rune : Style.SpaceChar.Rune); + MoveAndAdd (x, y, drawRange && isSet ? Style.RangeChar.Grapheme : Style.SpaceChar.Grapheme); if (isVertical) { @@ -1016,11 +1016,11 @@ private void DrawSlider () ? Style.RangeChar.Attribute ?? normalAttr : Style.SpaceChar.Attribute ?? normalAttr ); - Rune rune = isSet && _config._type == SliderType.RightRange ? Style.RangeChar.Rune : Style.SpaceChar.Rune; + string text = isSet && _config._type == SliderType.RightRange ? Style.RangeChar.Grapheme : Style.SpaceChar.Grapheme; for (var i = 0; i < remaining; i++) { - MoveAndAdd (x, y, rune); + MoveAndAdd (x, y, text); if (isVertical) { @@ -1038,7 +1038,7 @@ private void DrawSlider () for (var i = 0; i < remaining; i++) { - MoveAndAdd (x, y, Style.EmptyChar.Rune); + MoveAndAdd (x, y, Style.EmptyChar.Grapheme); if (isVertical) { diff --git a/Terminal.Gui/Views/TableView/TreeTableSource.cs b/Terminal.Gui/Views/TableView/TreeTableSource.cs index 6cbb5b0a73..0a671f1f60 100644 --- a/Terminal.Gui/Views/TableView/TreeTableSource.cs +++ b/Terminal.Gui/Views/TableView/TreeTableSource.cs @@ -87,14 +87,14 @@ private string GetColumnZeroRepresentationFromTree (int row) { Branch branch = RowToBranch (row); - // Everything on line before the expansion run and branch text - Rune [] prefix = branch.GetLinePrefix ().ToArray (); - Rune expansion = branch.GetExpandableSymbol (); + // Everything on the line before the expansion run and branch text + string [] prefix = branch.GetLinePrefix ().ToArray (); + string expansion = branch.GetExpandableSymbol (); string lineBody = _tree.AspectGetter (branch.Model) ?? ""; var sb = new StringBuilder (); - foreach (Rune p in prefix) + foreach (string p in prefix) { sb.Append (p); } diff --git a/Terminal.Gui/Views/TextInput/TextField.cs b/Terminal.Gui/Views/TextInput/TextField.cs index bc2390fb62..808ae386dd 100644 --- a/Terminal.Gui/Views/TextInput/TextField.cs +++ b/Terminal.Gui/Views/TextInput/TextField.cs @@ -16,7 +16,7 @@ public class TextField : View, IDesignable private int _selectedStart; // -1 represents there is no text selection. private string _selectedText; private int _start; - private List _text; + private List _text; /// /// Initializes a new instance of the class. @@ -543,7 +543,7 @@ public string SelectedText ClearAllSelection (); // Note we use NewValue here; TextChanging subscribers may have changed it - _text = args.Result.EnumerateRunes ().ToList (); + _text = args.Result.ToStringList (); if (!Secret && !_historyText.IsFromHistory) { @@ -631,7 +631,7 @@ public virtual void Cut () } Clipboard.Contents = SelectedText; - List newText = DeleteSelectedText (); + List newText = DeleteSelectedText (); Text = StringExtensions.ToString (newText); Adjust (); } @@ -702,7 +702,7 @@ public virtual void DeleteCharLeft (bool usePreTextChangedCursorPos) } else { - List newText = DeleteSelectedText (); + List newText = DeleteSelectedText (); Text = StringExtensions.ToString (newText); Adjust (); } @@ -736,7 +736,7 @@ public virtual void DeleteCharRight () } else { - List newText = DeleteSelectedText (); + List newText = DeleteSelectedText (); Text = StringExtensions.ToString (newText); Adjust (); } @@ -945,8 +945,8 @@ protected override bool OnDrawingContent () for (int idx = p; idx < tcount; idx++) { - Rune rune = _text [idx]; - int cols = rune.GetColumns (); + string text = _text [idx]; + int cols = text.GetColumns (); if (!Enabled) { @@ -982,7 +982,7 @@ protected override bool OnDrawingContent () if (col + cols <= width) { - AddRune (Secret ? Glyphs.Dot : rune); + AddStr (Secret ? Glyphs.Dot.ToString () : text); } if (!TextModel.SetCol (ref col, width, cols)) @@ -1258,7 +1258,7 @@ private void CreateContextMenu () private void ContextMenu_KeyChanged (object sender, KeyChangedEventArgs e) { KeyBindings.Replace (e.OldKey.KeyCode, e.NewKey.KeyCode); } - private List DeleteSelectedText () + private List DeleteSelectedText () { SetSelectedStartSelectedLength (); int selStart = SelectedStart > -1 ? _start : _cursorPosition; @@ -1274,7 +1274,7 @@ private List DeleteSelectedText () ClearAllSelection (); _cursorPosition = selStart >= newText.GetRuneCount () ? newText.GetRuneCount () : selStart; - return newText.ToRuneList (); + return newText.ToStringList (); } private void GenerateSuggestions () @@ -1322,7 +1322,7 @@ private void InsertText (Key a, bool usePreTextChangedCursorPos) new (_cursorPosition, 0) ); - List newText = _text; + List newText = _text; if (SelectedLength > 0) { @@ -1343,7 +1343,7 @@ private void InsertText (Key a, bool usePreTextChangedCursorPos) if (_cursorPosition == newText.Count + 1) { - SetText (newText.Concat (kbstr).ToList ()); + SetText (newText.Concat (kbstr.Select (r => r.ToString ())).ToList ()); } else { @@ -1354,7 +1354,7 @@ private void InsertText (Key a, bool usePreTextChangedCursorPos) SetText ( newText.GetRange (0, _preTextChangedCursorPos) - .Concat (kbstr) + .Concat (kbstr.Select (r => r.ToString ())) .Concat ( newText.GetRange ( _preTextChangedCursorPos, @@ -1371,7 +1371,7 @@ private void InsertText (Key a, bool usePreTextChangedCursorPos) { SetText ( newText.GetRange (0, _preTextChangedCursorPos) - .Concat (kbstr) + .Concat (kbstr.Select (r => r.ToString ())) .Concat ( newText.GetRange ( Math.Min (_preTextChangedCursorPos + 1, newText.Count), @@ -1736,7 +1736,7 @@ private void RenderCaption () hotKeyAttribute); } - private void SetClipboard (IEnumerable text) + private void SetClipboard (IEnumerable text) { if (!Secret) { @@ -1762,8 +1762,8 @@ private void SetSelectedStartSelectedLength () } } - private void SetText (List newText) { Text = StringExtensions.ToString (newText); } - private void SetText (IEnumerable newText) { SetText (newText.ToList ()); } + private void SetText (List newText) { Text = StringExtensions.ToString (newText); } + private void SetText (IEnumerable newText) { SetText (newText.ToList ()); } private void ShowContextMenu (bool keyboard) { diff --git a/Terminal.Gui/Views/TextInput/TextModel.cs b/Terminal.Gui/Views/TextInput/TextModel.cs index 275c8a9083..be11b5e5e2 100644 --- a/Terminal.Gui/Views/TextInput/TextModel.cs +++ b/Terminal.Gui/Views/TextInput/TextModel.cs @@ -72,7 +72,7 @@ public int GetMaxVisibleLine (int first, int last, int tabWidth) for (int i = first; i < last; i++) { List line = GetLine (i); - int tabSum = line.Sum (c => c.Rune.Value == '\t' ? Math.Max (tabWidth - 1, 0) : 0); + int tabSum = line.Sum (c => c.Grapheme == "\t" ? Math.Max (tabWidth - 1, 0) : 0); int l = line.Count + tabSum; if (l > maxLength) @@ -223,7 +223,7 @@ public override string ToString () if (cell is { }) { - rune = cell.Value.Rune; + rune = Rune.GetRuneAt (cell.Value.Grapheme, 0); } else { @@ -300,10 +300,11 @@ void ProcMovePrev (ref int nCol, ref int nRow, Rune nRune) } List line = GetLine (nRow); + Rune firstRune = Rune.GetRuneAt (line [0].Grapheme, 0); if (nCol == 0 && nRow == fromRow - && (Rune.IsLetterOrDigit (line [0].Rune) || Rune.IsPunctuation (line [0].Rune) || Rune.IsSymbol (line [0].Rune))) + && (Rune.IsLetterOrDigit (firstRune) || Rune.IsPunctuation (firstRune) || Rune.IsSymbol (firstRune))) { return; } @@ -367,7 +368,7 @@ void ProcMovePrev (ref int nCol, ref int nRow, Rune nRune) try { - Rune rune = _lines [row].Count > 0 ? RuneAt (col, row)!.Value.Rune : default (Rune); + Rune rune = _lines [row].Count > 0 ? Rune.GetRuneAt (RuneAt (col, row)!.Value.Grapheme, 0) : default (Rune); RuneType runeType = GetRuneType (rune); int lastValidCol = IsSameRuneType (rune, runeType, useSameRuneType) && (Rune.IsLetterOrDigit (rune) || Rune.IsPunctuation (rune) || Rune.IsSymbol (rune)) @@ -426,10 +427,11 @@ void ProcMoveNext (ref int nCol, ref int nRow, Rune nRune) } List line = GetLine (nRow); + Rune firstRune = Rune.GetRuneAt (line [0].Grapheme, 0); if (nCol == line.Count && nRow == fromRow - && (Rune.IsLetterOrDigit (line [0].Rune) || Rune.IsPunctuation (line [0].Rune) || Rune.IsSymbol (line [0].Rune))) + && (Rune.IsLetterOrDigit (firstRune) || Rune.IsPunctuation (firstRune) || Rune.IsSymbol (firstRune))) { return; } @@ -476,10 +478,10 @@ void ProcMoveNext (ref int nCol, ref int nRow, Rune nRune) } if (startCol > 0 - && StringExtensions.ToString (line.GetRange (startCol, col - startCol).Select (c => c.Rune).ToList ()).Trim () == "" - && (col - startCol > 1 || (col - startCol > 0 && line [startCol - 1].Rune == (Rune)' '))) + && StringExtensions.ToString (line.GetRange (startCol, col - startCol).Select (c => c.Grapheme).ToList ()).Trim () == "" + && (col - startCol > 1 || (col - startCol > 0 && line [startCol - 1].Grapheme == " "))) { - while (startCol > 0 && line [startCol - 1].Rune == (Rune)' ') + while (startCol > 0 && line [startCol - 1].Grapheme == " ") { startCol--; } @@ -496,13 +498,13 @@ void ProcMoveNext (ref int nCol, ref int nRow, Rune nRune) if (selectWordOnly) { - List selRunes = line.GetRange (startCol, col - startCol).Select (c => c.Rune).ToList (); + List selText = line.GetRange (startCol, col - startCol).Select (c => c.Grapheme).ToList (); - if (StringExtensions.ToString (selRunes).Trim () != "") + if (StringExtensions.ToString (selText).Trim () != "") { - for (int i = selRunes.Count - 1; i > -1; i--) + for (int i = selText.Count - 1; i > -1; i--) { - if (selRunes [i] == (Rune)' ') + if (selText [i] == " ") { col--; } @@ -520,18 +522,18 @@ void ProcMoveNext (ref int nCol, ref int nRow, Rune nRune) internal static int CalculateLeftColumn (List t, int start, int end, int width, int tabWidth = 0) { - List runes = new (); + List strings = new (); foreach (Cell cell in t) { - runes.Add (cell.Rune); + strings.Add (cell.Grapheme); } - return CalculateLeftColumn (runes, start, end, width, tabWidth); + return CalculateLeftColumn (strings, start, end, width, tabWidth); } // Returns the left column in a range of the string. - internal static int CalculateLeftColumn (List t, int start, int end, int width, int tabWidth = 0) + internal static int CalculateLeftColumn (List t, int start, int end, int width, int tabWidth = 0) { if (t is null || t.Count == 0) { @@ -539,15 +541,15 @@ internal static int CalculateLeftColumn (List t, int start, int end, int w } var size = 0; - int tcount = end > t.Count - 1 ? t.Count - 1 : end; + int tCount = end > t.Count - 1 ? t.Count - 1 : end; var col = 0; - for (int i = tcount; i >= 0; i--) + for (int i = tCount; i >= 0; i--) { - Rune rune = t [i]; - size += rune.GetColumns (); + string text = t [i]; + size += text.GetColumns (false); - if (rune.Value == '\t') + if (text == "\t") { size += tabWidth + 1; } @@ -577,23 +579,23 @@ internal static (int size, int length) DisplaySize ( List t, int start = -1, int end = -1, - bool checkNextRune = true, + bool checkNextText = true, int tabWidth = 0 ) { - List runes = new (); + List strings = new (); foreach (Cell cell in t) { - runes.Add (cell.Rune); + strings.Add (cell.Grapheme); } - return DisplaySize (runes, start, end, checkNextRune, tabWidth); + return DisplaySize (strings, start, end, checkNextText, tabWidth); } // Returns the size and length in a range of the string. internal static (int size, int length) DisplaySize ( - List t, + List t, int start = -1, int end = -1, bool checkNextRune = true, @@ -608,35 +610,35 @@ internal static (int size, int length) DisplaySize ( var size = 0; var len = 0; - int tcount = end == -1 ? t.Count : + int tCount = end == -1 ? t.Count : end > t.Count ? t.Count : end; int i = start == -1 ? 0 : start; - for (; i < tcount; i++) + for (; i < tCount; i++) { - Rune rune = t [i]; - size += rune.GetColumns (); - len += rune.GetEncodingLength (Encoding.Unicode); + string text = t [i]; + size += text.GetColumns (false); + len += text.Length; - if (rune.Value == '\t') + if (text == "\t") { size += tabWidth + 1; len += tabWidth - 1; } - if (checkNextRune && i == tcount - 1 && t.Count > tcount && IsWideRune (t [i + 1], tabWidth, out int s, out int l)) + if (checkNextRune && i == tCount - 1 && t.Count > tCount && IsWideText (t [i + 1], tabWidth, out int s, out int l)) { size += s; len += l; } } - bool IsWideRune (Rune r, int tWidth, out int s, out int l) + bool IsWideText (string s1, int tWidth, out int s, out int l) { - s = r.GetColumns (); - l = r.GetEncodingLength (); + s = s1.GetColumns (); + l = Encoding.Unicode.GetByteCount (s1); - if (r.Value == '\t') + if (s1 == "\t") { s += tWidth + 1; l += tWidth - 1; @@ -745,17 +747,17 @@ internal Size GetDisplaySize () internal static int GetColFromX (List t, int start, int x, int tabWidth = 0) { - List runes = new (); + List strings = new (); foreach (Cell cell in t) { - runes.Add (cell.Rune); + strings.Add (cell.Grapheme); } - return GetColFromX (runes, start, x, tabWidth); + return GetColFromX (strings, start, x, tabWidth); } - internal static int GetColFromX (List t, int start, int x, int tabWidth = 0) + internal static int GetColFromX (List t, int start, int x, int tabWidth = 0) { if (x < 0) { @@ -767,10 +769,10 @@ internal static int GetColFromX (List t, int start, int x, int tabWidth = for (int i = start; i < t.Count; i++) { - Rune r = t [i]; - size += r.GetColumns (); + string s = t [i]; + size += s.GetColumns (); - if (r.Value == '\t') + if (s == "\t") { size += tabWidth + 1; } @@ -1056,18 +1058,21 @@ private bool MoveNext (ref int col, ref int row, out Rune rune, bool useSameRune if (col + 1 < line.Count) { col++; - rune = line [col].Rune; + rune = Rune.GetRuneAt (line [col].Grapheme, 0); + Rune prevRune = Rune.GetRuneAt (line [col - 1].Grapheme, 0); if (col + 1 == line.Count && !Rune.IsLetterOrDigit (rune) - && !Rune.IsWhiteSpace (line [col - 1].Rune) - && IsSameRuneType (line [col - 1].Rune, GetRuneType (rune), useSameRuneType)) + && !Rune.IsWhiteSpace (prevRune) + && IsSameRuneType (prevRune, GetRuneType (rune), useSameRuneType)) { col++; } + prevRune = Rune.GetRuneAt (line [col - 1].Grapheme, 0); + if (!Rune.IsWhiteSpace (rune) - && (Rune.IsWhiteSpace (line [col - 1].Rune) || !IsSameRuneType (line [col - 1].Rune, GetRuneType (rune), useSameRuneType))) + && (Rune.IsWhiteSpace (prevRune) || !IsSameRuneType (prevRune, GetRuneType (rune), useSameRuneType))) { return false; } @@ -1098,12 +1103,13 @@ private bool MovePrev (ref int col, ref int row, out Rune rune, bool useSameRune if (col > 0) { col--; - rune = line [col].Rune; + rune = Rune.GetRuneAt (line [col].Grapheme, 0); + Rune nextRune = Rune.GetRuneAt (line [col + 1].Grapheme, 0); if ((!Rune.IsWhiteSpace (rune) - && !Rune.IsWhiteSpace (line [col + 1].Rune) - && !IsSameRuneType (line [col + 1].Rune, GetRuneType (rune), useSameRuneType)) - || (Rune.IsWhiteSpace (rune) && !Rune.IsWhiteSpace (line [col + 1].Rune))) + && !Rune.IsWhiteSpace (nextRune) + && !IsSameRuneType (nextRune, GetRuneType (rune), useSameRuneType)) + || (Rune.IsWhiteSpace (rune) && !Rune.IsWhiteSpace (nextRune))) { return false; } diff --git a/Terminal.Gui/Views/TextInput/TextView.cs b/Terminal.Gui/Views/TextInput/TextView.cs index f9e2031d94..d4fb20b093 100644 --- a/Terminal.Gui/Views/TextInput/TextView.cs +++ b/Terminal.Gui/Views/TextInput/TextView.cs @@ -1487,7 +1487,7 @@ public void Load (Stream stream) } /// Loads the contents of the list into the . - /// Rune cells list to load the contents from. + /// Text cells list to load the contents from. public void Load (List cells) { SetWrapModel (); @@ -1807,8 +1807,8 @@ protected override bool OnDrawingContent () for (int idxCol = _leftColumn; idxCol < lineRuneCount; idxCol++) { - Rune rune = idxCol >= lineRuneCount ? (Rune)' ' : line [idxCol].Rune; - int cols = rune.GetColumns (); + string text = idxCol >= lineRuneCount ? " " : line [idxCol].Grapheme; + int cols = text.GetColumns (false); if (idxCol < line.Count && IsSelecting && PointInSelection (idxCol, idxRow)) { @@ -1827,7 +1827,7 @@ protected override bool OnDrawingContent () OnDrawNormalColor (line, idxCol, idxRow); } - if (rune.Value == '\t') + if (text == "\t") { cols += TabWidth + 1; @@ -1846,7 +1846,7 @@ protected override bool OnDrawingContent () } else { - AddRune (col, row, rune); + AddStr (col, row, text); // Ensures that cols less than 0 to be 1 because it will be converted to a printable rune cols = Math.Max (cols, 1); @@ -1857,7 +1857,7 @@ protected override bool OnDrawingContent () break; } - if (idxCol + 1 < lineRuneCount && col + line [idxCol + 1].Rune.GetColumns () > right) + if (idxCol + 1 < lineRuneCount && col + line [idxCol + 1].Grapheme.GetColumns () > right) { break; } @@ -2053,9 +2053,9 @@ public void Paste () break; } - int cols = line [idx].Rune.GetColumns (); + int cols = line [idx].Grapheme.GetColumns (); - if (line [idx].Rune.Value == '\t') + if (line [idx].Grapheme == "\t") { cols += TabWidth + 1; } @@ -2812,12 +2812,12 @@ internal string GetRegion ( cells = line.GetRange (startCol, endCol - startCol); cellsList.Add (cells); - return StringFromRunes (cells); + return StringFromCells (cells); } cells = line.GetRange (startCol, line.Count - startCol); cellsList.Add (cells); - string res = StringFromRunes (cells); + string res = StringFromCells (cells); for (int row = startRow + 1; row < maxRow; row++) { @@ -2827,14 +2827,14 @@ internal string GetRegion ( res = res + Environment.NewLine - + StringFromRunes (cells); + + StringFromCells (cells); } line = model is null ? _model.GetLine (maxRow) : model.GetLine (maxRow); cellsList.AddRange ([]); cells = line.GetRange (0, endCol); cellsList.Add (cells); - res = res + Environment.NewLine + StringFromRunes (cells); + res = res + Environment.NewLine + StringFromCells (cells); return res; } @@ -3114,7 +3114,7 @@ private bool InsertText (Key a, Attribute? attribute = null) { if (Used) { - Insert (new () { Rune = a.AsRune, Attribute = attribute }); + Insert (new () { Grapheme = a.AsRune.ToString (), Attribute = attribute }); CurrentColumn++; if (CurrentColumn >= _leftColumn + Viewport.Width) @@ -3125,7 +3125,7 @@ private bool InsertText (Key a, Attribute? attribute = null) } else { - Insert (new () { Rune = a.AsRune, Attribute = attribute }); + Insert (new () { Grapheme = a.AsRune.ToString (), Attribute = attribute }); CurrentColumn++; } } @@ -3213,7 +3213,7 @@ private void KillToEndOfLine () int restCount = currentLine.Count - CurrentColumn; List rest = currentLine.GetRange (CurrentColumn, restCount); var val = string.Empty; - val += StringFromRunes (rest); + val += StringFromCells (rest); if (_lastWasKill) { @@ -3319,7 +3319,7 @@ private void KillToLeftStart () int restCount = CurrentColumn; List rest = currentLine.GetRange (0, restCount); var val = string.Empty; - val += StringFromRunes (rest); + val += StringFromCells (rest); if (_lastWasKill) { @@ -3848,7 +3848,7 @@ private bool ProcessBackTab () List currentLine = GetCurrentLine (); - if (currentLine.Count > 0 && currentLine [CurrentColumn - 1].Rune.Value == '\t') + if (currentLine.Count > 0 && currentLine[CurrentColumn - 1].Grapheme == "\t") { _historyText.Add (new () { new (currentLine) }, CursorPosition); @@ -4606,29 +4606,28 @@ private void StopSelecting () _isButtonShift = false; } - private string StringFromRunes (List cells) + private string StringFromCells (List cells) { - if (cells is null) - { - throw new ArgumentNullException (nameof (cells)); - } + ArgumentNullException.ThrowIfNull (cells); var size = 0; - foreach (Cell cell in cells) { - size += cell.Rune.GetEncodingLength (); + string t = cell.Grapheme; + size += Encoding.Unicode.GetByteCount (t); } - var encoded = new byte [size]; + byte [] encoded = new byte [size]; var offset = 0; - foreach (Cell cell in cells) { - offset += cell.Rune.Encode (encoded, offset); + string t = cell.Grapheme; + int bytesWritten = Encoding.Unicode.GetBytes (t, 0, t.Length, encoded, offset); + offset += bytesWritten; } - return StringExtensions.ToString (encoded); + // decode using the same encoding and the bytes actually written + return Encoding.Unicode.GetString (encoded, 0, offset); } private void TextView_SuperViewChanged (object sender, SuperViewChangedEventArgs e) diff --git a/Terminal.Gui/Views/TreeView/Branch.cs b/Terminal.Gui/Views/TreeView/Branch.cs index 811824dbfc..f1c036075d 100644 --- a/Terminal.Gui/Views/TreeView/Branch.cs +++ b/Terminal.Gui/Views/TreeView/Branch.cs @@ -87,9 +87,9 @@ public virtual void Draw (int y, int availableWidth) isSelected ? _tree.HasFocus ? _tree.GetAttributeForRole (VisualRole.Focus) : _tree.GetAttributeForRole (VisualRole.HotNormal) : _tree.GetAttributeForRole (VisualRole.Normal); Attribute symbolColor = _tree.Style.HighlightModelTextOnly ? _tree.GetAttributeForRole (VisualRole.Normal) : textColor; - // Everything on line before the expansion run and branch text - Rune [] prefix = GetLinePrefix ().ToArray (); - Rune expansion = GetExpandableSymbol (); + // Everything on the line before the expansion run and branch text + string [] prefix = GetLinePrefix ().ToArray (); + string expansion = GetExpandableSymbol (); string lineBody = _tree.AspectGetter (Model) ?? ""; _tree.Move (0, y); @@ -99,7 +99,7 @@ public virtual void Draw (int y, int availableWidth) Attribute attr = symbolColor; // Draw the line prefix (all parallel lanes or whitespace and an expand/collapse/leaf symbol) - foreach (Rune r in prefix) + foreach (string s in prefix) { if (toSkip > 0) { @@ -107,8 +107,8 @@ public virtual void Draw (int y, int availableWidth) } else { - cells.Add (NewCell (attr, r)); - availableWidth -= r.GetColumns (); + cells.Add (NewCell (attr, s)); + availableWidth -= s.GetColumns (); } } @@ -212,7 +212,7 @@ public virtual void Draw (int y, int availableWidth) } attr = modelColor; - cells.AddRange (lineBody.Select (r => NewCell (attr, new (r)))); + cells.AddRange (lineBody.Select (c => NewCell (attr, c.ToString ()))); if (availableWidth > 0) { @@ -220,7 +220,7 @@ public virtual void Draw (int y, int availableWidth) cells.AddRange ( Enumerable.Repeat ( - NewCell (attr, new (' ')), + NewCell (attr, " "), availableWidth ) ); @@ -243,7 +243,7 @@ public virtual void Draw (int y, int availableWidth) foreach (Cell cell in cells) { _tree.SetAttribute ((Attribute)cell.Attribute!); - _tree.AddRune (cell.Rune); + _tree.AddStr (cell.Grapheme); } } @@ -288,21 +288,21 @@ private List> FetchChildren () /// object to indicate whether it or not (or it is a leaf). /// /// - public Rune GetExpandableSymbol () + public string GetExpandableSymbol () { Rune leafSymbol = _tree.Style.ShowBranchLines ? Glyphs.HLine : (Rune)' '; if (IsExpanded) { - return _tree.Style.CollapseableSymbol ?? leafSymbol; + return _tree.Style.CollapseableSymbol.ToString () ?? leafSymbol.ToString (); } if (CanExpand ()) { - return _tree.Style.ExpandableSymbol ?? leafSymbol; + return _tree.Style.ExpandableSymbol.ToString () ?? leafSymbol.ToString (); } - return leafSymbol; + return leafSymbol.ToString (); } /// @@ -409,14 +409,14 @@ internal void ExpandAll () /// any tree branches (if enabled). /// /// - internal IEnumerable GetLinePrefix () + internal IEnumerable GetLinePrefix () { // If not showing line branches or this is a root object. if (!_tree.Style.ShowBranchLines) { for (var i = 0; i < Depth; i++) { - yield return new (' '); + yield return new (" "); } yield break; @@ -427,23 +427,23 @@ internal IEnumerable GetLinePrefix () { if (cur.IsLast ()) { - yield return new (' '); + yield return new (" "); } else { - yield return Glyphs.VLine; + yield return Glyphs.VLine.ToString (); } - yield return new (' '); + yield return new (" "); } if (IsLast ()) { - yield return Glyphs.LLCorner; + yield return Glyphs.LLCorner.ToString (); } else { - yield return Glyphs.LeftTee; + yield return Glyphs.LeftTee.ToString (); } } @@ -531,5 +531,5 @@ private bool IsLast () return Parent.ChildBranches.LastOrDefault () == this; } - private static Cell NewCell (Attribute attr, Rune r) { return new () { Rune = r, Attribute = new (attr) }; } + private static Cell NewCell (Attribute attr, string s) { return new () { Grapheme = s, Attribute = new (attr) }; } } diff --git a/Tests/UnitTests/DriverAssert.cs b/Tests/UnitTests/DriverAssert.cs index a1abc36b59..bbef9143f5 100644 --- a/Tests/UnitTests/DriverAssert.cs +++ b/Tests/UnitTests/DriverAssert.cs @@ -196,7 +196,7 @@ public static Rectangle AssertDriverContentsWithFrameAre ( IDriver? driver = null ) { - List> lines = []; + List> lines = []; var sb = new StringBuilder (); driver ??= Application.Driver; @@ -209,13 +209,13 @@ public static Rectangle AssertDriverContentsWithFrameAre ( for (var rowIndex = 0; rowIndex < driver.Rows; rowIndex++) { - List runes = []; + List strings = []; for (var colIndex = 0; colIndex < driver.Cols; colIndex++) { - Rune runeAtCurrentLocation = contents! [rowIndex, colIndex].Rune; + string textAtCurrentLocation = contents! [rowIndex, colIndex].Grapheme; - if (runeAtCurrentLocation != _spaceRune) + if (textAtCurrentLocation != _spaceRune.ToString ()) { if (x == -1) { @@ -224,11 +224,11 @@ public static Rectangle AssertDriverContentsWithFrameAre ( for (var i = 0; i < colIndex; i++) { - runes.InsertRange (i, [_spaceRune]); + strings.InsertRange (i, [_spaceRune.ToString ()]); } } - if (runeAtCurrentLocation.GetColumns () > 1) + if (textAtCurrentLocation.GetColumns () > 1) { colIndex++; } @@ -243,18 +243,13 @@ public static Rectangle AssertDriverContentsWithFrameAre ( if (x > -1) { - runes.Add (runeAtCurrentLocation); + strings.Add (textAtCurrentLocation); } - - // See Issue #2616 - //foreach (var combMark in contents [r, c].CombiningMarks) { - // runes.Add (combMark); - //} } - if (runes.Count > 0) + if (strings.Count > 0) { - lines.Add (runes); + lines.Add (strings); } } @@ -268,13 +263,13 @@ public static Rectangle AssertDriverContentsWithFrameAre ( } // Remove trailing whitespace on each line - foreach (List row in lines) + foreach (List row in lines) { for (int c = row.Count - 1; c >= 0; c--) { - Rune rune = row [c]; + string text = row [c]; - if (rune != (Rune)' ' || row.Sum (x => x.GetColumns ()) == w) + if (text != " " || row.Sum (x => x.GetColumns ()) == w) { break; } @@ -283,7 +278,7 @@ public static Rectangle AssertDriverContentsWithFrameAre ( } } - // Convert Rune list to string + // Convert Text list to string for (var r = 0; r < lines.Count; r++) { var line = StringExtensions.ToString (lines [r]); diff --git a/Tests/UnitTests/Drivers/ClipRegionTests.cs b/Tests/UnitTests/Drivers/ClipRegionTests.cs index 8ede58565a..40c5aba9f8 100644 --- a/Tests/UnitTests/Drivers/ClipRegionTests.cs +++ b/Tests/UnitTests/Drivers/ClipRegionTests.cs @@ -16,24 +16,24 @@ public void AddRune_Is_Clipped () Application.Driver!.Move (0, 0); Application.Driver!.AddRune ('x'); - Assert.Equal ((Rune)'x', Application.Driver!.Contents! [0, 0].Rune); + Assert.Equal ("x", Application.Driver!.Contents! [0, 0].Grapheme); Application.Driver?.Move (5, 5); Application.Driver?.AddRune ('x'); - Assert.Equal ((Rune)'x', Application.Driver!.Contents [5, 5].Rune); + Assert.Equal ("x", Application.Driver!.Contents [5, 5].Grapheme); // Clear the contents Application.Driver?.FillRect (new Rectangle (0, 0, Application.Driver.Rows, Application.Driver.Cols), ' '); - Assert.Equal ((Rune)' ', Application.Driver?.Contents [0, 0].Rune); + Assert.Equal (" ", Application.Driver?.Contents [0, 0].Grapheme); // Setup the region with a single rectangle, fill screen with 'x' Application.Driver!.Clip = new (new Rectangle (5, 5, 5, 5)); Application.Driver.FillRect (new Rectangle (0, 0, Application.Driver.Rows, Application.Driver.Cols), 'x'); - Assert.Equal ((Rune)' ', Application.Driver?.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', Application.Driver?.Contents [4, 9].Rune); - Assert.Equal ((Rune)'x', Application.Driver?.Contents [5, 5].Rune); - Assert.Equal ((Rune)'x', Application.Driver?.Contents [9, 9].Rune); - Assert.Equal ((Rune)' ', Application.Driver?.Contents [10, 10].Rune); + Assert.Equal (" ", Application.Driver?.Contents [0, 0].Grapheme); + Assert.Equal (" ", Application.Driver?.Contents [4, 9].Grapheme); + Assert.Equal ("x", Application.Driver?.Contents [5, 5].Grapheme); + Assert.Equal ("x", Application.Driver?.Contents [9, 9].Grapheme); + Assert.Equal (" ", Application.Driver?.Contents [10, 10].Grapheme); Application.Shutdown (); } diff --git a/Tests/UnitTests/View/Draw/ClipTests.cs b/Tests/UnitTests/View/Draw/ClipTests.cs index 44b120d769..474ebb03b9 100644 --- a/Tests/UnitTests/View/Draw/ClipTests.cs +++ b/Tests/UnitTests/View/Draw/ClipTests.cs @@ -47,17 +47,17 @@ public void AddRune_Is_Constrained_To_Viewport () view.Draw (); // Only valid location w/in Viewport is 0, 0 (view) - 2, 2 (screen) - Assert.Equal ((Rune)' ', Application.Driver?.Contents! [2, 2].Rune); + Assert.Equal (" ", Application.Driver?.Contents! [2, 2].Grapheme); // When we exit Draw, the view is excluded from the clip. So drawing at 0,0, is not valid and is clipped. view.AddRune (0, 0, Rune.ReplacementChar); - Assert.Equal ((Rune)' ', Application.Driver?.Contents! [2, 2].Rune); + Assert.Equal (" ", Application.Driver?.Contents! [2, 2].Grapheme); view.AddRune (-1, -1, Rune.ReplacementChar); - Assert.Equal ((Rune)'P', Application.Driver?.Contents! [1, 1].Rune); + Assert.Equal ("P", Application.Driver?.Contents! [1, 1].Grapheme); view.AddRune (1, 1, Rune.ReplacementChar); - Assert.Equal ((Rune)'P', Application.Driver?.Contents! [3, 3].Rune); + Assert.Equal ("P", Application.Driver?.Contents! [3, 3].Grapheme); } [Theory] @@ -226,7 +226,7 @@ public void Clipping_Wide_Runes () // 01 2345678901234 56 78 90 12 34 56 // │� |0123456989│� ン ラ イ ン で す 。 expectedOutput = """ - │�│0123456789│�ンラインです。 + │�│0123456789│ ンラインです。 """; DriverAssert.AssertDriverContentsWithFrameAre (expectedOutput, _output); diff --git a/Tests/UnitTests/View/Draw/DrawTests.cs b/Tests/UnitTests/View/Draw/DrawTests.cs index 2526c2178f..2c731ac3ca 100644 --- a/Tests/UnitTests/View/Draw/DrawTests.cs +++ b/Tests/UnitTests/View/Draw/DrawTests.cs @@ -14,19 +14,19 @@ public class DrawTests (ITestOutputHelper output) [Trait ("Category", "Unicode")] public void CJK_Compatibility_Ideographs_ConsoleWidth_ColumnWidth_Equal_Two () { - const string us = "\U0000f900"; + const string s = "\U0000f900"; var r = (Rune)0xf900; - Assert.Equal ("豈", us); + Assert.Equal ("豈", s); Assert.Equal ("豈", r.ToString ()); - Assert.Equal (us, r.ToString ()); + Assert.Equal (s, r.ToString ()); - Assert.Equal (2, us.GetColumns ()); + Assert.Equal (2, s.GetColumns ()); Assert.Equal (2, r.GetColumns ()); - var win = new Window { Title = us }; + var win = new Window { Title = s }; var view = new View { Text = r.ToString (), Height = Dim.Fill (), Width = Dim.Fill () }; - var tf = new TextField { Text = us, Y = 1, Width = 3 }; + var tf = new TextField { Text = s, Y = 1, Width = 3 }; win.Add (view, tf); Toplevel top = new (); top.Add (win); @@ -36,9 +36,9 @@ public void CJK_Compatibility_Ideographs_ConsoleWidth_ColumnWidth_Equal_Two () const string expectedOutput = """ - ┌┤豈├────┐ - │豈 │ - │豈 │ + ┌┤豈├────┐ + │豈 │ + │豈 │ └────────┘ """; DriverAssert.AssertDriverContentsWithFrameAre (expectedOutput, output); diff --git a/Tests/UnitTests/View/TextTests.cs b/Tests/UnitTests/View/TextTests.cs index 3e552204c1..8e9a7beab8 100644 --- a/Tests/UnitTests/View/TextTests.cs +++ b/Tests/UnitTests/View/TextTests.cs @@ -701,7 +701,7 @@ string GetContents () for (var i = 0; i < 4; i++) { - text += Application.Driver?.Contents [0, i].Rune; + text += Application.Driver?.Contents [0, i].Grapheme; } return text; diff --git a/Tests/UnitTests/Views/LabelTests.cs b/Tests/UnitTests/Views/LabelTests.cs index 550abf360b..0ebc19d9ba 100644 --- a/Tests/UnitTests/Views/LabelTests.cs +++ b/Tests/UnitTests/Views/LabelTests.cs @@ -154,7 +154,7 @@ This TextFormatter (tf2) is rewritten. ", [AutoInitShutdown] public void Label_Draw_Horizontal_Simple_Runes () { - var label = new Label { Text = "Demo Simple Rune" }; + var label = new Label { Text = "Demo Simple Text" }; var top = new Toplevel (); top.Add (label); Application.Begin (top); @@ -163,7 +163,7 @@ public void Label_Draw_Horizontal_Simple_Runes () Assert.Equal (new (0, 0, 16, 1), label.Frame); var expected = @" -Demo Simple Rune +Demo Simple Text "; Rectangle pos = DriverAssert.AssertDriverContentsWithFrameAre (expected, output); @@ -173,9 +173,9 @@ Demo Simple Rune [Fact] [AutoInitShutdown] - public void Label_Draw_Vertical_Simple_Runes () + public void Label_Draw_Vertical_Simple_Text () { - var label = new Label { TextDirection = TextDirection.TopBottom_LeftRight, Text = "Demo Simple Rune" }; + var label = new Label { TextDirection = TextDirection.TopBottom_LeftRight, Text = "Demo Simple Text" }; var top = new Toplevel (); top.Add (label); Application.Begin (top); @@ -196,10 +196,10 @@ public void Label_Draw_Vertical_Simple_Runes () l e -R -u -n +T e +x +t "; Rectangle pos = DriverAssert.AssertDriverContentsWithFrameAre (expected, output); diff --git a/Tests/UnitTests/Views/ListViewTests.cs b/Tests/UnitTests/Views/ListViewTests.cs index d428277608..3995e61dde 100644 --- a/Tests/UnitTests/Views/ListViewTests.cs +++ b/Tests/UnitTests/Views/ListViewTests.cs @@ -362,7 +362,7 @@ string GetContents (int line) for (var i = 0; i < 7; i++) { - item += Application.Driver?.Contents [line, i].Rune; + item += Application.Driver?.Contents [line, i].Grapheme; } return item; diff --git a/Tests/UnitTests/Views/ProgressBarTests.cs b/Tests/UnitTests/Views/ProgressBarTests.cs index 26b70fe0ed..f78cbc4453 100644 --- a/Tests/UnitTests/Views/ProgressBarTests.cs +++ b/Tests/UnitTests/Views/ProgressBarTests.cs @@ -42,57 +42,57 @@ public void Fraction_Redraw () if (i == 0) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); } else if (i == 1) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); } else if (i == 2) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); } else if (i == 3) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); } else if (i == 4) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); } else if (i == 5) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); } } } @@ -180,687 +180,687 @@ public void Pulse_Redraw_BidirectionalMarquee_False () if (i == 0) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 1) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 2) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 3) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 4) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 5) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 6) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 7) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 8) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 9) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 10) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 11) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 12) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 13) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 14) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 15) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 16) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 17) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 18) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 19) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 20) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 21) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 22) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 23) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 24) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 25) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 26) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 27) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 28) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 29) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 30) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 31) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 32) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 33) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 34) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 35) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 36) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 37) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } } } @@ -885,687 +885,687 @@ public void Pulse_Redraw_BidirectionalMarquee_True_Default () if (i == 0) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 1) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 2) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 3) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 4) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 5) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 6) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 7) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 8) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 9) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 10) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 11) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 12) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 13) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 14) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 15) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 16) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 17) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 18) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 19) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 20) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 21) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 22) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 14].Grapheme); } else if (i == 23) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 24) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 25) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 26) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 27) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 28) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 29) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 30) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 31) { - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (" ", driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 32) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 33) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 34) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 35) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 36) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } else if (i == 37) { - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 0].Rune); - Assert.Equal (Glyphs.BlocksMeterSegment, driver.Contents [0, 1].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 2].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 3].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 4].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 5].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 6].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 7].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 8].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 10].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 11].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 12].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 13].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 14].Rune); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 0].Grapheme); + Assert.Equal (Glyphs.BlocksMeterSegment.ToString (), driver.Contents [0, 1].Grapheme); + Assert.Equal (" ", driver.Contents [0, 2].Grapheme); + Assert.Equal (" ", driver.Contents [0, 3].Grapheme); + Assert.Equal (" ", driver.Contents [0, 4].Grapheme); + Assert.Equal (" ", driver.Contents [0, 5].Grapheme); + Assert.Equal (" ", driver.Contents [0, 6].Grapheme); + Assert.Equal (" ", driver.Contents [0, 7].Grapheme); + Assert.Equal (" ", driver.Contents [0, 8].Grapheme); + Assert.Equal (" ", driver.Contents [0, 9].Grapheme); + Assert.Equal (" ", driver.Contents [0, 10].Grapheme); + Assert.Equal (" ", driver.Contents [0, 11].Grapheme); + Assert.Equal (" ", driver.Contents [0, 12].Grapheme); + Assert.Equal (" ", driver.Contents [0, 13].Grapheme); + Assert.Equal (" ", driver.Contents [0, 14].Grapheme); } } } diff --git a/Tests/UnitTests/Views/TextFieldTests.cs b/Tests/UnitTests/Views/TextFieldTests.cs index b4d27b93b0..c37b10ed2b 100644 --- a/Tests/UnitTests/Views/TextFieldTests.cs +++ b/Tests/UnitTests/Views/TextFieldTests.cs @@ -95,6 +95,7 @@ public void CaptionedTextField_DoesNotOverspillViewport_Unicode () Assert.Equal (11, caption.Length); Assert.Equal (10, caption.EnumerateRunes ().Sum (c => c.GetColumns ())); + Assert.Equal (10, caption.GetColumns ()); TextField tf = GetTextFieldsInView (); diff --git a/Tests/UnitTests/Views/TextViewTests.cs b/Tests/UnitTests/Views/TextViewTests.cs index d00000d2e0..6b4d9c7662 100644 --- a/Tests/UnitTests/Views/TextViewTests.cs +++ b/Tests/UnitTests/Views/TextViewTests.cs @@ -6916,7 +6916,7 @@ private int GetLeftCol (int start) { string [] lines = _textView.Text.Split (Environment.NewLine); - if (lines == null || lines.Length == 0) + if (lines is { Length: 0 }) { return 0; } @@ -7024,11 +7024,11 @@ public void CellEventArgs_WordWrap_True () List> text = [ Cell.ToCells ( - "This is the first line.".ToRunes () + "This is the first line.".ToStringList () ), Cell.ToCells ( - "This is the second line.".ToRunes () + "This is the second line.".ToStringList () ) ]; TextView tv = CreateTextView (); @@ -7091,12 +7091,9 @@ public void Cell_LoadCells_InheritsPreviousAttribute () { string csName = color.Key; - foreach (Rune rune in csName.EnumerateRunes ()) - { - cells.Add (new () { Rune = rune, Attribute = color.Value.Normal }); - } + cells.AddRange (Cell.ToCellList (csName, color.Value.Normal)); - cells.Add (new () { Rune = (Rune)'\n', Attribute = color.Value.Focus }); + cells.Add (new () { Grapheme = "\n", Attribute = color.Value.Focus }); } TextView tv = CreateTextView (); diff --git a/Tests/UnitTests/Views/TreeViewTests.cs b/Tests/UnitTests/Views/TreeViewTests.cs index 88b9cde4be..4a35ac84c3 100644 --- a/Tests/UnitTests/Views/TreeViewTests.cs +++ b/Tests/UnitTests/Views/TreeViewTests.cs @@ -975,10 +975,10 @@ public void TestTreeView_DrawLineEvent () Assert.All (eventArgs, ea => Assert.Equal (ea.Tree, tv)); Assert.All (eventArgs, ea => Assert.False (ea.Handled)); - Assert.Equal ("├-root one", eventArgs [0].Cells.Aggregate ("", (s, n) => s += n.Rune).TrimEnd ()); - Assert.Equal ("│ ├─leaf 1", eventArgs [1].Cells.Aggregate ("", (s, n) => s += n.Rune).TrimEnd ()); - Assert.Equal ("│ └─leaf 2", eventArgs [2].Cells.Aggregate ("", (s, n) => s += n.Rune).TrimEnd ()); - Assert.Equal ("└─root two", eventArgs [3].Cells.Aggregate ("", (s, n) => s += n.Rune).TrimEnd ()); + Assert.Equal ("├-root one", eventArgs [0].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ()); + Assert.Equal ("│ ├─leaf 1", eventArgs [1].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ()); + Assert.Equal ("│ └─leaf 2", eventArgs [2].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ()); + Assert.Equal ("└─root two", eventArgs [3].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ()); Assert.Equal (1, eventArgs [0].IndexOfExpandCollapseSymbol); Assert.Equal (3, eventArgs [1].IndexOfExpandCollapseSymbol); @@ -1088,9 +1088,9 @@ oot two Assert.All (eventArgs, ea => Assert.Equal (ea.Tree, tv)); Assert.All (eventArgs, ea => Assert.False (ea.Handled)); - Assert.Equal ("─leaf 1", eventArgs [0].Cells.Aggregate ("", (s, n) => s += n.Rune).TrimEnd ()); - Assert.Equal ("─leaf 2", eventArgs [1].Cells.Aggregate ("", (s, n) => s += n.Rune).TrimEnd ()); - Assert.Equal ("oot two", eventArgs [2].Cells.Aggregate ("", (s, n) => s += n.Rune).TrimEnd ()); + Assert.Equal ("─leaf 1", eventArgs [0].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ()); + Assert.Equal ("─leaf 2", eventArgs [1].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ()); + Assert.Equal ("oot two", eventArgs [2].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ()); Assert.Equal (0, eventArgs [0].IndexOfExpandCollapseSymbol); Assert.Equal (0, eventArgs [1].IndexOfExpandCollapseSymbol); diff --git a/Tests/UnitTestsParallelizable/Drawing/CellTests.cs b/Tests/UnitTestsParallelizable/Drawing/CellTests.cs index 13a088a13f..b635d2bad1 100644 --- a/Tests/UnitTestsParallelizable/Drawing/CellTests.cs +++ b/Tests/UnitTestsParallelizable/Drawing/CellTests.cs @@ -1,17 +1,39 @@ using System.Text; -using Xunit.Abstractions; namespace UnitTests_Parallelizable.DrawingTests; -public class CellTests () +public class CellTests { [Fact] public void Constructor_Defaults () { var c = new Cell (); Assert.True (c is { }); - Assert.Equal (0, c.Rune.Value); + Assert.Empty (c.Runes); Assert.Null (c.Attribute); + Assert.False (c.IsDirty); + Assert.Null (c.Grapheme); + } + + [Theory] + [InlineData (null, new uint [] { })] + [InlineData ("", new uint [] { })] + [InlineData ("a", new uint [] { 0x0061 })] + [InlineData ("👩‍❤️‍💋‍👨", new uint [] { 0x1F469, 0x200D, 0x2764, 0xFE0F, 0x200D, 0x1F48B, 0x200D, 0x1F468 })] + [InlineData ("æ", new uint [] { 0x00E6 })] + [InlineData ("a︠", new uint [] { 0x0061, 0xFE20 })] + [InlineData ("e︡", new uint [] { 0x0065, 0xFE21 })] + public void Runes_From_Grapheme (string grapheme, uint [] expected) + { + // Arrange + var c = new Cell { Grapheme = grapheme }; + + // Act + Rune [] runes = expected.Select (u => new Rune (u)).ToArray (); + + // Assert + Assert.Equal (grapheme, c.Grapheme); + Assert.Equal (runes, c.Runes); } [Fact] @@ -21,32 +43,138 @@ public void Equals_False () var c2 = new Cell { - Rune = new ('a'), Attribute = new (Color.Red) + Grapheme = "a", Attribute = new (Color.Red) }; Assert.False (c1.Equals (c2)); Assert.False (c2.Equals (c1)); - c1.Rune = new ('a'); + c1.Grapheme = "a"; c1.Attribute = new (); - Assert.Equal (c1.Rune, c2.Rune); + Assert.Equal (c1.Grapheme, c2.Grapheme); Assert.False (c1.Equals (c2)); Assert.False (c2.Equals (c1)); } [Fact] - public void ToString_Override () + public void Set_Text_With_Invalid_Grapheme_Throws () { - var c1 = new Cell (); + Assert.Throws (() => new Cell { Grapheme = "ab" }); + Assert.Throws (() => new Cell { Grapheme = "\u0061\u0062" }); // ab + } - var c2 = new Cell + [Theory] + [MemberData (nameof (ToStringTestData))] + public void ToString_Override (string text, Attribute? attribute, string expected) + { + var c = new Cell (attribute, true, text); + string result = c.ToString (); + + Assert.Equal (expected, result); + } + + public static IEnumerable ToStringTestData () + { + yield return ["", null, "[\"\":]"]; + yield return ["a", null, "[\"a\":]"]; + yield return ["\t", null, "[\"\\t\":]"]; + yield return ["\r", null, "[\"\\r\":]"]; + yield return ["\n", null, "[\"\\n\":]"]; + yield return ["\r\n", null, "[\"\\r\\n\":]"]; + yield return ["\f", null, "[\"\\f\":]"]; + yield return ["\v", null, "[\"\\v\":]"]; + yield return ["\x1B", null, "[\"\\u001B\":]"]; + yield return ["\\", new Attribute (Color.Blue), "[\"\\\":[Blue,Blue,None]]"]; + yield return ["😀", null, "[\"😀\":]"]; + yield return ["👨‍👩‍👦‍👦", null, "[\"👨‍👩‍👦‍👦\":]"]; + yield return ["A", new Attribute (Color.Red) { Style = TextStyle.Blink }, "[\"A\":[Red,Red,Blink]]"]; + yield return ["\U0001F469\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468", null, "[\"👩‍❤️‍💋‍👨\":]"]; + } + + [Fact] + public void Graphemes_Decomposed_Normalize () + { + Cell c1 = new () { - Rune = new ('a'), Attribute = new (Color.Red) + // 'e' + '◌́' COMBINING ACUTE ACCENT (U+0301) + Grapheme = "e\u0301" // visually "é" }; - Assert.Equal ("['\0':]", c1.ToString ()); - Assert.Equal ( - "['a':[Red,Red,None]]", - c2.ToString () - ); + Cell c2 = new () + { + // NFC single code point (U+00E9) + Grapheme = "é" + }; + + // Validation + Assert.Equal ("é", c1.Grapheme); // Proper normalized grapheme + Assert.Equal (c1.Grapheme, c2.Grapheme); + Assert.Equal (c1.Runes.Count, c2.Runes.Count); + Assert.Equal (new (0x00E9), c2.Runes [0]); + } + + [Fact] + public void Cell_IsDirty_Flag_Works () + { + var c = new Cell (); + Assert.False (c.IsDirty); + c.IsDirty = true; + Assert.True (c.IsDirty); + c.IsDirty = false; + Assert.False (c.IsDirty); + } + + [Theory] + [InlineData ("\uFDD0", false)] + [InlineData ("\uFDEF", false)] + [InlineData ("\uFFFE", true)] + [InlineData ("\uFFFF", false)] + [InlineData ("\U0001FFFE", false)] + [InlineData ("\U0001FFFF", false)] + [InlineData ("\U0010FFFE", false)] + [InlineData ("\U0010FFFF", false)] + public void IsNormalized_ArgumentException (string text, bool throws) + { + try + { + bool normalized = text.IsNormalized (NormalizationForm.FormC); + + Assert.True (normalized); + Assert.False (throws); + } + catch (ArgumentException) + { + Assert.True (throws); + } + + Cell c = new () { Grapheme = text }; + } + + [Fact] + public void Surrogate_Normalize_Throws_And_Cell_Setter_Throws () + { + // Create the lone high surrogate at runtime (safe) + string s = new string ((char)0xD800, 1); + + // Confirm the runtime string actually contains the surrogate + Assert.Equal (0xD800, s [0]); + + // Normalize should throw + Assert.Throws (() => s.Normalize (NormalizationForm.FormC)); + + // And if your Grapheme setter normalizes, assignment should throw as well + Assert.Throws (() => new Cell () { Grapheme = s }); + + // Create the lone low surrogate at runtime (safe) + s = new string ((char)0xDC00, 1); + + // Confirm the runtime string actually contains the surrogate + Assert.Equal (0xDC00, s [0]); + + // Normalize should throw + Assert.Throws (() => s.Normalize (NormalizationForm.FormC)); + + // And if your Grapheme setter normalizes, assignment should throw as well + Assert.Throws (() => new Cell () { Grapheme = s }); } + } diff --git a/Tests/UnitTestsParallelizable/Drivers/AddRuneTests.cs b/Tests/UnitTestsParallelizable/Drivers/AddRuneTests.cs index 2dd2fb769a..4b42057911 100644 --- a/Tests/UnitTestsParallelizable/Drivers/AddRuneTests.cs +++ b/Tests/UnitTestsParallelizable/Drivers/AddRuneTests.cs @@ -19,7 +19,7 @@ public void AddRune () driver.Rows = 25; driver.Cols = 80; driver.AddRune (new Rune ('a')); - Assert.Equal ((Rune)'a', driver.Contents [0, 0].Rune); + Assert.Equal ("a", driver.Contents [0, 0].Grapheme); driver.End (); } @@ -29,28 +29,30 @@ public void AddRune_Accented_Letter_With_Three_Combining_Unicode_Chars () { IDriver driver = CreateFakeDriver (); - var expected = new Rune ('ắ'); + var expected = "ắ"; var text = "\u1eaf"; driver.AddStr (text); - Assert.Equal (expected, driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); + Assert.Equal (expected, driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); driver.ClearContents (); driver.Move (0, 0); + expected = "ắ"; text = "\u0103\u0301"; driver.AddStr (text); - Assert.Equal (expected, driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); + Assert.Equal (expected, driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); driver.ClearContents (); driver.Move (0, 0); + expected = "ắ"; text = "\u0061\u0306\u0301"; driver.AddStr (text); - Assert.Equal (expected, driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); + Assert.Equal (expected, driver.Contents [0, 0].Grapheme); + Assert.Equal (" ", driver.Contents [0, 1].Grapheme); // var s = "a\u0301\u0300\u0306"; @@ -86,7 +88,7 @@ public void AddRune_InvalidLocation_DoesNothing () { for (var row = 0; row < driver.Rows; row++) { - Assert.Equal ((Rune)' ', driver.Contents [row, col].Rune); + Assert.Equal (" ", driver.Contents [row, col].Grapheme); } } @@ -99,12 +101,12 @@ public void AddRune_MovesToNextColumn () IDriver driver = CreateFakeDriver (); driver.AddRune ('a'); - Assert.Equal ((Rune)'a', driver.Contents [0, 0].Rune); + Assert.Equal ("a", driver.Contents [0, 0].Grapheme); Assert.Equal (0, driver.Row); Assert.Equal (1, driver.Col); driver.AddRune ('b'); - Assert.Equal ((Rune)'b', driver.Contents [0, 1].Rune); + Assert.Equal ("b", driver.Contents [0, 1].Grapheme); Assert.Equal (0, driver.Row); Assert.Equal (2, driver.Col); @@ -116,7 +118,7 @@ public void AddRune_MovesToNextColumn () // Add a rune to the last column of the first row; should increment the row or col even though it's now invalid driver.AddRune ('c'); - Assert.Equal ((Rune)'c', driver.Contents [0, lastCol].Rune); + Assert.Equal ("c", driver.Contents [0, lastCol].Grapheme); Assert.Equal (lastCol + 1, driver.Col); // Add a rune; should succeed but do nothing as it's outside of Contents @@ -127,7 +129,7 @@ public void AddRune_MovesToNextColumn () { for (var row = 0; row < driver.Rows; row++) { - Assert.NotEqual ((Rune)'d', driver.Contents [row, col].Rune); + Assert.NotEqual ("d", driver.Contents [row, col].Grapheme); } } @@ -146,12 +148,12 @@ public void AddRune_MovesToNextColumn_Wide () Assert.Equal (2, rune.GetColumns ()); driver.AddRune (rune); - Assert.Equal (rune, driver.Contents [0, 0].Rune); + Assert.Equal (rune.ToString (), driver.Contents [0, 0].Grapheme); Assert.Equal (0, driver.Row); Assert.Equal (2, driver.Col); //driver.AddRune ('b'); - //Assert.Equal ((Rune)'b', driver.Contents [0, 1].Rune); + //Assert.Equal ((Text)'b', driver.Contents [0, 1].Text); //Assert.Equal (0, driver.Row); //Assert.Equal (2, driver.Col); @@ -163,7 +165,7 @@ public void AddRune_MovesToNextColumn_Wide () //// Add a rune to the last column of the first row; should increment the row or col even though it's now invalid //driver.AddRune ('c'); - //Assert.Equal ((Rune)'c', driver.Contents [0, lastCol].Rune); + //Assert.Equal ((Text)'c', driver.Contents [0, lastCol].Text); //Assert.Equal (lastCol + 1, driver.Col); //// Add a rune; should succeed but do nothing as it's outside of Contents @@ -171,7 +173,7 @@ public void AddRune_MovesToNextColumn_Wide () //Assert.Equal (lastCol + 2, driver.Col); //for (var col = 0; col < driver.Cols; col++) { // for (var row = 0; row < driver.Rows; row++) { - // Assert.NotEqual ((Rune)'d', driver.Contents [row, col].Rune); + // Assert.NotEqual ((Text)'d', driver.Contents [row, col].Text); // } //} diff --git a/Tests/UnitTestsParallelizable/Drivers/ContentsTests.cs b/Tests/UnitTestsParallelizable/Drivers/ContentsTests.cs index ceaccc042a..b900ad2065 100644 --- a/Tests/UnitTestsParallelizable/Drivers/ContentsTests.cs +++ b/Tests/UnitTestsParallelizable/Drivers/ContentsTests.cs @@ -36,7 +36,7 @@ public void AddStr_With_Combining_Characters () // a + ogonek + acute = ( ą́ ) var oGonek = new Rune (0x0328); // Combining ogonek (a small hook or comma shape) combined = "a" + oGonek + acuteAccent; - expected = ("a" + oGonek).Normalize (NormalizationForm.FormC); // See Issue #2616 + expected = ("a" + oGonek + acuteAccent).Normalize (NormalizationForm.FormC); // See Issue #2616 driver.Move (0, 0); driver.AddStr (combined); @@ -44,7 +44,7 @@ public void AddStr_With_Combining_Characters () // e + ogonek + acute = ( ę́́ ) combined = "e" + oGonek + acuteAccent; - expected = ("e" + oGonek).Normalize (NormalizationForm.FormC); // See Issue #2616 + expected = ("e" + oGonek + acuteAccent).Normalize (NormalizationForm.FormC); // See Issue #2616 driver.Move (0, 0); driver.AddStr (combined); @@ -52,7 +52,7 @@ public void AddStr_With_Combining_Characters () // i + ogonek + acute = ( į́́́ ) combined = "i" + oGonek + acuteAccent; - expected = ("i" + oGonek).Normalize (NormalizationForm.FormC); // See Issue #2616 + expected = ("i" + oGonek + acuteAccent).Normalize (NormalizationForm.FormC); // See Issue #2616 driver.Move (0, 0); driver.AddStr (combined); @@ -60,7 +60,7 @@ public void AddStr_With_Combining_Characters () // u + ogonek + acute = ( ų́́́́ ) combined = "u" + oGonek + acuteAccent; - expected = ("u" + oGonek).Normalize (NormalizationForm.FormC); // See Issue #2616 + expected = ("u" + oGonek + acuteAccent).Normalize (NormalizationForm.FormC); // See Issue #2616 driver.Move (0, 0); driver.AddStr (combined); diff --git a/Tests/UnitTestsParallelizable/Drivers/DriverTests.cs b/Tests/UnitTestsParallelizable/Drivers/DriverTests.cs index 9f87d80d09..511c7e12f5 100644 --- a/Tests/UnitTestsParallelizable/Drivers/DriverTests.cs +++ b/Tests/UnitTestsParallelizable/Drivers/DriverTests.cs @@ -1,6 +1,52 @@ using UnitTests; +using Xunit.Abstractions; namespace UnitTests_Parallelizable.DriverTests; public class DriverTests : FakeDriverBase -{ } +{ + [Theory] + [InlineData (null, true)] + [InlineData ("", true)] + [InlineData ("a", true)] + [InlineData ("👩‍❤️‍💋‍👨", false)] + public void IsValidLocation (string text, bool positive) + { + IDriver driver = CreateFakeDriver (); + driver.SetScreenSize (10, 10); + + // positive + Assert.True (driver.IsValidLocation (text, 0, 0)); + Assert.True (driver.IsValidLocation (text, 1, 1)); + Assert.Equal (positive, driver.IsValidLocation (text, driver.Cols - 1, driver.Rows - 1)); + + // negative + Assert.False (driver.IsValidLocation (text, -1, 0)); + Assert.False (driver.IsValidLocation (text, 0, -1)); + Assert.False (driver.IsValidLocation (text, -1, -1)); + Assert.False (driver.IsValidLocation (text, driver.Cols, driver.Rows - 1)); + Assert.False (driver.IsValidLocation (text, driver.Cols, driver.Rows - 1)); + Assert.False (driver.IsValidLocation (text, driver.Cols, driver.Rows)); + + // Define a clip rectangle + driver.Clip = new (new Rectangle (5, 5, 5, 5)); + + // positive + Assert.True (driver.IsValidLocation (text, 5, 5)); + Assert.Equal (positive, driver.IsValidLocation (text, 9, 9)); + + // negative + Assert.False (driver.IsValidLocation (text, 4, 5)); + Assert.False (driver.IsValidLocation (text, 5, 4)); + Assert.False (driver.IsValidLocation (text, 10, 9)); + Assert.False (driver.IsValidLocation (text, 9, 10)); + Assert.False (driver.IsValidLocation (text, -1, 0)); + Assert.False (driver.IsValidLocation (text, 0, -1)); + Assert.False (driver.IsValidLocation (text, -1, -1)); + Assert.False (driver.IsValidLocation (text, driver.Cols, driver.Rows - 1)); + Assert.False (driver.IsValidLocation (text, driver.Cols, driver.Rows - 1)); + Assert.False (driver.IsValidLocation (text, driver.Cols, driver.Rows)); + + driver.End (); + } +} diff --git a/Tests/UnitTestsParallelizable/Drivers/FakeDriverTests.cs b/Tests/UnitTestsParallelizable/Drivers/FakeDriverTests.cs index 251a26344d..30ba27be9e 100644 --- a/Tests/UnitTestsParallelizable/Drivers/FakeDriverTests.cs +++ b/Tests/UnitTestsParallelizable/Drivers/FakeDriverTests.cs @@ -155,7 +155,7 @@ public void FakeDriver_Can_Fill_Rectangle () { for (int col = rect.X; col < rect.X + rect.Width; col++) { - Assert.Equal ((Rune)'X', driver.Contents [row, col].Rune); + Assert.Equal ("X", driver.Contents [row, col].Grapheme); } } } diff --git a/Tests/UnitTestsParallelizable/TestSetup.cs b/Tests/UnitTestsParallelizable/TestSetup.cs index 2a6402c119..5379905ba9 100644 --- a/Tests/UnitTestsParallelizable/TestSetup.cs +++ b/Tests/UnitTestsParallelizable/TestSetup.cs @@ -24,8 +24,8 @@ public void Dispose () // Reset application state just in case a test changed something. // TODO: Add an Assert to ensure none of the state of Application changed. // TODO: Add an Assert to ensure none of the state of ConfigurationManager changed. - CheckDefaultState (); Application.ResetState (true); + CheckDefaultState (); } // IMPORTANT: Ensure this matches the code in Init_ResetState_Resets_Properties diff --git a/Tests/UnitTestsParallelizable/Text/RuneTests.cs b/Tests/UnitTestsParallelizable/Text/RuneTests.cs index 34214d6ef8..4e03e8048b 100644 --- a/Tests/UnitTestsParallelizable/Text/RuneTests.cs +++ b/Tests/UnitTestsParallelizable/Text/RuneTests.cs @@ -88,7 +88,7 @@ public void GetColumns_GetRuneCount () 1 )] // the letters 법 join to form the Korean word for "rice:" U+BC95 법 (read from top left to bottom right) [InlineData ("\U0001F468\u200D\U0001F469\u200D\U0001F467", "👨‍👩‍👧", 8, 2, 8)] // Man, Woman and Girl emoji. - [InlineData ("\u0915\u093f", "कि", 2, 1, 2)] // Hindi कि with DEVANAGARI LETTER KA and DEVANAGARI VOWEL SIGN I + //[InlineData ("\u0915\u093f", "कि", 2, 2, 2)] // Hindi कि with DEVANAGARI LETTER KA and DEVANAGARI VOWEL SIGN I [InlineData ( "\u0e4d\u0e32", "ํา", @@ -213,7 +213,7 @@ public void GetColumns_Utf8_Encode (byte [] code, string str, int columns, int s [InlineData ( '\u1161', "ᅡ", - 1, + 0, 1, 3 )] // ᅡ Hangul Jungseong A - Unicode Hangul Jamo for join with column width equal to 0 alone. @@ -231,7 +231,7 @@ public void GetColumns_Utf8_Encode (byte [] code, string str, int columns, int s )] // ䷀Hexagram For The Creative Heaven - U+4dc0 - https://github.com/microsoft/terminal/blob/main/src/types/unicode_width_overrides.xml // See https://github.com/microsoft/terminal/issues/19389 - [InlineData ('\ud7b0', "ힰ", 1, 1, 3)] // ힰ ┤Hangul Jungseong O-Yeo - ힰ U+d7b0')] + [InlineData ('\ud7b0', "ힰ", 0, 1, 3)] // ힰ ┤Hangul Jungseong O-Yeo - ힰ U+d7b0')] [InlineData ('\uf61e', "", 1, 1, 3)] // Private Use Area [InlineData ('\u23f0', "⏰", 2, 1, 3)] // Alarm Clock - ⏰ U+23f0 [InlineData ('\u1100', "ᄀ", 2, 1, 3)] // ᄀ Hangul Choseong Kiyeok @@ -365,6 +365,42 @@ public void Rune_ColumnWidth_Versus_String_ConsoleWidth (string text, int string [InlineData ('\ud801')] public void Rune_Exceptions_Integers (int code) { Assert.Throws (() => new Rune (code)); } + [Theory] + // Control characters (should be mapped to Control Pictures) + [InlineData ('\u0000', 0x2400)] // NULL → ␀ + [InlineData ('\u0009', 0x2409)] // TAB → ␉ + [InlineData ('\u000A', 0x240A)] // LF → ␊ + [InlineData ('\u000D', 0x240D)] // CR → ␍ + + // Printable characters (should remain unchanged) + [InlineData ('A', 'A')] + [InlineData (' ', ' ')] + [InlineData ('~', '~')] + public void MakePrintable_ReturnsExpected (char inputChar, int expectedCodePoint) + { + // Arrange + Rune input = new Rune (inputChar); + + // Act + Rune result = input.MakePrintable (); + + // Assert + Assert.Equal (expectedCodePoint, result.Value); + } + + [Fact] + public void MakePrintable_SupplementaryRune_RemainsUnchanged () + { + // Arrange: supplementary character outside BMP (not a control) + Rune input = new Rune (0x1F600); // 😀 grinning face emoji + + // Act + Rune result = input.MakePrintable (); + + // Assert + Assert.Equal (input.Value, result.Value); + } + [Theory] [InlineData (new [] { '\ud799', '\udc21' })] public void Rune_Exceptions_Utf16_Encode (char [] code) @@ -954,11 +990,9 @@ int txtElementCount Assert.Equal (runeCount, us.GetRuneCount ()); Assert.Equal (stringCount, s.Length); - TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator (s); - var textElementCount = 0; - while (enumerator.MoveNext ()) + foreach (string _ in GraphemeHelper.GetGraphemes (s)) { textElementCount++; // For versions prior to Net5.0 the StringInfo class might handle some grapheme clusters incorrectly. } @@ -1064,4 +1098,95 @@ private bool ProcessTestStringUseChar (string s) return true; } + + [Theory] + [InlineData (0x0041, new byte [] { 0x41 })] // 'A', ASCII + [InlineData (0x00E9, new byte [] { 0xC3, 0xA9 })] // 'é', 2-byte UTF-8 + [InlineData (0x20AC, new byte [] { 0xE2, 0x82, 0xAC })] // '€', 3-byte UTF-8 + [InlineData (0x1F600, new byte [] { 0xF0, 0x9F, 0x98, 0x80 })] // 😀 emoji, 4-byte UTF-8 + public void Encode_WritesExpectedBytes (int codePoint, byte [] expectedBytes) + { + // Arrange + Rune rune = new Rune (codePoint); + byte [] buffer = new byte [10]; // extra space + for (int i = 0; i < buffer.Length; i++) + { + buffer [i] = 0xFF; + } + + // Act + int written = rune.Encode (buffer); + + // Assert + Assert.Equal (expectedBytes.Length, written); + for (int i = 0; i < written; i++) + { + Assert.Equal (expectedBytes [i], buffer [i]); + } + } + + [Fact] + public void Encode_WithStartAndCount_WritesPartialBytes () + { + // Arrange: U+1F600 😀 (4 bytes) + Rune rune = new Rune (0x1F600); + byte [] buffer = new byte [10]; + for (int i = 0; i < buffer.Length; i++) + { + buffer [i] = 0xFF; + } + + // Act: write starting at index 2, limit count to 2 bytes + int written = rune.Encode (buffer, start: 2, count: 2); + + // Assert + Assert.Equal (2, written); + // Original UTF-8 bytes: F0 9F 98 80 + Assert.Equal (0xF0, buffer [2]); + Assert.Equal (0x9F, buffer [3]); + // Remaining buffer untouched + Assert.Equal (0xFF, buffer [0]); + Assert.Equal (0xFF, buffer [1]); + Assert.Equal (0xFF, buffer [4]); + } + + [Fact] + public void Encode_WithCountGreaterThanRuneBytes_WritesAllBytes () + { + // Arrange: é → C3 A9 + Rune rune = new Rune ('é'); + byte [] buffer = new byte [10]; + for (int i = 0; i < buffer.Length; i++) + { + buffer [i] = 0xFF; + } + + // Act: count larger than needed + int written = rune.Encode (buffer, start: 1, count: 10); + + // Assert + Assert.Equal (2, written); + Assert.Equal (0xC3, buffer [1]); + Assert.Equal (0xA9, buffer [2]); + Assert.Equal (0xFF, buffer [3]); // next byte untouched + } + + [Fact] + public void Encode_ZeroCount_WritesNothing () + { + Rune rune = new Rune ('A'); + byte [] buffer = new byte [5]; + for (int i = 0; i < buffer.Length; i++) + { + buffer [i] = 0xFF; + } + + int written = rune.Encode (buffer, start: 0, count: 0); + + Assert.Equal (0, written); + foreach (var b in buffer) + { + Assert.Equal (0xFF, b); // buffer untouched + } + } } diff --git a/Tests/UnitTestsParallelizable/Text/StringTests.cs b/Tests/UnitTestsParallelizable/Text/StringTests.cs index 80c52b96ea..a3c4e52bab 100644 --- a/Tests/UnitTestsParallelizable/Text/StringTests.cs +++ b/Tests/UnitTestsParallelizable/Text/StringTests.cs @@ -4,6 +4,13 @@ public class StringTests { + [Fact] + public void TestGetColumns_Null () + { + string? str = null; + Assert.Equal (0, str!.GetColumns ()); + } + [Fact] public void TestGetColumns_Empty () { @@ -11,6 +18,20 @@ public void TestGetColumns_Empty () Assert.Equal (0, str.GetColumns ()); } + [Fact] + public void TestGetColumns_SingleRune () + { + var str = "a"; + Assert.Equal (1, str.GetColumns ()); + } + + [Fact] + public void TestGetColumns_Zero_Width () + { + var str = "\u200D"; + Assert.Equal (0, str.GetColumns ()); + } + [Theory] [InlineData ("a", 1)] [InlineData ("á", 1)] @@ -30,53 +51,162 @@ public void TestGetColumns_Empty () // Test known wide codepoints [Theory] - [InlineData ("🙂", 2)] - [InlineData ("a🙂", 3)] - [InlineData ("🙂a", 3)] - [InlineData ("👨‍👩‍👦‍👦", 2)] - [InlineData ("👨‍👩‍👦‍👦🙂", 4)] - [InlineData ("👨‍👩‍👦‍👦🙂a", 5)] - [InlineData ("👨‍👩‍👦‍👦a🙂", 5)] - [InlineData ("👨‍👩‍👦‍👦👨‍👩‍👦‍👦", 4)] - [InlineData ("山", 2)] // The character for "mountain" in Chinese/Japanese/Korean (山), Unicode U+5C71 - [InlineData ("山🙂", 4)] // The character for "mountain" in Chinese/Japanese/Korean (山), Unicode U+5C71 - //[InlineData ("\ufe20\ufe21", 2)] // Combining Ligature Left Half ︠ - U+fe20 -https://github.com/microsoft/terminal/blob/main/src/types/unicode_width_overrides.xml - // // Combining Ligature Right Half - U+fe21 -https://github.com/microsoft/terminal/blob/main/src/types/unicode_width_overrides.xml - public void TestGetColumns_MultiRune_WideBMP (string str, int expected) { Assert.Equal (expected, str.GetColumns ()); } + [InlineData ("🙂", 2, 1, 2)] + [InlineData ("a🙂", 3, 2, 3)] + [InlineData ("🙂a", 3, 2, 3)] + [InlineData ("👨‍👩‍👦‍👦", 8, 1, 2)] + [InlineData ("👨‍👩‍👦‍👦🙂", 10, 2, 4)] + [InlineData ("👨‍👩‍👦‍👦🙂a", 11, 3, 5)] + [InlineData ("👨‍👩‍👦‍👦a🙂", 11, 3, 5)] + [InlineData ("👨‍👩‍👦‍👦👨‍👩‍👦‍👦", 16, 2, 4)] + [InlineData ("าำ", 2, 1, 2)] // า U+0E32 - THAI CHARACTER SARA AA with ำ U+0E33 - THAI CHARACTER SARA AM + [InlineData ("山", 2, 1, 2)] // The character for "mountain" in Chinese/Japanese/Korean (山), Unicode U+5C71 + [InlineData ("山🙂", 4, 2, 4)] // The character for "mountain" in Chinese/Japanese/Korean (山), Unicode U+5C71 + [InlineData ("a\ufe20e\ufe21", 2, 2, 2)] // Combining Ligature Left Half ︠ - U+fe20 -https://github.com/microsoft/terminal/blob/main/src/types/unicode_width_overrides.xml + // Combining Ligature Right Half - U+fe21 -https://github.com/microsoft/terminal/blob/main/src/types/unicode_width_overrides.xml + //[InlineData ("क", 1, 1, 1)] // क U+0915 Devanagari Letter Ka + //[InlineData ("ि", 1, 1, 1)] // U+093F Devanagari Vowel Sign I ि (i-kar). + //[InlineData ("कि", 2, 1, 2)] // "कि" is U+0915 for the base consonant "क" with U+093F for the vowel sign "ि" (i-kar). + [InlineData ("ᄀ", 2, 1, 2)] // ᄀ U+1100 HANGUL CHOSEONG KIYEOK (consonant) + [InlineData ("ᅡ", 0, 1, 0)] // ᅡ U+1161 HANGUL JUNGSEONG A (vowel) + [InlineData ("가", 2, 1, 2)] // ᄀ U+1100 HANGUL CHOSEONG KIYEOK (consonant) with ᅡ U+1161 HANGUL JUNGSEONG A (vowel) + [InlineData ("ᄒ", 2, 1, 2)] // ᄒ U+1112 Hangul Choseong Hieuh + [InlineData ("ᅵ", 0, 1, 0)] // ᅵ U+1175 Hangul Jungseong I + [InlineData ("ᇂ", 0, 1, 0)] // ᇂ U+11C2 Hangul Jongseong Hieuh + [InlineData ("힣", 2, 1, 2)] // ᄒ (choseong h) + ᅵ (jungseong i) + ᇂ (jongseong h) + [InlineData ("ힰ", 0, 1, 0)] // U+D7B0 ힰ Hangul Jungseong O-Yeo + [InlineData ("ᄀힰ", 2, 1, 2)] // ᄀ U+1100 HANGUL CHOSEONG KIYEOK (consonant) with U+D7B0 ힰ Hangul Jungseong O-Yeo + //[InlineData ("षि", 2, 1, 2)] // U+0937 ष DEVANAGARI LETTER SSA with U+093F ि COMBINING DEVANAGARI VOWEL SIGN I + public void TestGetColumns_MultiRune_WideBMP_Graphemes (string str, int expectedRunesWidth, int expectedGraphemesCount, int expectedWidth) + { + Assert.Equal (expectedRunesWidth, str.EnumerateRunes ().Sum (r => r.GetColumns ())); + Assert.Equal (expectedGraphemesCount, GraphemeHelper.GetGraphemes (str).ToArray ().Length); + Assert.Equal (expectedWidth, str.GetColumns ()); + } - [Fact] - public void TestGetColumns_Null () + [Theory] + [InlineData (null)] + [InlineData ("")] + public void TestGetColumns_Does_Not_Throws_With_Null_And_Empty_String (string? text) { - string? str = null; - Assert.Equal (0, str!.GetColumns ()); + // ReSharper disable once InvokeAsExtensionMethod + Assert.Equal (0, StringExtensions.GetColumns (text!)); } - [Fact] - public void TestGetColumns_SingleRune () + public class ReadOnlySpanExtensionsTests { - var str = "a"; - Assert.Equal (1, str.GetColumns ()); + [Theory] + [InlineData ("12345", true)] // all ASCII digits + [InlineData ("0", true)] // single ASCII digit + [InlineData ("", false)] // empty span + [InlineData ("12a45", false)] // contains a letter + [InlineData ("123", false)] // full-width Unicode digits (not ASCII) + [InlineData ("12 34", false)] // contains space + [InlineData ("١٢٣", false)] // Arabic-Indic digits + public void IsAllAsciiDigits_WorksAsExpected (string input, bool expected) + { + // Arrange + ReadOnlySpan span = input.AsSpan (); + + // Act + bool result = span.IsAllAsciiDigits (); + + // Assert + Assert.Equal (expected, result); + } } - [Fact] - public void TestGetColumns_Zero_Width () + [Theory] + [InlineData ("0", true)] + [InlineData ("9", true)] + [InlineData ("A", true)] + [InlineData ("F", true)] + [InlineData ("a", true)] + [InlineData ("f", true)] + [InlineData ("123ABC", true)] + [InlineData ("abcdef", true)] + [InlineData ("G", false)] // 'G' not hex + [InlineData ("Z9", false)] // 'Z' not hex + [InlineData ("12 34", false)] // space not hex + [InlineData ("", false)] // empty string + [InlineData ("123", false)] // full-width digits, not ASCII + [InlineData ("0xFF", false)] // includes 'x' + public void IsAllAsciiHexDigits_ReturnsExpected (string input, bool expected) { - var str = "\u200D"; - Assert.Equal (0, str.GetColumns ()); + // Arrange + ReadOnlySpan span = input.AsSpan (); + + // Act + bool result = span.IsAllAsciiHexDigits (); + + // Assert + Assert.Equal (expected, result); } [Theory] - [InlineData (null)] - [InlineData ("")] - public void TestGetColumns_Does_Not_Throws_With_Null_And_Empty_String (string? text) + [MemberData (nameof (GetStringConcatCases))] + public void ToString_ReturnsExpected (IEnumerable input, string expected) { - if (text is null) - { - Assert.Equal (0, StringExtensions.GetColumns (text!)); - } - else - { - Assert.Equal (0, text.GetColumns ()); - } + // Act + string result = StringExtensions.ToString (input); + + // Assert + Assert.Equal (expected, result); + } + + public static IEnumerable GetStringConcatCases () + { + yield return [new string [] { }, string.Empty]; // Empty sequence + yield return [new [] { "" }, string.Empty]; // Single empty string + yield return [new [] { "A" }, "A"]; // Single element + yield return [new [] { "A", "B" }, "AB"]; // Simple concatenation + yield return [new [] { "Hello", " ", "World" }, "Hello World"]; // Multiple parts + yield return [new [] { "123", "456", "789" }, "123456789"]; // Numeric strings + yield return [new [] { "👩‍", "🧒" }, "👩‍🧒"]; // Grapheme sequence + yield return [new [] { "α", "β", "γ" }, "αβγ"]; // Unicode letters + yield return [new [] { "A", null, "B" }, "AB"]; // Null ignored by string.Concat + } + + [Theory] + [InlineData ("", false)] // Empty string + [InlineData ("A", false)] // Single BMP character + [InlineData ("AB", false)] // Two BMP chars, not a surrogate pair + [InlineData ("👩", true)] // Single emoji surrogate pair (U+1F469) + [InlineData ("🧒", true)] // Another emoji surrogate pair (U+1F9D2) + [InlineData ("𐍈", true)] // Gothic letter hwair (U+10348) + [InlineData ("A👩", false)] // One BMP + one surrogate half + [InlineData ("👩‍", false)] // Surrogate pair + ZWJ (length != 2) + public void IsSurrogatePair_ReturnsExpected (string input, bool expected) + { + // Act + bool result = input.IsSurrogatePair (); + + // Assert + Assert.Equal (expected, result); + } + + [Theory] + // Control characters (should be replaced with the "Control Pictures" block) + [InlineData ("\u0000", "\u2400")] // NULL → ␀ + [InlineData ("\u0009", "\u2409")] // TAB → ␉ + [InlineData ("\u000A", "\u240A")] // LF → ␊ + [InlineData ("\u000D", "\u240D")] // CR → ␍ + + // Printable characters (should remain unchanged) + [InlineData ("A", "A")] + [InlineData (" ", " ")] + [InlineData ("~", "~")] + + // Multi-character string (should return unchanged) + [InlineData ("AB", "AB")] + [InlineData ("Hello", "Hello")] + [InlineData ("\u0009A", "\u0009A")] // includes a control char, but length > 1 + public void MakePrintable_ReturnsExpected (string input, string expected) + { + // Act + string result = input.MakePrintable (); + + // Assert + Assert.Equal (expected, result); } } diff --git a/Tests/UnitTestsParallelizable/Text/TextFormatterDrawTests.cs b/Tests/UnitTestsParallelizable/Text/TextFormatterDrawTests.cs index 0c142f08b2..34db80c7eb 100644 --- a/Tests/UnitTestsParallelizable/Text/TextFormatterDrawTests.cs +++ b/Tests/UnitTestsParallelizable/Text/TextFormatterDrawTests.cs @@ -665,5 +665,32 @@ string expectedDraw DriverAssert.AssertDriverContentsWithFrameAre (expectedDraw, output, driver); } + [Theory] + [InlineData ("\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466", 2, 1, TextDirection.LeftRight_TopBottom, "👨‍👩‍👧‍👦")] + [InlineData ("\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466", 2, 1, TextDirection.TopBottom_LeftRight, "👨‍👩‍👧‍👦")] + public void Draw_Emojis_With_Zero_Width_Joiner ( + string text, + int width, + int height, + TextDirection direction, + string expectedDraw + ) + { + IDriver driver = CreateFakeDriver (); + + TextFormatter tf = new () + { + Direction = direction, + ConstrainToSize = new (width, height), + Text = text, + WordWrap = false + }; + Assert.Equal (width, text.GetColumns ()); + + tf.Draw (new (0, 0, width, height), Attribute.Default, Attribute.Default, driver: driver); + + DriverAssert.AssertDriverContentsWithFrameAre (expectedDraw, output, driver); + } + #endregion } diff --git a/Tests/UnitTestsParallelizable/Text/TextFormatterTests.cs b/Tests/UnitTestsParallelizable/Text/TextFormatterTests.cs index 88e95fd7f2..f9e72f4dd8 100644 --- a/Tests/UnitTestsParallelizable/Text/TextFormatterTests.cs +++ b/Tests/UnitTestsParallelizable/Text/TextFormatterTests.cs @@ -792,19 +792,16 @@ public void GetColumnsRequiredForVerticalText_List_With_Combining_Runes () [MemberData (nameof (CMGlyphs))] public void GetLengthThatFits_List_Simple_And_Wide_Runes (string text, int columns, int expectedLength) { - List runes = text.ToRuneList (); - Assert.Equal (expectedLength, TextFormatter.GetLengthThatFits (runes, columns)); + Assert.Equal (expectedLength, TextFormatter.GetLengthThatFits (text, columns)); } [Theory] [InlineData ("test", 3, 3)] [InlineData ("test", 4, 4)] [InlineData ("test", 10, 4)] - public void GetLengthThatFits_Runelist (string text, int columns, int expectedLength) + public void GetLengthThatFits_For_String (string text, int columns, int expectedLength) { - List runes = text.ToRuneList (); - - Assert.Equal (expectedLength, TextFormatter.GetLengthThatFits (runes, columns)); + Assert.Equal (expectedLength, TextFormatter.GetLengthThatFits (text, columns)); } [Theory] @@ -833,7 +830,7 @@ public void GetLengthThatFits_String (string text, int columns, int expectedLeng public void GetLengthThatFits_With_Combining_Runes () { var text = "Les Mise\u0328\u0301rables"; - Assert.Equal (16, TextFormatter.GetLengthThatFits (text, 14)); + Assert.Equal (14, TextFormatter.GetLengthThatFits (text, 14)); } [Fact] @@ -2761,8 +2758,7 @@ IEnumerable resultLines "ฮ", "ฯ", "ะั", - "า", - "ำ" + "าำ" } )] public void WordWrap_Unicode_SingleWordLine ( @@ -2797,7 +2793,17 @@ IEnumerable resultLines Assert.True ( expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0) ); - Assert.Equal (resultLines, wrappedLines); + + if (maxWidth == 1) + { + List newResultLines = resultLines.ToList (); + newResultLines [^1] = ""; + Assert.Equal (newResultLines, wrappedLines); + } + else + { + Assert.Equal (resultLines, wrappedLines); + } } /// WordWrap strips CRLF @@ -3074,8 +3080,8 @@ public void Draw_Horizontal_Right (string text, int width, string expectedText) } [Theory] - [InlineData (14, 1, TextDirection.LeftRight_TopBottom, "Les Misęrables")] - [InlineData (1, 14, TextDirection.TopBottom_LeftRight, "L\ne\ns\n \nM\ni\ns\nę\nr\na\nb\nl\ne\ns")] + [InlineData (14, 1, TextDirection.LeftRight_TopBottom, "Les Misę́rables")] + [InlineData (1, 14, TextDirection.TopBottom_LeftRight, "L\ne\ns\n \nM\ni\ns\nę́\nr\na\nb\nl\ne\ns")] [InlineData ( 4, 4, @@ -3084,7 +3090,7 @@ public void Draw_Horizontal_Right (string text, int width, string expectedText) LMre eias ssb - ęl " + ę́l " )] public void Draw_With_Combining_Runes (int width, int height, TextDirection textDirection, string expected) { @@ -3111,7 +3117,6 @@ public void Draw_With_Combining_Runes (int width, int height, TextDirection text driver.End (); } - [Theory] [InlineData (17, 1, TextDirection.LeftRight_TopBottom, 4, "This is a Tab")] [InlineData (1, 17, TextDirection.TopBottom_LeftRight, 4, "T\nh\ni\ns\n \ni\ns\n \na\n \n \n \n \n \nT\na\nb")] @@ -3189,7 +3194,6 @@ string expected driver.End (); } - [Theory] [InlineData (17, 1, TextDirection.LeftRight_TopBottom, 4, "This is a Tab")] [InlineData (1, 17, TextDirection.TopBottom_LeftRight, 4, "T\nh\ni\ns\n \ni\ns\n \na\n \n \n \n \n \nT\na\nb")] @@ -3227,5 +3231,4 @@ string expected driver.End (); } - } diff --git a/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs b/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs index a5362f46fc..9a1bd2dfac 100644 --- a/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs +++ b/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs @@ -626,7 +626,7 @@ string GetContents () for (var i = 0; i < 16; i++) { - item += driver.Contents [0, i]!.Rune; + item += driver.Contents [0, i]!.Grapheme; } return item; diff --git a/Tests/UnitTestsParallelizable/Views/TextViewTests.cs b/Tests/UnitTestsParallelizable/Views/TextViewTests.cs index 8ea0df071f..a9b940bea4 100644 --- a/Tests/UnitTestsParallelizable/Views/TextViewTests.cs +++ b/Tests/UnitTestsParallelizable/Views/TextViewTests.cs @@ -1444,23 +1444,23 @@ void AssertRedGreenAttribute () public void Internal_Tests () { var txt = "This is a text."; - List txtRunes = Cell.StringToCells (txt); - Assert.Equal (txt.Length, txtRunes.Count); - Assert.Equal ('T', txtRunes [0].Rune.Value); - Assert.Equal ('h', txtRunes [1].Rune.Value); - Assert.Equal ('i', txtRunes [2].Rune.Value); - Assert.Equal ('s', txtRunes [3].Rune.Value); - Assert.Equal (' ', txtRunes [4].Rune.Value); - Assert.Equal ('i', txtRunes [5].Rune.Value); - Assert.Equal ('s', txtRunes [6].Rune.Value); - Assert.Equal (' ', txtRunes [7].Rune.Value); - Assert.Equal ('a', txtRunes [8].Rune.Value); - Assert.Equal (' ', txtRunes [9].Rune.Value); - Assert.Equal ('t', txtRunes [10].Rune.Value); - Assert.Equal ('e', txtRunes [11].Rune.Value); - Assert.Equal ('x', txtRunes [12].Rune.Value); - Assert.Equal ('t', txtRunes [13].Rune.Value); - Assert.Equal ('.', txtRunes [^1].Rune.Value); + List txtStrings = Cell.StringToCells (txt); + Assert.Equal (txt.Length, txtStrings.Count); + Assert.Equal ("T", txtStrings [0].Grapheme); + Assert.Equal ("h", txtStrings [1].Grapheme); + Assert.Equal ("i", txtStrings [2].Grapheme); + Assert.Equal ("s", txtStrings [3].Grapheme); + Assert.Equal (" ", txtStrings [4].Grapheme); + Assert.Equal ("i", txtStrings [5].Grapheme); + Assert.Equal ("s", txtStrings [6].Grapheme); + Assert.Equal (" ", txtStrings [7].Grapheme); + Assert.Equal ("a", txtStrings [8].Grapheme); + Assert.Equal (" ", txtStrings [9].Grapheme); + Assert.Equal ("t", txtStrings [10].Grapheme); + Assert.Equal ("e", txtStrings [11].Grapheme); + Assert.Equal ("x", txtStrings [12].Grapheme); + Assert.Equal ("t", txtStrings [13].Grapheme); + Assert.Equal (".", txtStrings [^1].Grapheme); var col = 0; Assert.True (TextModel.SetCol (ref col, 80, 79)); @@ -1469,19 +1469,19 @@ public void Internal_Tests () var start = 0; var x = 8; - Assert.Equal (8, TextModel.GetColFromX (txtRunes, start, x)); - Assert.Equal ('a', txtRunes [start + x].Rune.Value); + Assert.Equal (8, TextModel.GetColFromX (txtStrings, start, x)); + Assert.Equal ("a", txtStrings [start + x].Grapheme); start = 1; x = 7; - Assert.Equal (7, TextModel.GetColFromX (txtRunes, start, x)); - Assert.Equal ('a', txtRunes [start + x].Rune.Value); + Assert.Equal (7, TextModel.GetColFromX (txtStrings, start, x)); + Assert.Equal ("a", txtStrings [start + x].Grapheme); - Assert.Equal ((15, 15), TextModel.DisplaySize (txtRunes)); - Assert.Equal ((6, 6), TextModel.DisplaySize (txtRunes, 1, 7)); + Assert.Equal ((15, 15), TextModel.DisplaySize (txtStrings)); + Assert.Equal ((6, 6), TextModel.DisplaySize (txtStrings, 1, 7)); - Assert.Equal (0, TextModel.CalculateLeftColumn (txtRunes, 0, 7, 8)); - Assert.Equal (1, TextModel.CalculateLeftColumn (txtRunes, 0, 8, 8)); - Assert.Equal (2, TextModel.CalculateLeftColumn (txtRunes, 0, 9, 8)); + Assert.Equal (0, TextModel.CalculateLeftColumn (txtStrings, 0, 7, 8)); + Assert.Equal (1, TextModel.CalculateLeftColumn (txtStrings, 0, 8, 8)); + Assert.Equal (2, TextModel.CalculateLeftColumn (txtStrings, 0, 9, 8)); var tm = new TextModel (); tm.AddLine (0, Cell.StringToCells ("This is first line.")); @@ -2050,9 +2050,9 @@ public void Equals_True () Assert.True (c1.Equals (c2)); Assert.True (c2.Equals (c1)); - c1.Rune = new ('a'); + c1.Grapheme = new ("a"); c1.Attribute = new (); - c2.Rune = new ('a'); + c2.Grapheme = new ("a"); c2.Attribute = new (); Assert.True (c1.Equals (c2)); Assert.True (c2.Equals (c1)); @@ -2063,10 +2063,10 @@ public void Cell_LoadCells_Without_Scheme_Is_Never_Null () { List cells = new () { - new () { Rune = new ('T') }, - new () { Rune = new ('e') }, - new () { Rune = new ('s') }, - new () { Rune = new ('t') } + new () { Grapheme = new ("T") }, + new () { Grapheme = new ("e") }, + new () { Grapheme = new ("s") }, + new () { Grapheme = new ("t") } }; TextView tv = CreateTextView (); var top = new Toplevel ();