diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs
index 7d9785c22c..c9d6818672 100644
--- a/Terminal.Gui/Views/TextField.cs
+++ b/Terminal.Gui/Views/TextField.cs
@@ -1519,18 +1519,28 @@ private void MoveHomeExtend ()
}
}
- private bool MoveLeft ()
+ ///
+ /// Moves the cursor +/- the given , clearing
+ /// any selection and returning true if any meaningful changes were made.
+ ///
+ /// Distance to move the cursor, will be clamped to
+ /// text length. Positive for right, Negative for left.
+ ///
+ private bool Move (int distance)
{
- if (_cursorPosition > 0)
- {
- ClearAllSelection ();
- _cursorPosition--;
- Adjust ();
+ var oldCursorPosition = _cursorPosition;
+ var hadSelection = _selectedText != null && _selectedText.Length > 0;
- return true;
- }
+ _cursorPosition = Math.Min (_text.Count, Math.Max (0, _cursorPosition + distance));
+ ClearAllSelection ();
+ Adjust ();
- return false;
+ return _cursorPosition != oldCursorPosition || hadSelection;
+ }
+
+ private bool MoveLeft ()
+ {
+ return Move (-1);
}
private void MoveLeftExtend ()
@@ -1543,17 +1553,7 @@ private void MoveLeftExtend ()
private bool MoveRight ()
{
- if (_cursorPosition == _text.Count)
- {
- return false;
- }
-
- ClearAllSelection ();
-
- _cursorPosition++;
- Adjust ();
-
- return true;
+ return Move (1);
}
private void MoveRightExtend ()
diff --git a/Terminal.Gui/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs
index c34e9220bd..674d8328ed 100644
--- a/Terminal.Gui/Views/TextView.cs
+++ b/Terminal.Gui/Views/TextView.cs
@@ -5958,6 +5958,11 @@ private bool ProcessMoveLeft ()
// if the user presses Left (without any control keys) and they are at the start of the text
if (CurrentColumn == 0 && CurrentRow == 0)
{
+ if (IsSelecting)
+ {
+ StopSelecting ();
+ return true;
+ }
// do not respond (this lets the key press fall through to navigation system - which usually changes focus backward)
return false;
}
@@ -5991,6 +5996,13 @@ private bool ProcessMoveRight ()
// if they are at the very end of all the text do not respond (this lets the key press fall through to navigation system - which usually changes focus forward)
if (CurrentColumn == lastCol && CurrentRow == lastRow)
{
+ // Unless they have text selected
+ if (IsSelecting)
+ {
+ // In which case clear
+ StopSelecting ();
+ return true;
+ }
return false;
}
diff --git a/UnitTests/Views/TextFieldTests.cs b/UnitTests/Views/TextFieldTests.cs
index 4e1fec138b..d2f8ba4c5a 100644
--- a/UnitTests/Views/TextFieldTests.cs
+++ b/UnitTests/Views/TextFieldTests.cs
@@ -2089,6 +2089,53 @@ public void Autocomplete__Added_To_SuperView_On_Add ()
Assert.Equal (2, superView.Subviews.Count);
}
+ [Fact]
+ public void Right_CursorAtEnd_WithSelection_ShouldClearSelection ()
+ {
+ var tf = new TextField
+ {
+ Text = "Hello",
+ };
+ tf.SetFocus ();
+ tf.SelectAll ();
+ tf.CursorPosition = 5;
+
+ // When there is selected text and the cursor is at the end of the text field
+ Assert.Equal ("Hello",tf.SelectedText);
+
+ // Pressing right should not move focus, instead it should clear selection
+ Assert.True(tf.NewKeyDownEvent (Key.CursorRight));
+ Assert.Null (tf.SelectedText);
+
+ // Now that the selection is cleared another right keypress should move focus
+ Assert.False (tf.NewKeyDownEvent (Key.CursorRight));
+ }
+ [Fact]
+ public void Left_CursorAtStart_WithSelection_ShouldClearSelection ()
+ {
+ var tf = new TextField
+ {
+ Text = "Hello",
+ };
+ tf.SetFocus ();
+
+ tf.CursorPosition = 2;
+ Assert.True (tf.NewKeyDownEvent (Key.CursorLeft.WithShift));
+ Assert.True (tf.NewKeyDownEvent (Key.CursorLeft.WithShift));
+
+ // When there is selected text and the cursor is at the start of the text field
+ Assert.Equal ("He", tf.SelectedText);
+
+ // Pressing left should not move focus, instead it should clear selection
+ Assert.True (tf.NewKeyDownEvent (Key.CursorLeft));
+ Assert.Null (tf.SelectedText);
+
+ // When clearing selected text with left the cursor should be at the start of the selection
+ Assert.Equal (0,tf.CursorPosition);
+
+ // Now that the selection is cleared another left keypress should move focus
+ Assert.False (tf.NewKeyDownEvent (Key.CursorLeft));
+ }
[Fact]
public void Autocomplete_Visible_False_By_Default ()
{
diff --git a/UnitTests/Views/TextViewTests.cs b/UnitTests/Views/TextViewTests.cs
index a05af9ef07..a912064f6d 100644
--- a/UnitTests/Views/TextViewTests.cs
+++ b/UnitTests/Views/TextViewTests.cs
@@ -8789,6 +8789,58 @@ public void Autocomplete_Visible_False_By_Default ()
Assert.False (t.Autocomplete.Visible);
}
+ [Fact]
+ public void Right_CursorAtEnd_WithSelection_ShouldClearSelection ()
+ {
+ var tv = new TextView
+ {
+ Text = "Hello",
+ };
+ tv.SetFocus ();
+
+ tv.NewKeyDownEvent (Key.End.WithShift);
+ Assert.Equal (5,tv.CursorPosition.X);
+
+ // When there is selected text and the cursor is at the end of the text field
+ Assert.Equal ("Hello", tv.SelectedText);
+
+ // Pressing right should not move focus, instead it should clear selection
+ Assert.True (tv.NewKeyDownEvent (Key.CursorRight));
+ Assert.Empty (tv.SelectedText);
+
+ // Now that the selection is cleared another right keypress should move focus
+ Assert.False (tv.NewKeyDownEvent (Key.CursorRight));
+ }
+ [Fact]
+ public void Left_CursorAtStart_WithSelection_ShouldClearSelection ()
+ {
+ var tv = new TextView
+ {
+ Text = "Hello",
+ };
+ tv.SetFocus ();
+
+ tv.NewKeyDownEvent (Key.CursorRight);
+ tv.NewKeyDownEvent (Key.CursorRight);
+
+ Assert.Equal (2,tv.CursorPosition.X);
+
+ Assert.True (tv.NewKeyDownEvent (Key.CursorLeft.WithShift));
+ Assert.True (tv.NewKeyDownEvent (Key.CursorLeft.WithShift));
+
+ // When there is selected text and the cursor is at the start of the text field
+ Assert.Equal ("He", tv.SelectedText);
+
+ // Pressing left should not move focus, instead it should clear selection
+ Assert.True (tv.NewKeyDownEvent (Key.CursorLeft));
+ Assert.Empty (tv.SelectedText);
+
+ // When clearing selected text with left the cursor should be at the start of the selection
+ Assert.Equal (0, tv.CursorPosition.X);
+
+ // Now that the selection is cleared another left keypress should move focus
+ Assert.False (tv.NewKeyDownEvent (Key.CursorLeft));
+ }
[Fact]
[AutoInitShutdown]
public void Draw_Esc_Rune ()
@@ -9047,5 +9099,4 @@ public void Cell_LoadCells_Without_ColorScheme_Is_Never_Null ()
}
private TextView CreateTextView () { return new () { Width = 30, Height = 10 }; }
-
}