Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #3713 - TextField & TextView - When pressing right/left clear the selection instead of move tab #3776

Merged
merged 8 commits into from
Oct 11, 2024
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 ()
tznind marked this conversation as resolved.
Show resolved Hide resolved
{
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 }; }

}
Loading