From dbbe3f7424a9f1c34cd5ced55001652c8fbedad8 Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 3 Dec 2024 04:11:02 +0000 Subject: [PATCH 01/19] Fixes #2616. Support combining sequences that don't normalize. --- Terminal.Gui/Application/Application.cs | 24 +++++++++--- Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs | 38 ++++++------------- .../CursesDriver/CursesDriver.cs | 11 +++--- .../ConsoleDrivers/NetDriver/NetDriver.cs | 11 +++--- .../WindowsDriver/WindowsConsole.cs | 9 +++++ .../WindowsDriver/WindowsDriver.cs | 14 +++++++ Terminal.Gui/Drawing/Cell.cs | 12 ++---- UICatalog/Scenarios/CombiningMarks.cs | 18 +++++++-- UnitTests/ConsoleDrivers/AddRuneTests.cs | 8 +++- UnitTests/ConsoleDrivers/ContentsTests.cs | 8 ++-- UnitTests/TestHelpers.cs | 25 +++++++++--- UnitTests/Text/TextFormatterTests.cs | 6 +-- 12 files changed, 115 insertions(+), 69 deletions(-) diff --git a/Terminal.Gui/Application/Application.cs b/Terminal.Gui/Application/Application.cs index 77a53de2a4..6aa68d0c9b 100644 --- a/Terminal.Gui/Application/Application.cs +++ b/Terminal.Gui/Application/Application.cs @@ -67,6 +67,25 @@ public static string ToString (IConsoleDriver? driver) { sb.Append (sp); } + else if (contents [r, c].CombiningMarks is { 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. + string combine = rune.ToString (); + string? normalized = null; + + foreach (Rune combMark in contents [r, c].CombiningMarks) + { + combine += combMark; + normalized = combine.Normalize (NormalizationForm.FormC); + } + + sb.Append (normalized); + } else { sb.Append ((char)rune.Value); @@ -76,11 +95,6 @@ public static string ToString (IConsoleDriver? driver) { c++; } - - // See Issue #2616 - //foreach (var combMark in contents [r, c].CombiningMarks) { - // sb.Append ((char)combMark.Value); - //} } sb.AppendLine (); diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs index f64de17fc9..59ec509711 100644 --- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs @@ -208,35 +208,19 @@ public void AddRune (Rune rune) // b) Ignoring any CMs that don't normalize if (Col > 0) { - if (Contents [Row, Col - 1].CombiningMarks.Count > 0) + for (int i = Col; i > 0; i--) { - // Just add this mark to the list - Contents [Row, Col - 1].CombiningMarks.Add (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 (); - - // Normalize to Form C (Canonical Composition) - string normalized = combined.Normalize (NormalizationForm.FormC); - - if (normalized.Length == 1) + if (!Contents [Row, i - 1].Rune.IsCombiningMark ()) { - // It normalized! We can just set the Cell to the left with the - // normalized codepoint - Contents [Row, Col - 1].Rune = (Rune)normalized [0]; - - // 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].CombiningMarks.Add (rune); - - // Ignore. Don't move to next column (let the driver figure out what to do). + if (Contents [Row, i - 1].CombiningMarks is null) + { + Contents [Row, i - 1].CombiningMarks = []; + } + // Just add this mark to the list + Contents [Row, i - 1].CombiningMarks.Add (rune); + Debug.Assert (Contents [Row, i - 1].CombiningMarks.Count > 0); + + break; } } diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 43330eab3b..8284680942 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -319,7 +319,7 @@ public override bool UpdateScreen () Rune rune = Contents [row, col].Rune; output.Append (rune); - if (Contents [row, col].CombiningMarks.Count > 0) + if (Contents [row, col].CombiningMarks is { 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) @@ -327,10 +327,11 @@ public override bool UpdateScreen () // 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); - //} - // WriteToConsole (output, ref lastCol, row, ref outputWidth); + foreach (var combMark in Contents [row, col].CombiningMarks) + { + output.Append (combMark); + } + WriteToConsole (output, ref lastCol, row, ref outputWidth); } else if (rune.IsSurrogatePair () && rune.GetColumns () < 2) { diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs index 62c6db94b8..e58ff10020 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs @@ -167,7 +167,7 @@ public override bool UpdateScreen () Rune rune = Contents [row, col].Rune; output.Append (rune); - if (Contents [row, col].CombiningMarks.Count > 0) + if (Contents [row, col].CombiningMarks is { 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) @@ -175,10 +175,11 @@ public override bool UpdateScreen () // 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); - //} - // WriteToConsole (output, ref lastCol, row, ref outputWidth); + foreach (var combMark in Contents [row, col].CombiningMarks) + { + output.Append (combMark); + } + WriteToConsole (output, ref lastCol, row, ref outputWidth); } else if (rune.IsSurrogatePair () && rune.GetColumns () < 2) { diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs index 2c6689737f..63d2a79fcb 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs @@ -197,6 +197,14 @@ public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord { _stringBuilder.Append (info.Char); } + + if (info.CombiningMarks is { }) + { + foreach (var combMark in info.CombiningMarks) + { + _stringBuilder.Append (combMark); + } + } } else { @@ -785,6 +793,7 @@ public struct ExtendedCharInfo public char Char { get; set; } public Attribute Attribute { get; set; } public bool Empty { get; set; } // TODO: Temp hack until virtual terminal sequences + internal List? CombiningMarks; public ExtendedCharInfo (char character, Attribute attribute) { diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs index 251ad4dad9..115c6db0c9 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs @@ -356,6 +356,20 @@ public override bool UpdateScreen () _outputBuffer [position].Empty = false; + if (Contents [row, col].CombiningMarks is { Count: > 0 }) + { + _outputBuffer [position].CombiningMarks = []; + + foreach (var combMark in Contents [row, col].CombiningMarks) + { + _outputBuffer [position].CombiningMarks!.Add ((char)combMark.Value); + } + } + else + { + _outputBuffer [position].CombiningMarks = null; + } + if (Contents [row, col].Rune.IsBmp) { _outputBuffer [position].Char = (char)Contents [row, col].Rune.Value; diff --git a/Terminal.Gui/Drawing/Cell.cs b/Terminal.Gui/Drawing/Cell.cs index 5ce4e21df5..d769265609 100644 --- a/Terminal.Gui/Drawing/Cell.cs +++ b/Terminal.Gui/Drawing/Cell.cs @@ -4,7 +4,7 @@ /// 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, Rune Rune = default, List CombiningMarks = null) { /// The attributes to use when drawing the Glyph. public Attribute? Attribute { get; set; } = Attribute; @@ -23,13 +23,11 @@ public Rune Rune get => _rune; set { - CombiningMarks.Clear (); + CombiningMarks = null; _rune = value; } } - private List _combiningMarks; - /// /// The combining marks for that when combined makes this Cell a combining sequence. If /// empty, then is ignored. @@ -38,11 +36,7 @@ public Rune Rune /// Only valid in the rare case where is a combining sequence that could not be normalized to a /// single Rune. /// - internal List CombiningMarks - { - get => _combiningMarks ?? []; - private set => _combiningMarks = value ?? []; - } + internal List CombiningMarks { get; set; } = CombiningMarks; /// public override string ToString () { return $"[{Rune}, {Attribute}]"; } diff --git a/UICatalog/Scenarios/CombiningMarks.cs b/UICatalog/Scenarios/CombiningMarks.cs index d351982513..bca5a8bf01 100644 --- a/UICatalog/Scenarios/CombiningMarks.cs +++ b/UICatalog/Scenarios/CombiningMarks.cs @@ -16,9 +16,9 @@ public override void Main () top.Move (0, 0); top.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616."); top.Move (0, 2); - top.AddStr ("\u0301\u0301\u0328<- \"\\u301\\u301\\u328]\" using AddStr."); + top.AddStr ("\u0301\u0301\u0328<- \"\\u0301\\u0301\\u0328]\" using AddStr."); top.Move (0, 3); - top.AddStr ("[a\u0301\u0301\u0328]<- \"[a\\u301\\u301\\u328]\" using AddStr."); + top.AddStr ("[a\u0301\u0301\u0328]<- \"[a\\u0301\\u0301\\u0328]\" using AddStr."); top.Move (0, 4); top.AddRune ('['); top.AddRune ('a'); @@ -26,7 +26,19 @@ public override void Main () top.AddRune ('\u0301'); top.AddRune ('\u0328'); top.AddRune (']'); - top.AddStr ("<- \"[a\\u301\\u301\\u328]\" using AddRune for each."); + top.AddStr ("<- \"[a\\u0301\\u0301\\u0328]\" using AddRune for each."); + top.Move (0, 6); + top.AddStr ("[e\u0301\u0301\u0328]<- \"[e\\u0301\\u0301\\u0328]\" using AddStr."); + top.Move (0, 7); + top.AddStr ("[e\u0301\u0328\u0301]<- \"[e\\u0301\\u0328\\u0301]\" using AddStr."); + top.Move (0, 8); + top.AddStr ("[e\u0328\u0301]<- \"[e\\u0328\\u0301]\" using AddStr."); + top.Move (0, 10); + top.AddStr ("From now on we are using Text Formatter"); + TextFormatter tf = new () { Text = "[e\u0301\u0301\u0328]<- \"[e\\u0301\\u0301\\u0328]\" using TextFormatter." }; + tf.Draw (new (0, 11, tf.Text.Length, 1), top.ColorScheme.Normal, top.ColorScheme.Normal); + tf.Text = "[e\u0328\u0301]<- \"[e\\u0328\\u0301]\" using TextFormatter."; + tf.Draw (new (0, 12, tf.Text.Length, 1), top.ColorScheme.Normal, top.ColorScheme.Normal); }; Application.Run (top); diff --git a/UnitTests/ConsoleDrivers/AddRuneTests.cs b/UnitTests/ConsoleDrivers/AddRuneTests.cs index 5c753386ee..ed624b495c 100644 --- a/UnitTests/ConsoleDrivers/AddRuneTests.cs +++ b/UnitTests/ConsoleDrivers/AddRuneTests.cs @@ -55,7 +55,9 @@ public void AddRune_Accented_Letter_With_Three_Combining_Unicode_Chars () text = "\u0103\u0301"; driver.AddStr (text); - Assert.Equal (expected, driver.Contents [0, 0].Rune); + Assert.Single (driver.Contents [0, 0].CombiningMarks); + string combined = driver.Contents [0, 0].Rune + driver.Contents [0, 0].CombiningMarks [0].ToString (); + Assert.Equal (expected, (Rune)combined.Normalize (NormalizationForm.FormC) [0]); Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); driver.ClearContents (); @@ -63,7 +65,9 @@ public void AddRune_Accented_Letter_With_Three_Combining_Unicode_Chars () text = "\u0061\u0306\u0301"; driver.AddStr (text); - Assert.Equal (expected, driver.Contents [0, 0].Rune); + Assert.Equal (2, driver.Contents [0, 0].CombiningMarks.Count); + combined = driver.Contents [0, 0].Rune + driver.Contents [0, 0].CombiningMarks [0].ToString () + driver.Contents [0, 0].CombiningMarks [1]; + Assert.Equal (expected, (Rune)combined.Normalize (NormalizationForm.FormC) [0]); Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune); // var s = "a\u0301\u0300\u0306"; diff --git a/UnitTests/ConsoleDrivers/ContentsTests.cs b/UnitTests/ConsoleDrivers/ContentsTests.cs index d0f2d83ff7..f0e2cb91f0 100644 --- a/UnitTests/ConsoleDrivers/ContentsTests.cs +++ b/UnitTests/ConsoleDrivers/ContentsTests.cs @@ -56,7 +56,7 @@ public void AddStr_With_Combining_Characters (Type driverType) // 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 = ("á" + ogonek).Normalize (NormalizationForm.FormC); // See Issue #2616 driver.Move (0, 0); driver.AddStr (combined); @@ -64,7 +64,7 @@ public void AddStr_With_Combining_Characters (Type driverType) // e + ogonek + acute = ( ę́́ ) combined = "e" + ogonek + acuteaccent; - expected = ("e" + ogonek).Normalize (NormalizationForm.FormC); // See Issue #2616 + expected = ("é" + ogonek).Normalize (NormalizationForm.FormC); // See Issue #2616 driver.Move (0, 0); driver.AddStr (combined); @@ -72,7 +72,7 @@ public void AddStr_With_Combining_Characters (Type driverType) // i + ogonek + acute = ( į́́́ ) combined = "i" + ogonek + acuteaccent; - expected = ("i" + ogonek).Normalize (NormalizationForm.FormC); // See Issue #2616 + expected = ("í" + ogonek).Normalize (NormalizationForm.FormC); // See Issue #2616 driver.Move (0, 0); driver.AddStr (combined); @@ -80,7 +80,7 @@ public void AddStr_With_Combining_Characters (Type driverType) // u + ogonek + acute = ( ų́́́́ ) combined = "u" + ogonek + acuteaccent; - expected = ("u" + ogonek).Normalize (NormalizationForm.FormC); // See Issue #2616 + expected = ("ú" + ogonek).Normalize (NormalizationForm.FormC); // See Issue #2616 driver.Move (0, 0); driver.AddStr (combined); diff --git a/UnitTests/TestHelpers.cs b/UnitTests/TestHelpers.cs index 3f32e35b5a..415c0b20bb 100644 --- a/UnitTests/TestHelpers.cs +++ b/UnitTests/TestHelpers.cs @@ -411,7 +411,7 @@ public static Rectangle AssertDriverContentsWithFrameAre ( colIndex++; } - if (colIndex + 1 > w) + if (colIndex + 1 > w && !runeAtCurrentLocation.IsCombiningMark ()) { w = colIndex + 1; } @@ -419,15 +419,28 @@ public static Rectangle AssertDriverContentsWithFrameAre ( h = rowIndex - y + 1; } - if (x > -1) + if (x > -1 && contents [rowIndex, colIndex].CombiningMarks is null) { runes.Add (runeAtCurrentLocation); } - // See Issue #2616 - //foreach (var combMark in contents [r, c].CombiningMarks) { - // runes.Add (combMark); - //} + if (contents [rowIndex, colIndex].CombiningMarks is { Count: > 0 }) + { + string combine = runeAtCurrentLocation.ToString (); + string? normalized = null; + + // See Issue #2616 + foreach (var combMark in contents [rowIndex, colIndex].CombiningMarks) + { + combine += combMark; + normalized = combine.Normalize (NormalizationForm.FormC); + } + + foreach (Rune enumerateRune in normalized!.EnumerateRunes ()) + { + runes.Add (enumerateRune); + } + } } if (runes.Count > 0) diff --git a/UnitTests/Text/TextFormatterTests.cs b/UnitTests/Text/TextFormatterTests.cs index d83ab398f2..b1f8a97876 100644 --- a/UnitTests/Text/TextFormatterTests.cs +++ b/UnitTests/Text/TextFormatterTests.cs @@ -4114,8 +4114,8 @@ public void Draw_Vertical_TopBottom_LeftRight_Top (string text, int height, stri } [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, @@ -4124,7 +4124,7 @@ public void Draw_Vertical_TopBottom_LeftRight_Top (string text, int height, stri LMre eias ssb - ęl " + ę́l " )] public void Draw_With_Combining_Runes (int width, int height, TextDirection textDirection, string expected) { From cc5ca9e4308dc3579a98e2e57a652e54bd6f507c Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 5 Dec 2024 00:53:49 +0000 Subject: [PATCH 02/19] Trying to deal with non-bmp. --- Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs | 16 ++--- .../WindowsDriver/WindowsDriver.cs | 28 ++++++-- Terminal.Gui/Text/RuneExtensions.cs | 3 +- UICatalog/Scenarios/CombiningMarks.cs | 65 +++++++++++-------- 4 files changed, 68 insertions(+), 44 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs index 59ec509711..cdafe9c5bd 100644 --- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs @@ -210,7 +210,7 @@ public void AddRune (Rune rune) { for (int i = Col; i > 0; i--) { - if (!Contents [Row, i - 1].Rune.IsCombiningMark ()) + if (!Contents [Row, i - 1].Rune.IsCombiningMark () && Contents [Row, i - 1].Rune.Value != ' ') { if (Contents [Row, i - 1].CombiningMarks is null) { @@ -282,13 +282,13 @@ public void AddRune (Rune rune) { Contents [Row, Col].Rune = rune; - 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].IsDirty = true; - } + //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].IsDirty = true; + //} } } else diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs index 115c6db0c9..9493fc1b30 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs @@ -377,16 +377,30 @@ public override bool UpdateScreen () else { //_outputBuffer [position].Empty = true; - _outputBuffer [position].Char = (char)Rune.ReplacementChar.Value; + //_outputBuffer [position].Char = (char)Rune.ReplacementChar.Value; + var rune = Contents [row, col].Rune; + char [] surrogatePair = rune.ToString ().ToCharArray (); + Debug.Assert (surrogatePair.Length == 2); + _outputBuffer [position].Char = surrogatePair [0]; - if (Contents [row, col].Rune.GetColumns () > 1 && col + 1 < Cols) + if (_outputBuffer [position].CombiningMarks == null) + { + _outputBuffer [position].CombiningMarks = []; + _outputBuffer [position].CombiningMarks!.Add (surrogatePair [1]); + } + else { - // TODO: This is a hack to deal with non-BMP and wide characters. - col++; - position = row * Cols + col; - _outputBuffer [position].Empty = false; - _outputBuffer [position].Char = ' '; + _outputBuffer [position].CombiningMarks!.Insert (0, surrogatePair [1]); } + + //if (Contents [row, col].Rune.GetColumns () > 1 && col + 1 < Cols) + //{ + // // TODO: This is a hack to deal with non-BMP and wide characters. + // col++; + // position = row * Cols + col; + // _outputBuffer [position].Empty = false; + // _outputBuffer [position].Char = ' '; + //} } } } diff --git a/Terminal.Gui/Text/RuneExtensions.cs b/Terminal.Gui/Text/RuneExtensions.cs index 835dba6791..e6912f4c22 100644 --- a/Terminal.Gui/Text/RuneExtensions.cs +++ b/Terminal.Gui/Text/RuneExtensions.cs @@ -129,7 +129,8 @@ public static bool IsCombiningMark (this Rune rune) return Rune.GetUnicodeCategory (rune) == UnicodeCategory.NonSpacingMark || category == UnicodeCategory.SpacingCombiningMark - || category == UnicodeCategory.EnclosingMark; + || category == UnicodeCategory.EnclosingMark + || category == UnicodeCategory.Format; } /// Reports whether a rune is a surrogate code point. diff --git a/UICatalog/Scenarios/CombiningMarks.cs b/UICatalog/Scenarios/CombiningMarks.cs index bca5a8bf01..a597e8a24b 100644 --- a/UICatalog/Scenarios/CombiningMarks.cs +++ b/UICatalog/Scenarios/CombiningMarks.cs @@ -12,34 +12,43 @@ public override void Main () var top = new Toplevel (); top.DrawComplete += (s, e) => - { - top.Move (0, 0); - top.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616."); - top.Move (0, 2); - top.AddStr ("\u0301\u0301\u0328<- \"\\u0301\\u0301\\u0328]\" using AddStr."); - top.Move (0, 3); - top.AddStr ("[a\u0301\u0301\u0328]<- \"[a\\u0301\\u0301\\u0328]\" using AddStr."); - top.Move (0, 4); - top.AddRune ('['); - top.AddRune ('a'); - top.AddRune ('\u0301'); - top.AddRune ('\u0301'); - top.AddRune ('\u0328'); - top.AddRune (']'); - top.AddStr ("<- \"[a\\u0301\\u0301\\u0328]\" using AddRune for each."); - top.Move (0, 6); - top.AddStr ("[e\u0301\u0301\u0328]<- \"[e\\u0301\\u0301\\u0328]\" using AddStr."); - top.Move (0, 7); - top.AddStr ("[e\u0301\u0328\u0301]<- \"[e\\u0301\\u0328\\u0301]\" using AddStr."); - top.Move (0, 8); - top.AddStr ("[e\u0328\u0301]<- \"[e\\u0328\\u0301]\" using AddStr."); - top.Move (0, 10); - top.AddStr ("From now on we are using Text Formatter"); - TextFormatter tf = new () { Text = "[e\u0301\u0301\u0328]<- \"[e\\u0301\\u0301\\u0328]\" using TextFormatter." }; - tf.Draw (new (0, 11, tf.Text.Length, 1), top.ColorScheme.Normal, top.ColorScheme.Normal); - tf.Text = "[e\u0328\u0301]<- \"[e\\u0328\\u0301]\" using TextFormatter."; - tf.Draw (new (0, 12, tf.Text.Length, 1), top.ColorScheme.Normal, top.ColorScheme.Normal); - }; + { + var i = -1; + top.Move (0, ++i); + top.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616."); + top.Move (0, ++i); + top.AddStr ("\u0301\u0301\u0328<- \"\\u0301\\u0301\\u0328]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[a\u0301\u0301\u0328]<- \"[a\\u0301\\u0301\\u0328]\" using AddStr."); + top.Move (0, ++i); + top.AddRune ('['); + top.AddRune ('a'); + top.AddRune ('\u0301'); + top.AddRune ('\u0301'); + top.AddRune ('\u0328'); + top.AddRune (']'); + top.AddStr ("<- \"[a\\u0301\\u0301\\u0328]\" using AddRune for each."); + top.Move (0, ++i + 1); + top.AddStr ("[e\u0301\u0301\u0328]<- \"[e\\u0301\\u0301\\u0328]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[e\u0301\u0328\u0301]<- \"[e\\u0301\\u0328\\u0301]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[e\u0328\u0301]<- \"[e\\u0328\\u0301]\" using AddStr."); + i++; + top.Move (0, ++i); + top.AddStr ("From now on we are using TextFormatter"); + TextFormatter tf = new () { Text = "[e\u0301\u0301\u0328]<- \"[e\\u0301\\u0301\\u0328]\" using TextFormatter." }; + tf.Draw (new (0, ++i, tf.Text.Length, 1), top.ColorScheme.Normal, top.ColorScheme.Normal); + tf.Text = "[e\u0328\u0301]<- \"[e\\u0328\\u0301]\" using TextFormatter."; + tf.Draw (new (0, ++i, tf.Text.Length, 1), top.ColorScheme.Normal, top.ColorScheme.Normal); + i++; + top.Move (0, ++i); + top.AddStr ("From now on we are using Surrogate pairs with combining diacritics"); + top.Move (0, ++i); + top.AddStr ("[\ud835\udc4b\u0302]<- \"[\\ud835\\udc4b\\u0302]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\ud83e\uddd1\u200d\ud83e\uddd2]<- \"[\\ud83e\\uddd1\\u200d\\ud83e\\uddd2]\" using AddStr."); + }; Application.Run (top); top.Dispose (); From 42db5c98ea56bc6d05c2acba616f838c7a00d020 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 5 Dec 2024 00:58:45 +0000 Subject: [PATCH 03/19] Fix for WindowsDriver. --- .../WindowsDriver/WindowsDriver.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs index 9493fc1b30..dc6ae21540 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs @@ -393,14 +393,14 @@ public override bool UpdateScreen () _outputBuffer [position].CombiningMarks!.Insert (0, surrogatePair [1]); } - //if (Contents [row, col].Rune.GetColumns () > 1 && col + 1 < Cols) - //{ - // // TODO: This is a hack to deal with non-BMP and wide characters. - // col++; - // position = row * Cols + col; - // _outputBuffer [position].Empty = false; - // _outputBuffer [position].Char = ' '; - //} + if (Contents [row, col].Rune.GetColumns () > 1 && col + 1 < Cols) + { + // TODO: This is a hack to deal with non-BMP and wide characters. + col++; + position = row * Cols + col; + _outputBuffer [position].Empty = false; + _outputBuffer [position].Char = '\0'; + } } } } From 9b2f8b779c0085f706271ec21e63bc0b7bcbcc97 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 5 Dec 2024 12:39:19 +0000 Subject: [PATCH 04/19] Re-enables ReplacementChar because it's more adequate. --- Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs index cdafe9c5bd..16ed03b1a5 100644 --- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs @@ -210,7 +210,7 @@ public void AddRune (Rune rune) { for (int i = Col; i > 0; i--) { - if (!Contents [Row, i - 1].Rune.IsCombiningMark () && Contents [Row, i - 1].Rune.Value != ' ') + if (!Contents [Row, i - 1].Rune.IsCombiningMark () && Contents [Row, i - 1].Rune != Rune.ReplacementChar) { if (Contents [Row, i - 1].CombiningMarks is null) { @@ -282,13 +282,13 @@ public void AddRune (Rune rune) { Contents [Row, Col].Rune = rune; - //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].IsDirty = true; - //} + 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].IsDirty = true; + } } } else From 84b337f6dbb1e8299ecef51e88bf4ee6583bfcf8 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 5 Dec 2024 14:57:14 +0000 Subject: [PATCH 05/19] Prevents throwing an exception if the token was canceled after wait. --- Terminal.Gui/ConsoleDrivers/NetDriver/NetMainLoop.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver/NetMainLoop.cs b/Terminal.Gui/ConsoleDrivers/NetDriver/NetMainLoop.cs index 32e7c53dbd..ca0a670a19 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver/NetMainLoop.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver/NetMainLoop.cs @@ -142,6 +142,11 @@ private void NetInputHandler () _waitForProbe.Reset (); } + if (_inputHandlerTokenSource.IsCancellationRequested) + { + return; + } + ProcessInputQueue (); } catch (OperationCanceledException) From 264cccb1c0b871725e914882fc789e30952101d2 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 5 Dec 2024 15:53:33 +0000 Subject: [PATCH 06/19] Now it's rendering surrogate pairs better, but still needs to figure out how to remove empty columns. --- Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs | 9 +++------ .../ConsoleDrivers/CursesDriver/CursesDriver.cs | 17 +++++++++++------ .../ConsoleDrivers/NetDriver/NetDriver.cs | 17 +++++++++++------ UICatalog/Scenarios/CombiningMarks.cs | 6 ++++++ 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs index 16ed03b1a5..0477a6f5cf 100644 --- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs @@ -317,13 +317,10 @@ public void AddRune (Rune rune) 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; + // Col now points to the second column of the character. Ensure it does get + // rendered to allow the driver to handle it in its own way. + Contents [Row, Col].IsDirty = true; Contents [Row, Col].Attribute = CurrentAttribute; - - // TODO: Determine if we should wipe this out (for now now) - //Contents [Row, Col].Rune = (Rune)' '; } } diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 8284680942..22b60a466a 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -317,6 +317,11 @@ public override bool UpdateScreen () outputWidth++; Rune rune = Contents [row, col].Rune; + + if (rune == Rune.ReplacementChar) + { + continue; + } output.Append (rune); if (Contents [row, col].CombiningMarks is { Count: > 0 }) @@ -331,13 +336,13 @@ public override bool UpdateScreen () { output.Append (combMark); } - WriteToConsole (output, ref lastCol, row, ref outputWidth); - } - else if (rune.IsSurrogatePair () && rune.GetColumns () < 2) - { - WriteToConsole (output, ref lastCol, row, ref outputWidth); - SetCursorPosition (col - 1, row); + //WriteToConsole (output, ref lastCol, row, ref outputWidth); } + //else if (rune.IsSurrogatePair () && rune.GetColumns () < 2) + //{ + // WriteToConsole (output, ref lastCol, row, ref outputWidth); + // SetCursorPosition (col - 1, row); + //} Contents [row, col].IsDirty = false; } diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs index e58ff10020..b3aea4241a 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs @@ -165,6 +165,11 @@ public override bool UpdateScreen () outputWidth++; Rune rune = Contents [row, col].Rune; + + if (rune == Rune.ReplacementChar) + { + continue; + } output.Append (rune); if (Contents [row, col].CombiningMarks is { Count: > 0 }) @@ -179,13 +184,13 @@ public override bool UpdateScreen () { output.Append (combMark); } - WriteToConsole (output, ref lastCol, row, ref outputWidth); - } - else if (rune.IsSurrogatePair () && rune.GetColumns () < 2) - { - WriteToConsole (output, ref lastCol, row, ref outputWidth); - SetCursorPosition (col - 1, row); + //WriteToConsole (output, ref lastCol, row, ref outputWidth); } + //else if (rune.IsSurrogatePair () && rune.GetColumns () < 2) + //{ + // WriteToConsole (output, ref lastCol, row, ref outputWidth); + // SetCursorPosition (col - 1, row); + //} Contents [row, col].IsDirty = false; } diff --git a/UICatalog/Scenarios/CombiningMarks.cs b/UICatalog/Scenarios/CombiningMarks.cs index a597e8a24b..474d07b022 100644 --- a/UICatalog/Scenarios/CombiningMarks.cs +++ b/UICatalog/Scenarios/CombiningMarks.cs @@ -47,7 +47,13 @@ public override void Main () top.Move (0, ++i); top.AddStr ("[\ud835\udc4b\u0302]<- \"[\\ud835\\udc4b\\u0302]\" using AddStr."); top.Move (0, ++i); + top.AddStr ("[\ud83e\uddd1\ud83e\uddd2]<- \"[\\ud83e\\uddd1\\ud83e\\uddd2]\" using AddStr."); + top.Move (0, ++i); top.AddStr ("[\ud83e\uddd1\u200d\ud83e\uddd2]<- \"[\\ud83e\\uddd1\\u200d\\ud83e\\uddd2]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\U0001F9D1\U0001F9D2]<- \"[\\U0001F9D1\\U0001F9D2]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\U0001F9D1\u200D\U0001F9D2]<- \"[\\U0001F9D1\\u200D\\U0001F9D2]\" using AddStr."); }; Application.Run (top); From d5c7625f499ab80ec8d0dda6ab3d88f81e85cfe8 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 5 Dec 2024 21:06:26 +0000 Subject: [PATCH 07/19] Remove unnecessary fields. --- Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs | 1 - Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsMainLoop.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs index 63d2a79fcb..6d878387f7 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs @@ -10,7 +10,6 @@ internal class WindowsConsole { private CancellationTokenSource? _inputReadyCancellationTokenSource; private readonly BlockingCollection _inputQueue = new (new ConcurrentQueue ()); - internal WindowsMainLoop? _mainLoop; public const int STD_OUTPUT_HANDLE = -11; public const int STD_INPUT_HANDLE = -10; diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsMainLoop.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsMainLoop.cs index f1ffafdca0..73f4f8e07d 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsMainLoop.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsMainLoop.cs @@ -36,7 +36,6 @@ public WindowsMainLoop (IConsoleDriver consoleDriver) if (!ConsoleDriver.RunningUnitTests) { _winConsole = ((WindowsDriver)consoleDriver).WinConsole; - _winConsole!._mainLoop = this; } } From 0d4759c4c6ef1bdfbac91c0d7e76b0b64d5d2a73 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 5 Dec 2024 23:06:23 +0000 Subject: [PATCH 08/19] Improve the NetDriver and CursesDriver. --- Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs | 13 +++- .../CursesDriver/CursesDriver.cs | 10 ++++ .../ConsoleDrivers/NetDriver/NetDriver.cs | 10 ++++ UICatalog/Scenarios/CharacterMap/CharMap.cs | 60 +++++++++---------- 4 files changed, 62 insertions(+), 31 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs index 0477a6f5cf..8e268e4f4e 100644 --- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs @@ -1,6 +1,7 @@ #nullable enable using System.Diagnostics; +using System.Globalization; namespace Terminal.Gui; @@ -48,6 +49,10 @@ public abstract class ConsoleDriver : IConsoleDriver // This is in addition to the dirty flag on each cell. internal bool []? _dirtyLines; + // Represent the necessary space character that must be added at + // the end of the line due the use of Format (Cf) unicode category + internal int []? _lineColsOffset; + // QUESTION: When non-full screen apps are supported, will this represent the app size, or will that be in Application? /// Gets the location and size of the terminal screen. public Rectangle Screen => new (0, 0, Cols, Rows); @@ -196,7 +201,7 @@ public void AddRune (Rune rune) lock (Contents) { - if (runeWidth == 0 && rune.IsCombiningMark ()) + if (Rune.GetUnicodeCategory (rune) == UnicodeCategory.Format || (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) @@ -226,6 +231,11 @@ public void AddRune (Rune rune) Contents [Row, Col - 1].Attribute = CurrentAttribute; Contents [Row, Col - 1].IsDirty = true; + + if (runeWidth == 0 && Rune.GetUnicodeCategory (rune) == UnicodeCategory.Format) + { + _lineColsOffset! [Row]++; + } } else { @@ -396,6 +406,7 @@ public void ClearContents () Clip = new (Screen); _dirtyLines = new bool [Rows]; + _lineColsOffset = new int [Rows]; lock (Contents) { diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 22b60a466a..7e5e938ddc 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -348,6 +348,16 @@ public override bool UpdateScreen () } } + if (_lineColsOffset! [row] > 0) + { + for (var i = 0; i < _lineColsOffset [row]; i++) + { + output.Append (' '); + } + + _lineColsOffset! [row] = 0; + } + if (output.Length > 0) { SetCursorPosition (lastCol, row); diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs index b3aea4241a..c85dfed196 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs @@ -196,6 +196,16 @@ public override bool UpdateScreen () } } + if (_lineColsOffset! [row] > 0) + { + for (var i = 0; i < _lineColsOffset [row]; i++) + { + output.Append (' '); + } + + _lineColsOffset! [row] = 0; + } + if (output.Length > 0) { SetCursorPosition (lastCol, row); diff --git a/UICatalog/Scenarios/CharacterMap/CharMap.cs b/UICatalog/Scenarios/CharacterMap/CharMap.cs index 8b7d283ad9..2f4c8bd5fa 100644 --- a/UICatalog/Scenarios/CharacterMap/CharMap.cs +++ b/UICatalog/Scenarios/CharacterMap/CharMap.cs @@ -376,37 +376,37 @@ protected override bool OnDrawingContent () if (!ShowGlyphWidths || (y + Viewport.Y) % _rowHeight > 0) { // Draw the rune - if (width > 0) - { + //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 - { - AddRune (Rune.ReplacementChar); - } - } - } + //} + //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 + // { + // AddRune (Rune.ReplacementChar); + // } + // } + //} } else { From 79746e97bcdc55fe880682ae42671a9e5d483999 Mon Sep 17 00:00:00 2001 From: BDisp Date: Sun, 8 Dec 2024 00:39:56 +0000 Subject: [PATCH 09/19] Ensure using a valid cell to add combining marks. --- Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs | 71 ++++++++++++------- UICatalog/Scenarios/CharacterMap/CharMap.cs | 6 ++ .../Scenarios/CharacterMap/UnicodeRange.cs | 2 +- UICatalog/Scenarios/CombiningMarks.cs | 39 +++++++--- 4 files changed, 83 insertions(+), 35 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs index 2a7ab8bd8a..929678015e 100644 --- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs @@ -174,6 +174,13 @@ public virtual int Rows /// The topmost row in the terminal. public virtual int Top { get; set; } = 0; + /// + /// Gets or sets whenever is ignored or not. + /// + public static bool IgnoreIsCombiningMark { get; set; } + + private Point? _lastValidAddRuneCell = null; + /// Adds the specified rune to the display at the current cursor position. /// /// @@ -190,15 +197,15 @@ public virtual int Rows /// Rune to add. public void AddRune (Rune rune) { - int runeWidth = -1; - bool validLocation = IsValidLocation (rune, Col, Row); - if (Contents is null) { return; } + int runeWidth = -1; + bool validLocation = IsValidLocation (rune, Col, Row); Rectangle clipRect = Clip!.GetBounds (); + bool wasAddedToCombiningMarks = false; if (validLocation) { @@ -217,31 +224,28 @@ public void AddRune (Rune rune) // 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 (Col > 0 + && _lastValidAddRuneCell is { } + && _lastValidAddRuneCell.Value.Y == Row + && Contents [Row, _lastValidAddRuneCell.Value.X].IsDirty) { - for (int i = Col; i > 0; i--) + if (Contents [Row, _lastValidAddRuneCell.Value.X].CombiningMarks is null) { - if (!Contents [Row, i - 1].Rune.IsCombiningMark () && Contents [Row, i - 1].Rune != Rune.ReplacementChar) - { - if (Contents [Row, i - 1].CombiningMarks is null) - { - Contents [Row, i - 1].CombiningMarks = []; - } - // Just add this mark to the list - Contents [Row, i - 1].CombiningMarks.Add (rune); - Debug.Assert (Contents [Row, i - 1].CombiningMarks.Count > 0); - - break; - } + Contents [Row, _lastValidAddRuneCell.Value.X].CombiningMarks = []; } - Contents [Row, Col - 1].Attribute = CurrentAttribute; - Contents [Row, Col - 1].IsDirty = true; + // Just add this mark to the list + Contents [Row, _lastValidAddRuneCell.Value.X].CombiningMarks.Add (rune); + wasAddedToCombiningMarks = true; - if (runeWidth == 0 && Rune.GetUnicodeCategory (rune) == UnicodeCategory.Format) + //if (runeWidth == 0 && Rune.GetUnicodeCategory (rune) == UnicodeCategory.Format) + if (runeWidth == 0) { _lineColsOffset! [Row]++; } + + Contents [Row, _lastValidAddRuneCell.Value.X].Attribute = CurrentAttribute; + Contents [Row, _lastValidAddRuneCell.Value.X].IsDirty = true; } else { @@ -249,7 +253,11 @@ public void AddRune (Rune rune) Contents [Row, Col].Rune = rune; Contents [Row, Col].Attribute = CurrentAttribute; Contents [Row, Col].IsDirty = true; - Col++; + + if (runeWidth == 0) + { + Col++; + } } } else @@ -319,7 +327,20 @@ public void AddRune (Rune rune) } } - if (runeWidth is < 0 or > 0) + switch (IgnoreIsCombiningMark) + { + case false when _lastValidAddRuneCell is { } && !wasAddedToCombiningMarks: + case false when _lastValidAddRuneCell is null && !wasAddedToCombiningMarks: + _lastValidAddRuneCell = new (Col, Row); + + break; + case true: + _lastValidAddRuneCell = null; + + break; + } + + if (runeWidth is < 0 or > 0 && !wasAddedToCombiningMarks) { Col++; } @@ -406,6 +427,7 @@ public void FillRect (Rectangle rect, Rune rune = default) public void ClearContents () { Contents = new Cell [Rows, Cols]; + _lastValidAddRuneCell = null; //CONCURRENCY: Unsynchronized access to Clip isn't safe. // TODO: ClearContents should not clear the clip; it should only clear the contents. Move clearing it elsewhere. @@ -491,11 +513,8 @@ public bool IsValidLocation (Rune rune, int col, int row) { return col >= 0 && row >= 0 && col < Cols && row < Rows && Clip!.Contains (col, row); } - else - { - return Clip!.Contains (col, row) || Clip!.Contains (col + 1, row); - } + return Clip!.Contains (col, row) || Clip!.Contains (col + 1, row); } /// Called when the terminal size changes. Fires the event. diff --git a/UICatalog/Scenarios/CharacterMap/CharMap.cs b/UICatalog/Scenarios/CharacterMap/CharMap.cs index 2f4c8bd5fa..4f24f570c9 100644 --- a/UICatalog/Scenarios/CharacterMap/CharMap.cs +++ b/UICatalog/Scenarios/CharacterMap/CharMap.cs @@ -299,6 +299,8 @@ public bool ShowGlyphWidths protected override bool OnDrawingContent () { + ConsoleDriver.IgnoreIsCombiningMark = true; + if (Viewport.Height == 0 || Viewport.Width == 0) { return true; @@ -346,6 +348,8 @@ protected override bool OnDrawingContent () Move (firstColumnX + COLUMN_WIDTH, y); SetAttribute (GetNormalColor ()); + bool lastWasNonSpacingMark = false; + for (var col = 0; col < 16; col++) { int x = firstColumnX + COLUMN_WIDTH * col + 1; @@ -437,6 +441,8 @@ protected override bool OnDrawingContent () } } + ConsoleDriver.IgnoreIsCombiningMark = false; + return true; } diff --git a/UICatalog/Scenarios/CharacterMap/UnicodeRange.cs b/UICatalog/Scenarios/CharacterMap/UnicodeRange.cs index 686823486c..25d7237394 100644 --- a/UICatalog/Scenarios/CharacterMap/UnicodeRange.cs +++ b/UICatalog/Scenarios/CharacterMap/UnicodeRange.cs @@ -7,7 +7,7 @@ namespace UICatalog.Scenarios; /// -/// Represents all of the Uniicode ranges.from System.Text.Unicode.UnicodeRange plus +/// Represents all the Unicode ranges from System.Text.Unicode.UnicodeRange plus /// the non-BMP ranges not included. /// public class UnicodeRange (int start, int end, string category) diff --git a/UICatalog/Scenarios/CombiningMarks.cs b/UICatalog/Scenarios/CombiningMarks.cs index 474d07b022..1b229b133f 100644 --- a/UICatalog/Scenarios/CombiningMarks.cs +++ b/UICatalog/Scenarios/CombiningMarks.cs @@ -17,7 +17,17 @@ public override void Main () top.Move (0, ++i); top.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616."); top.Move (0, ++i); - top.AddStr ("\u0301\u0301\u0328<- \"\\u0301\\u0301\\u0328]\" using AddStr."); + top.AddStr ("\u0301<- \"\\u0301\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\u0301]<- \"[\\u0301]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[ \u0301]<- \"[ \\u0301]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\u0301 ]<- \"[\\u0301 ]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("\u0301\u0301\u0328<- \"\\u0301\\u0301\\u0328\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\u0301\u0301\u0328]<- \"[\\u0301\\u0301\\u0328]\" using AddStr."); top.Move (0, ++i); top.AddStr ("[a\u0301\u0301\u0328]<- \"[a\\u0301\\u0301\\u0328]\" using AddStr."); top.Move (0, ++i); @@ -28,12 +38,21 @@ public override void Main () top.AddRune ('\u0328'); top.AddRune (']'); top.AddStr ("<- \"[a\\u0301\\u0301\\u0328]\" using AddRune for each."); - top.Move (0, ++i + 1); - top.AddStr ("[e\u0301\u0301\u0328]<- \"[e\\u0301\\u0301\\u0328]\" using AddStr."); top.Move (0, ++i); - top.AddStr ("[e\u0301\u0328\u0301]<- \"[e\\u0301\\u0328\\u0301]\" using AddStr."); + top.AddStr ("[a\u0301\u0301\u0328]<- \"[a\\u0301\\u0301\\u0328]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[e\u0301\u0301\u0328]<- \"[e\\u0301\\u0301\\u0328]\" using AddStr."); top.Move (0, ++i); top.AddStr ("[e\u0328\u0301]<- \"[e\\u0328\\u0301]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("\u00ad<- \"\\u00ad\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\u00ad]<- \"[\\u00ad]\" using AddStr."); + top.Move (0, ++i); + top.AddRune ('['); + top.AddRune ('\u00ad'); + top.AddRune (']'); + top.AddStr ("<- \"[\\u00ad]\" using AddRune for each."); i++; top.Move (0, ++i); top.AddStr ("From now on we are using TextFormatter"); @@ -47,13 +66,17 @@ public override void Main () top.Move (0, ++i); top.AddStr ("[\ud835\udc4b\u0302]<- \"[\\ud835\\udc4b\\u0302]\" using AddStr."); top.Move (0, ++i); - top.AddStr ("[\ud83e\uddd1\ud83e\uddd2]<- \"[\\ud83e\\uddd1\\ud83e\\uddd2]\" using AddStr."); + top.AddStr ("[\ud83d\udc68\ud83e\uddd2]<- \"[\\ud83d\\udc68\\ud83e\\uddd2]\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("\u200d<- \"\\u200d\" using AddStr."); + top.Move (0, ++i); + top.AddStr ("[\u200d]<- \"[\\u200d]\" using AddStr."); top.Move (0, ++i); - top.AddStr ("[\ud83e\uddd1\u200d\ud83e\uddd2]<- \"[\\ud83e\\uddd1\\u200d\\ud83e\\uddd2]\" using AddStr."); + top.AddStr ("[\ud83d\udc68\u200d\ud83e\uddd2]<- \"[\\ud83d\\udc68\\u200d\\ud83e\\uddd2]\" using AddStr."); top.Move (0, ++i); - top.AddStr ("[\U0001F9D1\U0001F9D2]<- \"[\\U0001F9D1\\U0001F9D2]\" using AddStr."); + top.AddStr ("[\U0001F469\U0001F9D2]<- \"[\\U0001F469\\U0001F9D2]\" using AddStr."); top.Move (0, ++i); - top.AddStr ("[\U0001F9D1\u200D\U0001F9D2]<- \"[\\U0001F9D1\\u200D\\U0001F9D2]\" using AddStr."); + top.AddStr ("[\U0001F469\u200D\U0001F9D2]<- \"[\\U0001F469\\u200D\\U0001F9D2]\" using AddStr."); }; Application.Run (top); From d9e0ef64150c979a82737ce8c0f643e80e8fa91a Mon Sep 17 00:00:00 2001 From: BDisp Date: Sun, 8 Dec 2024 01:09:22 +0000 Subject: [PATCH 10/19] Fix NetDriver and CursesDriver combining marks. --- Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs | 9 +++++++++ Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 5069505442..51b257e7b6 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -323,8 +323,17 @@ public override bool UpdateScreen () { continue; } + output.Append (rune); + if (rune.IsCombiningMark ()) + { + if (rune.GetColumns () == 0) + { + output.Append (' '); + } + } + if (Contents [row, col].CombiningMarks is { Count: > 0 }) { // AtlasEngine does not support NON-NORMALIZED combining marks in a way diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs index 9ed9ab5bee..140e748555 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs @@ -171,8 +171,17 @@ public override bool UpdateScreen () { continue; } + output.Append (rune); + if (rune.IsCombiningMark ()) + { + if (rune.GetColumns () == 0) + { + output.Append (' '); + } + } + if (Contents [row, col].CombiningMarks is { Count: > 0 }) { // AtlasEngine does not support NON-NORMALIZED combining marks in a way From edd05456011b812d17fb94a67ad136bb7ca0b252 Mon Sep 17 00:00:00 2001 From: BDisp Date: Sun, 8 Dec 2024 01:19:47 +0000 Subject: [PATCH 11/19] Trying to fix WindowsDriver combining marks. --- .../ConsoleDrivers/WindowsDriver/WindowsConsole.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs index 6d878387f7..abe5a373af 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs @@ -197,6 +197,14 @@ public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord _stringBuilder.Append (info.Char); } + if (Rune.IsValid (info.Char) && ((Rune)info.Char).IsCombiningMark ()) + { + if (((Rune)info.Char).GetColumns () == 0) + { + _stringBuilder.Append (' '); + } + } + if (info.CombiningMarks is { }) { foreach (var combMark in info.CombiningMarks) From 93d75c804235e0ba062c5be995f5317b1ff54dbb Mon Sep 17 00:00:00 2001 From: BDisp Date: Sun, 8 Dec 2024 12:51:03 +0000 Subject: [PATCH 12/19] Add family glyph. --- UICatalog/Scenarios/CombiningMarks.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/UICatalog/Scenarios/CombiningMarks.cs b/UICatalog/Scenarios/CombiningMarks.cs index 1b229b133f..4d68bea20e 100644 --- a/UICatalog/Scenarios/CombiningMarks.cs +++ b/UICatalog/Scenarios/CombiningMarks.cs @@ -77,6 +77,10 @@ public override void Main () top.AddStr ("[\U0001F469\U0001F9D2]<- \"[\\U0001F469\\U0001F9D2]\" using AddStr."); top.Move (0, ++i); top.AddStr ("[\U0001F469\u200D\U0001F9D2]<- \"[\\U0001F469\\u200D\\U0001F9D2]\" using AddStr."); + top.Move (0, ++i); + 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."); }; Application.Run (top); From 963797c4caf78448cb7d6d14365402d7a532fa2f Mon Sep 17 00:00:00 2001 From: BDisp Date: Sun, 8 Dec 2024 13:03:13 +0000 Subject: [PATCH 13/19] Remove unused variable. --- UICatalog/Scenarios/CharacterMap/CharMap.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/UICatalog/Scenarios/CharacterMap/CharMap.cs b/UICatalog/Scenarios/CharacterMap/CharMap.cs index 4f24f570c9..fbc1fae63e 100644 --- a/UICatalog/Scenarios/CharacterMap/CharMap.cs +++ b/UICatalog/Scenarios/CharacterMap/CharMap.cs @@ -348,8 +348,6 @@ protected override bool OnDrawingContent () Move (firstColumnX + COLUMN_WIDTH, y); SetAttribute (GetNormalColor ()); - bool lastWasNonSpacingMark = false; - for (var col = 0; col < 16; col++) { int x = firstColumnX + COLUMN_WIDTH * col + 1; From 519b452e6f0317632cc4865a821b7b40883e863c Mon Sep 17 00:00:00 2001 From: BDisp Date: Sun, 8 Dec 2024 19:40:00 +0000 Subject: [PATCH 14/19] Fix UnicodeCategory.Format with width zero because six columns can only occupy two columns. --- Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs | 5 ++--- UICatalog/Scenarios/CombiningMarks.cs | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs index 929678015e..aa2265243b 100644 --- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs @@ -238,10 +238,9 @@ public void AddRune (Rune rune) Contents [Row, _lastValidAddRuneCell.Value.X].CombiningMarks.Add (rune); wasAddedToCombiningMarks = true; - //if (runeWidth == 0 && Rune.GetUnicodeCategory (rune) == UnicodeCategory.Format) - if (runeWidth == 0) + if (runeWidth == 0 && Rune.GetUnicodeCategory (rune) == UnicodeCategory.Format) { - _lineColsOffset! [Row]++; + _lineColsOffset! [Row] += Contents [Row, _lastValidAddRuneCell.Value.X].Rune.GetColumns (); } Contents [Row, _lastValidAddRuneCell.Value.X].Attribute = CurrentAttribute; diff --git a/UICatalog/Scenarios/CombiningMarks.cs b/UICatalog/Scenarios/CombiningMarks.cs index 4d68bea20e..89f178133d 100644 --- a/UICatalog/Scenarios/CombiningMarks.cs +++ b/UICatalog/Scenarios/CombiningMarks.cs @@ -13,6 +13,9 @@ public override void Main () top.DrawComplete += (s, e) => { + // Forces reset _lineColsOffset because we're dealing with direct draw + Application.ClearScreenNextIteration = true; + var i = -1; top.Move (0, ++i); top.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616."); From 17d3b0de64f4b6c3ec05d97ecc192c66692bf116 Mon Sep 17 00:00:00 2001 From: BDisp Date: Fri, 13 Dec 2024 15:19:07 +0000 Subject: [PATCH 15/19] Fix combining marks issue if IgnoreIsCombiningMark is false. --- Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs | 12 ++---------- UnitTests/ConsoleDrivers/ContentsTests.cs | 4 ++++ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs index aa2265243b..462ff09c16 100644 --- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs @@ -326,17 +326,9 @@ public void AddRune (Rune rune) } } - switch (IgnoreIsCombiningMark) + if (!IgnoreIsCombiningMark && !wasAddedToCombiningMarks) { - case false when _lastValidAddRuneCell is { } && !wasAddedToCombiningMarks: - case false when _lastValidAddRuneCell is null && !wasAddedToCombiningMarks: - _lastValidAddRuneCell = new (Col, Row); - - break; - case true: - _lastValidAddRuneCell = null; - - break; + _lastValidAddRuneCell = new (Col, Row); } if (runeWidth is < 0 or > 0 && !wasAddedToCombiningMarks) diff --git a/UnitTests/ConsoleDrivers/ContentsTests.cs b/UnitTests/ConsoleDrivers/ContentsTests.cs index f0e2cb91f0..6299c3a7f3 100644 --- a/UnitTests/ConsoleDrivers/ContentsTests.cs +++ b/UnitTests/ConsoleDrivers/ContentsTests.cs @@ -58,6 +58,7 @@ public void AddStr_With_Combining_Characters (Type driverType) combined = "a" + ogonek + acuteaccent; expected = ("á" + ogonek).Normalize (NormalizationForm.FormC); // See Issue #2616 + driver.ClearContents (); driver.Move (0, 0); driver.AddStr (combined); TestHelpers.AssertDriverContentsAre (expected, output, driver); @@ -66,6 +67,7 @@ public void AddStr_With_Combining_Characters (Type driverType) combined = "e" + ogonek + acuteaccent; expected = ("é" + ogonek).Normalize (NormalizationForm.FormC); // See Issue #2616 + driver.ClearContents (); driver.Move (0, 0); driver.AddStr (combined); TestHelpers.AssertDriverContentsAre (expected, output, driver); @@ -74,6 +76,7 @@ public void AddStr_With_Combining_Characters (Type driverType) combined = "i" + ogonek + acuteaccent; expected = ("í" + ogonek).Normalize (NormalizationForm.FormC); // See Issue #2616 + driver.ClearContents (); driver.Move (0, 0); driver.AddStr (combined); TestHelpers.AssertDriverContentsAre (expected, output, driver); @@ -82,6 +85,7 @@ public void AddStr_With_Combining_Characters (Type driverType) combined = "u" + ogonek + acuteaccent; expected = ("ú" + ogonek).Normalize (NormalizationForm.FormC); // See Issue #2616 + driver.ClearContents (); driver.Move (0, 0); driver.AddStr (combined); TestHelpers.AssertDriverContentsAre (expected, output, driver); From 7279a34d06f6afbb753a89b51c72732e35174a76 Mon Sep 17 00:00:00 2001 From: BDisp Date: Fri, 13 Dec 2024 18:02:07 +0000 Subject: [PATCH 16/19] Fix combining marks in the Application.ToString method. --- Terminal.Gui/Application/Application.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Terminal.Gui/Application/Application.cs b/Terminal.Gui/Application/Application.cs index fcf3d22d1f..315b2bbc06 100644 --- a/Terminal.Gui/Application/Application.cs +++ b/Terminal.Gui/Application/Application.cs @@ -84,7 +84,10 @@ public static string ToString (IConsoleDriver? driver) normalized = combine.Normalize (NormalizationForm.FormC); } - sb.Append (normalized); + foreach (Rune enumerateRune in normalized!.EnumerateRunes ()) + { + sb.Append (enumerateRune); + } } else { From 476a41d9961e47275a538ee70c1d394f02152084 Mon Sep 17 00:00:00 2001 From: BDisp Date: Fri, 13 Dec 2024 18:03:00 +0000 Subject: [PATCH 17/19] Fix unit test that was sometime causing failure. --- UnitTests/View/Draw/AllViewsDrawTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/UnitTests/View/Draw/AllViewsDrawTests.cs b/UnitTests/View/Draw/AllViewsDrawTests.cs index fa865068bf..f9e6c806ac 100644 --- a/UnitTests/View/Draw/AllViewsDrawTests.cs +++ b/UnitTests/View/Draw/AllViewsDrawTests.cs @@ -51,5 +51,7 @@ public void AllViews_Draw_Does_Not_Layout (Type viewType) Assert.Equal (1, layoutStartedCount); Assert.Equal (1, layoutCompleteCount); } + + Application.ResetState (true); } } From 36f492f2b24eba621a187682c9ad7e55c4784ce3 Mon Sep 17 00:00:00 2001 From: BDisp Date: Fri, 13 Dec 2024 18:12:55 +0000 Subject: [PATCH 18/19] Fix test that also was causing failing. --- UnitTests/Application/ApplicationScreenTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UnitTests/Application/ApplicationScreenTests.cs b/UnitTests/Application/ApplicationScreenTests.cs index f53bf8531b..9410f218e7 100644 --- a/UnitTests/Application/ApplicationScreenTests.cs +++ b/UnitTests/Application/ApplicationScreenTests.cs @@ -18,7 +18,7 @@ public void ClearScreenNextIteration_Resets_To_False_After_LayoutAndDraw () Assert.False (Application.ClearScreenNextIteration); // Cleanup - Application.ResetState (true); + Application.Shutdown (); } [Fact] From a9375e42a3400e127bc71b503cad24779b7757b6 Mon Sep 17 00:00:00 2001 From: BDisp Date: Fri, 13 Dec 2024 18:28:57 +0000 Subject: [PATCH 19/19] Always set ConsoleDriver.RunningUnitTests = true if Application.Init is called from a unit test. --- UnitTests/Application/ApplicationScreenTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/UnitTests/Application/ApplicationScreenTests.cs b/UnitTests/Application/ApplicationScreenTests.cs index 9410f218e7..ea965abce8 100644 --- a/UnitTests/Application/ApplicationScreenTests.cs +++ b/UnitTests/Application/ApplicationScreenTests.cs @@ -8,6 +8,7 @@ public class ApplicationScreenTests (ITestOutputHelper output) public void ClearScreenNextIteration_Resets_To_False_After_LayoutAndDraw () { // Arrange + ConsoleDriver.RunningUnitTests = true; Application.Init (); // Act @@ -18,7 +19,7 @@ public void ClearScreenNextIteration_Resets_To_False_After_LayoutAndDraw () Assert.False (Application.ClearScreenNextIteration); // Cleanup - Application.Shutdown (); + Application.ResetState (true); } [Fact]