Преглед на файлове

Fixes #4076 cursor text field (#4077)

* Add test for TextField cursor position

* Add comment and one more assert

* Fix cursor position at the end

* Remove unused local field

---------

Co-authored-by: BDisp <[email protected]>
Thomas Nind преди 4 месеца
родител
ревизия
38c6f385f1

+ 0 - 1
Terminal.Gui/FileServices/FileDialogStyle.cs

@@ -10,7 +10,6 @@ namespace Terminal.Gui;
 public class FileDialogStyle
 {
     private readonly IFileSystem _fileSystem;
-    private bool _preserveFilenameOnDirectoryChanges;
 
     /// <summary>Creates a new instance of the <see cref="FileDialogStyle"/> class.</summary>
     public FileDialogStyle (IFileSystem fileSystem)

+ 1 - 1
Terminal.Gui/Views/TextField.cs

@@ -1110,7 +1110,7 @@ public class TextField : View
             TextModel.SetCol (ref col, Viewport.Width - 1, cols);
         }
 
-        int pos = col - ScrollOffset + Math.Min (Viewport.X, 0);
+        int pos = col + Math.Min (Viewport.X, 0);
         Move (pos, 0);
 
         return new Point (pos, 0);

+ 51 - 0
Tests/IntegrationTests/FluentTests/TextFieldFluentTests.cs

@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO.Abstractions;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Terminal.Gui;
+using TerminalGuiFluentTesting;
+using TerminalGuiFluentTestingXunit;
+using Xunit.Abstractions;
+
+namespace IntegrationTests.FluentTests;
+public class TextFieldFluentTests
+{
+    private readonly TextWriter _out;
+
+    public TextFieldFluentTests (ITestOutputHelper outputHelper)
+    {
+        _out = new TestOutputWriter (outputHelper);
+    }
+
+    [Theory]
+    [ClassData (typeof (V2TestDrivers))]
+    public void TextField_Cursor_AtEnd_WhenTyping (V2TestDriver d)
+    {
+        // Simulates typing abcd into a TextField with width 3 (wide enough to render 2 characters only)
+        using var c = With.A<Window> (100, 20, d)
+                          .Add (new TextField () { Width = 3 })
+                          .Focus<TextField> ()
+                          .WaitIteration ()
+                          .AssertCursorPosition (new Point (1, 1)) // Initial cursor position (because Window has border)
+                          .RaiseKeyDownEvent (Key.A)
+                          .WaitIteration ()
+                          .ScreenShot ("After typing first letter", _out)
+                          .AssertCursorPosition (new Point (2, 1)) // Cursor moves along as letter is pressed
+                          .RaiseKeyDownEvent (Key.B)
+                          .WaitIteration ()
+                          .AssertCursorPosition (new Point (3, 1)) // Cursor moves along as letter is pressed
+                          .RaiseKeyDownEvent (Key.C)
+                          .WaitIteration ()
+                          .ScreenShot ("After typing all letters",_out)
+                          .AssertCursorPosition (new Point (3, 1)) // Cursor stays where it is because we are at end of TextField
+                          .RaiseKeyDownEvent (Key.D)
+                          .WaitIteration ()
+                          .ScreenShot ("Typing one more letter", _out)
+                          .AssertCursorPosition (new Point (3, 1)) // Cursor still stays at end of TextField
+                          .WriteOutLogs (_out)
+                          .Stop ();
+    }
+}

+ 6 - 1
Tests/TerminalGuiFluentTesting/FakeOutput.cs

@@ -24,5 +24,10 @@ internal class FakeOutput : IConsoleOutput
     public void SetCursorVisibility (CursorVisibility visibility) { }
 
     /// <inheritdoc/>
-    public void SetCursorPosition (int col, int row) { }
+    public void SetCursorPosition (int col, int row) { CursorPosition = new Point (col, row); }
+
+    /// <summary>
+    /// The last value set by calling <see cref="SetCursorPosition"/>
+    /// </summary>
+    public Point CursorPosition { get; private set; }
 }

+ 14 - 1
Tests/TerminalGuiFluentTesting/GuiTestContext.cs

@@ -706,10 +706,14 @@ public class GuiTestContext : IDisposable
     ///     is found (of Type T) or all views are looped through (back to the beginning)
     ///     in which case triggers hard stop and Exception
     /// </summary>
+    /// <param name="evaluator">Delegate that returns true if the passed View is the one
+    /// you are trying to focus. Leave <see langword="null"/> to focus the first view of type
+    /// <typeparamref name="T"/></param>
     /// <returns></returns>
     /// <exception cref="ArgumentException"></exception>
-    public GuiTestContext Focus<T> (Func<T, bool> evaluator) where T : View
+    public GuiTestContext Focus<T> (Func<T, bool>? evaluator = null) where T : View
     {
+        evaluator ??= _ => true;
         Toplevel? t = Application.Top;
 
         HashSet<View> seen = new ();
@@ -816,4 +820,13 @@ public class GuiTestContext : IDisposable
 
         return this;
     }
+
+    /// <summary>
+    /// Returns the last set position of the cursor.
+    /// </summary>
+    /// <returns></returns>
+    public Point GetCursorPosition ()
+    {
+        return _output.CursorPosition;
+    }
 }

+ 25 - 1
Tests/TerminalGuiFluentTestingXunit/XunitContextExtensions.cs

@@ -1,4 +1,5 @@
-using TerminalGuiFluentTesting;
+using System.Drawing;
+using TerminalGuiFluentTesting;
 using Xunit;
 
 namespace TerminalGuiFluentTestingXunit;
@@ -6,4 +7,27 @@ namespace TerminalGuiFluentTestingXunit;
 public static partial class XunitContextExtensions
 {
     // Placeholder
+
+
+    /// <summary>
+    /// Asserts that the last set cursor position matches <paramref name="expected"/>
+    /// </summary>
+    /// <param name="context"></param>
+    /// <param name="expected"></param>
+    /// <returns></returns>
+    public static GuiTestContext AssertCursorPosition (this GuiTestContext context, Point expected)
+    {
+        try
+        {
+            Assert.Equal (expected, context.GetCursorPosition ());
+        }
+        catch (Exception)
+        {
+            context.HardStop ();
+
+            throw;
+        }
+
+        return context;
+    }
 }