Skip to content

Commit

Permalink
Fixes #3713 - TextField & TextView - When pressing right/left cle…
Browse files Browse the repository at this point in the history
…ar the selection instead of move tab (#3776)

* When pressing right clear the selection instead of move tab - TextField

* Add tests and start on TextView

* Finish tests for TextView

* Fix typos

* typo fix x2

* Fix for Selecting being renamed IsSelecting

---------

Co-authored-by: Tig <[email protected]>
  • Loading branch information
tznind and tig authored Oct 11, 2024
1 parent 0085e25 commit cc0d965
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 21 deletions.
40 changes: 20 additions & 20 deletions Terminal.Gui/Views/TextField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1519,18 +1519,28 @@ private void MoveHomeExtend ()
}
}

private bool MoveLeft ()
/// <summary>
/// Moves the cursor +/- the given <paramref name="distance"/>, clearing
/// any selection and returning true if any meaningful changes were made.
/// </summary>
/// <param name="distance">Distance to move the cursor, will be clamped to
/// text length. Positive for right, Negative for left.</param>
/// <returns></returns>
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 ()
Expand All @@ -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 ()
Expand Down
12 changes: 12 additions & 0 deletions Terminal.Gui/Views/TextView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down
47 changes: 47 additions & 0 deletions UnitTests/Views/TextFieldTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ()
{
Expand Down
53 changes: 52 additions & 1 deletion UnitTests/Views/TextViewTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ()
Expand Down Expand Up @@ -9047,5 +9099,4 @@ public void Cell_LoadCells_Without_ColorScheme_Is_Never_Null ()
}

private TextView CreateTextView () { return new () { Width = 30, Height = 10 }; }

}

0 comments on commit cc0d965

Please sign in to comment.