From 241aec0e3d811698eb4e8275454a5e546375ba42 Mon Sep 17 00:00:00 2001 From: BDisp Date: Fri, 5 Dec 2025 00:12:52 +0000 Subject: [PATCH] Fixes #4442. TextField PositionCursor doesn't treat zero width as one column (#4443) * Fixes #4442. TextField PositionCursor doesn't treat zero width as one column * Each character must return at least one column, with the exception of Tab. * Add unit test for the ScrollOffset --- Terminal.Gui/Views/TextInput/TextField.cs | 3 +- .../Views/TextFieldTests.cs | 42 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Terminal.Gui/Views/TextInput/TextField.cs b/Terminal.Gui/Views/TextInput/TextField.cs index 794b09b40..3b3add863 100644 --- a/Terminal.Gui/Views/TextInput/TextField.cs +++ b/Terminal.Gui/Views/TextInput/TextField.cs @@ -1118,7 +1118,8 @@ public class TextField : View, IDesignable break; } - int cols = _text [idx].GetColumns (); + int cols = Math.Max (_text [idx].GetColumns (), 1); + TextModel.SetCol (ref col, Viewport.Width - 1, cols); } diff --git a/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs b/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs index 70d3121ab..bd49aa1d5 100644 --- a/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs +++ b/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs @@ -632,4 +632,46 @@ public class TextFieldTests (ITestOutputHelper output) : FakeDriverBase return sb.ToString (); } } + + [Fact] + public void PositionCursor_Treat_Zero_Width_As_One_Column () + { + IDriver driver = CreateFakeDriver (); + + TextField tf = new () { Width = 10, Text = "\u001B[" }; + tf.Driver = driver; + tf.SetRelativeLayout (new (10, 1)); + + Assert.Equal (0, tf.CursorPosition); + + tf.CursorPosition = 1; + Assert.Equal (new Point (1, 0), tf.PositionCursor ()); + + tf.CursorPosition = 2; + Assert.Equal (new Point (2, 0), tf.PositionCursor ()); + } + + [Fact] + public void ScrollOffset_Treat_Negative_Width_As_One_Column () + { + View view = new () { Width = 10, Height = 1}; + TextField tf = new () { Width = 2, Text = "\u001B[" }; + view.Add (tf); + tf.SetRelativeLayout (new (10, 1)); + + Assert.Equal (0, tf.ScrollOffset); + Assert.Equal (0, tf.CursorPosition); + + Assert.True (tf.NewKeyDownEvent (Key.CursorRight)); + Assert.Equal (0, tf.ScrollOffset); + Assert.Equal (1, tf.CursorPosition); + + Assert.True (tf.NewKeyDownEvent (Key.CursorRight)); + Assert.Equal (1, tf.ScrollOffset); + Assert.Equal (2, tf.CursorPosition); + + Assert.False (tf.NewKeyDownEvent (Key.CursorRight)); + Assert.Equal (1, tf.ScrollOffset); + Assert.Equal (2, tf.CursorPosition); + } }