Skip to content

Commit cc0d965

Browse files
tznindtig
andauthored
Fixes #3713 - TextField & TextView - When pressing right/left clear 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 <tig@users.noreply.github.com>
1 parent 0085e25 commit cc0d965

File tree

4 files changed

+131
-21
lines changed

4 files changed

+131
-21
lines changed

Terminal.Gui/Views/TextField.cs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,18 +1519,28 @@ private void MoveHomeExtend ()
15191519
}
15201520
}
15211521

1522-
private bool MoveLeft ()
1522+
/// <summary>
1523+
/// Moves the cursor +/- the given <paramref name="distance"/>, clearing
1524+
/// any selection and returning true if any meaningful changes were made.
1525+
/// </summary>
1526+
/// <param name="distance">Distance to move the cursor, will be clamped to
1527+
/// text length. Positive for right, Negative for left.</param>
1528+
/// <returns></returns>
1529+
private bool Move (int distance)
15231530
{
1524-
if (_cursorPosition > 0)
1525-
{
1526-
ClearAllSelection ();
1527-
_cursorPosition--;
1528-
Adjust ();
1531+
var oldCursorPosition = _cursorPosition;
1532+
var hadSelection = _selectedText != null && _selectedText.Length > 0;
15291533

1530-
return true;
1531-
}
1534+
_cursorPosition = Math.Min (_text.Count, Math.Max (0, _cursorPosition + distance));
1535+
ClearAllSelection ();
1536+
Adjust ();
15321537

1533-
return false;
1538+
return _cursorPosition != oldCursorPosition || hadSelection;
1539+
}
1540+
1541+
private bool MoveLeft ()
1542+
{
1543+
return Move (-1);
15341544
}
15351545

15361546
private void MoveLeftExtend ()
@@ -1543,17 +1553,7 @@ private void MoveLeftExtend ()
15431553

15441554
private bool MoveRight ()
15451555
{
1546-
if (_cursorPosition == _text.Count)
1547-
{
1548-
return false;
1549-
}
1550-
1551-
ClearAllSelection ();
1552-
1553-
_cursorPosition++;
1554-
Adjust ();
1555-
1556-
return true;
1556+
return Move (1);
15571557
}
15581558

15591559
private void MoveRightExtend ()

Terminal.Gui/Views/TextView.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5958,6 +5958,11 @@ private bool ProcessMoveLeft ()
59585958
// if the user presses Left (without any control keys) and they are at the start of the text
59595959
if (CurrentColumn == 0 && CurrentRow == 0)
59605960
{
5961+
if (IsSelecting)
5962+
{
5963+
StopSelecting ();
5964+
return true;
5965+
}
59615966
// do not respond (this lets the key press fall through to navigation system - which usually changes focus backward)
59625967
return false;
59635968
}
@@ -5991,6 +5996,13 @@ private bool ProcessMoveRight ()
59915996
// 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)
59925997
if (CurrentColumn == lastCol && CurrentRow == lastRow)
59935998
{
5999+
// Unless they have text selected
6000+
if (IsSelecting)
6001+
{
6002+
// In which case clear
6003+
StopSelecting ();
6004+
return true;
6005+
}
59946006
return false;
59956007
}
59966008

UnitTests/Views/TextFieldTests.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2089,6 +2089,53 @@ public void Autocomplete__Added_To_SuperView_On_Add ()
20892089
Assert.Equal (2, superView.Subviews.Count);
20902090
}
20912091

2092+
[Fact]
2093+
public void Right_CursorAtEnd_WithSelection_ShouldClearSelection ()
2094+
{
2095+
var tf = new TextField
2096+
{
2097+
Text = "Hello",
2098+
};
2099+
tf.SetFocus ();
2100+
tf.SelectAll ();
2101+
tf.CursorPosition = 5;
2102+
2103+
// When there is selected text and the cursor is at the end of the text field
2104+
Assert.Equal ("Hello",tf.SelectedText);
2105+
2106+
// Pressing right should not move focus, instead it should clear selection
2107+
Assert.True(tf.NewKeyDownEvent (Key.CursorRight));
2108+
Assert.Null (tf.SelectedText);
2109+
2110+
// Now that the selection is cleared another right keypress should move focus
2111+
Assert.False (tf.NewKeyDownEvent (Key.CursorRight));
2112+
}
2113+
[Fact]
2114+
public void Left_CursorAtStart_WithSelection_ShouldClearSelection ()
2115+
{
2116+
var tf = new TextField
2117+
{
2118+
Text = "Hello",
2119+
};
2120+
tf.SetFocus ();
2121+
2122+
tf.CursorPosition = 2;
2123+
Assert.True (tf.NewKeyDownEvent (Key.CursorLeft.WithShift));
2124+
Assert.True (tf.NewKeyDownEvent (Key.CursorLeft.WithShift));
2125+
2126+
// When there is selected text and the cursor is at the start of the text field
2127+
Assert.Equal ("He", tf.SelectedText);
2128+
2129+
// Pressing left should not move focus, instead it should clear selection
2130+
Assert.True (tf.NewKeyDownEvent (Key.CursorLeft));
2131+
Assert.Null (tf.SelectedText);
2132+
2133+
// When clearing selected text with left the cursor should be at the start of the selection
2134+
Assert.Equal (0,tf.CursorPosition);
2135+
2136+
// Now that the selection is cleared another left keypress should move focus
2137+
Assert.False (tf.NewKeyDownEvent (Key.CursorLeft));
2138+
}
20922139
[Fact]
20932140
public void Autocomplete_Visible_False_By_Default ()
20942141
{

UnitTests/Views/TextViewTests.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8789,6 +8789,58 @@ public void Autocomplete_Visible_False_By_Default ()
87898789
Assert.False (t.Autocomplete.Visible);
87908790
}
87918791

8792+
[Fact]
8793+
public void Right_CursorAtEnd_WithSelection_ShouldClearSelection ()
8794+
{
8795+
var tv = new TextView
8796+
{
8797+
Text = "Hello",
8798+
};
8799+
tv.SetFocus ();
8800+
8801+
tv.NewKeyDownEvent (Key.End.WithShift);
8802+
Assert.Equal (5,tv.CursorPosition.X);
8803+
8804+
// When there is selected text and the cursor is at the end of the text field
8805+
Assert.Equal ("Hello", tv.SelectedText);
8806+
8807+
// Pressing right should not move focus, instead it should clear selection
8808+
Assert.True (tv.NewKeyDownEvent (Key.CursorRight));
8809+
Assert.Empty (tv.SelectedText);
8810+
8811+
// Now that the selection is cleared another right keypress should move focus
8812+
Assert.False (tv.NewKeyDownEvent (Key.CursorRight));
8813+
}
8814+
[Fact]
8815+
public void Left_CursorAtStart_WithSelection_ShouldClearSelection ()
8816+
{
8817+
var tv = new TextView
8818+
{
8819+
Text = "Hello",
8820+
};
8821+
tv.SetFocus ();
8822+
8823+
tv.NewKeyDownEvent (Key.CursorRight);
8824+
tv.NewKeyDownEvent (Key.CursorRight);
8825+
8826+
Assert.Equal (2,tv.CursorPosition.X);
8827+
8828+
Assert.True (tv.NewKeyDownEvent (Key.CursorLeft.WithShift));
8829+
Assert.True (tv.NewKeyDownEvent (Key.CursorLeft.WithShift));
8830+
8831+
// When there is selected text and the cursor is at the start of the text field
8832+
Assert.Equal ("He", tv.SelectedText);
8833+
8834+
// Pressing left should not move focus, instead it should clear selection
8835+
Assert.True (tv.NewKeyDownEvent (Key.CursorLeft));
8836+
Assert.Empty (tv.SelectedText);
8837+
8838+
// When clearing selected text with left the cursor should be at the start of the selection
8839+
Assert.Equal (0, tv.CursorPosition.X);
8840+
8841+
// Now that the selection is cleared another left keypress should move focus
8842+
Assert.False (tv.NewKeyDownEvent (Key.CursorLeft));
8843+
}
87928844
[Fact]
87938845
[AutoInitShutdown]
87948846
public void Draw_Esc_Rune ()
@@ -9047,5 +9099,4 @@ public void Cell_LoadCells_Without_ColorScheme_Is_Never_Null ()
90479099
}
90489100

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

0 commit comments

Comments
 (0)