Fixes #1211. Added support to TextView for word based operations Ctrl+Del and Ctrl+Backspace. (#1212)

* Fixes #1211. Added support to TextView for word based operations Ctrl+Del and Ctrl+Backspace,

* Updating nuget packages.

* Revert "Updating nuget packages."

This reverts commit e7afc56a67.

* Removed commented code.

* Replacing '\r\n' with System.Environment.NewLine due the unit tests errors on the server.

* Ensures UpdateWrapModel is always processed after a SetWrapModel in the cases where WordWrap is true.

* Added new feature where pressing Ctrl+C copies the  entire current line into the clipboard if there are no selection.

* Fixes copy and paste without selection.

* Fixing Copy/Paste and unit tests.

* Added RemoveRange method to the WordWrapManager and more unit tests.
This commit is contained in:
BDisp
2021-04-18 18:17:48 +01:00
committed by GitHub
parent c18cf2efd6
commit 0fe512d198
2 changed files with 780 additions and 77 deletions

View File

@@ -689,6 +689,21 @@ namespace Terminal.Gui {
return false;
}
public bool RemoveRange (int row, int index, int count)
{
var modelRow = GetModelLineFromWrappedLines (row);
var line = GetCurrentLine (modelRow);
var modelCol = GetModelColFromWrappedLines (row, index);
try {
line.RemoveRange (modelCol, count);
} catch (Exception) {
return false;
}
return true;
}
public void UpdateModel (TextModel model, out int nRow, out int nCol, out int nStartRow, out int nStartCol,
int row, int col, int startRow, int startCol)
{
@@ -1568,7 +1583,7 @@ namespace Terminal.Gui {
void SetClipboard (ustring text)
{
if (!text.IsEmpty) {
if (text != null) {
Clipboard.Contents = text;
}
}
@@ -1775,7 +1790,6 @@ namespace Terminal.Gui {
{
int restCount;
List<Rune> rest;
bool lineRemoved = false;
// Handle some state here - whether the last command was a kill
// operation and the column tracking (up/down)
@@ -1946,38 +1960,8 @@ namespace Terminal.Gui {
ClearSelectedRegion ();
return true;
}
if (currentColumn > 0) {
// Delete backwards
currentLine = GetCurrentLine ();
currentLine.RemoveAt (currentColumn - 1);
if (wordWrap && wrapManager.RemoveAt (currentRow, currentColumn - 1)) {
wrapNeeded = true;
}
currentColumn--;
if (currentColumn < leftColumn) {
leftColumn--;
SetNeedsDisplay ();
} else
SetNeedsDisplay (new Rect (0, currentRow - topRow, 1, Frame.Width));
} else {
// Merges the current line with the previous one.
if (currentRow == 0)
return true;
var prowIdx = currentRow - 1;
var prevRow = model.GetLine (prowIdx);
var prevCount = prevRow.Count;
model.GetLine (prowIdx).AddRange (GetCurrentLine ());
model.RemoveLine (currentRow);
if (wordWrap && wrapManager.RemoveLine (currentRow, currentColumn, out lineRemoved, false)) {
wrapNeeded = true;
}
currentRow--;
if (wrapNeeded && !lineRemoved) {
currentColumn = Math.Max (prevCount - 1, 0);
} else {
currentColumn = prevCount;
}
Adjust ();
if (DeleteTextBackwards ()) {
return true;
}
break;
@@ -2001,25 +1985,8 @@ namespace Terminal.Gui {
ClearSelectedRegion ();
return true;
}
currentLine = GetCurrentLine ();
if (currentColumn == currentLine.Count) {
if (currentRow + 1 == model.Count)
break;
var nextLine = model.GetLine (currentRow + 1);
currentLine.AddRange (nextLine);
model.RemoveLine (currentRow + 1);
if (wordWrap && wrapManager.RemoveLine (currentRow, currentColumn, out _)) {
wrapNeeded = true;
}
var sr = currentRow - topRow;
SetNeedsDisplay (new Rect (0, sr, Frame.Width, sr + 1));
} else {
currentLine.RemoveAt (currentColumn);
if (wordWrap && wrapManager.RemoveAt (currentRow, currentColumn)) {
wrapNeeded = true;
}
var r = currentRow - topRow;
SetNeedsDisplay (new Rect (currentColumn - leftColumn, r, Frame.Width, r + 1));
if (DeleteTextForwards ()) {
return true;
}
break;
@@ -2038,14 +2005,19 @@ namespace Terminal.Gui {
break;
case Key.K | Key.CtrlMask: // kill-to-end
case Key.DeleteChar | Key.CtrlMask | Key.ShiftMask:
if (isReadOnly)
break;
var cRow = currentRow;
SetWrapModel ();
currentLine = GetCurrentLine ();
var setLastWasKill = true;
if (currentLine.Count > 0 && currentColumn == currentLine.Count) {
DeleteTextForwards ();
return true;
}
if (currentLine.Count == 0) {
model.RemoveLine (currentRow);
if (currentRow < model.Count - 1) {
model.RemoveLine (currentRow);
}
if (model.Count > 0 || lastWasKill) {
var val = ustring.Make ((Rune)'\n');
if (lastWasKill) {
@@ -2058,9 +2030,6 @@ namespace Terminal.Gui {
// Prevents from adding line feeds if there is no more lines.
setLastWasKill = false;
}
if (currentRow > 0) {
currentRow--;
}
} else {
restCount = currentLine.Count - currentColumn;
rest = currentLine.GetRange (currentColumn, restCount);
@@ -2074,20 +2043,44 @@ namespace Terminal.Gui {
} else {
SetClipboard (val);
}
if (currentColumn == 0) {
model.RemoveLine (currentRow);
if (currentRow > 0) {
currentRow--;
}
} else {
currentLine.RemoveRange (currentColumn, restCount);
}
if (model.Count == 0) {
// Prevents from adding line feeds if there is no more lines.
setLastWasKill = false;
}
currentLine.RemoveRange (currentColumn, restCount);
}
SetNeedsDisplay (new Rect (0, currentRow - topRow, Frame.Width, Frame.Height));
lastWasKill = setLastWasKill;
break;
case Key.Backspace | Key.CtrlMask | Key.ShiftMask: // kill-to-start
if (isReadOnly)
break;
currentLine = GetCurrentLine ();
setLastWasKill = true;
if (currentLine.Count > 0 && currentColumn == 0) {
DeleteTextBackwards ();
return true;
}
if (currentLine.Count == 0) {
if (currentRow > 0) {
model.RemoveLine (currentRow);
currentRow--;
currentLine = model.GetLine (currentRow);
currentColumn = currentLine.Count;
}
} else {
restCount = currentColumn;
rest = currentLine.GetRange (0, restCount);
var val = ustring.Empty;
if (currentColumn == 0 && lastWasKill && currentLine.Count > 0) {
val = ustring.Make ((Rune)'\n');
}
val += StringFromRunes (rest);
if (lastWasKill) {
AppendClipboard (val);
} else {
SetClipboard (val);
}
currentLine.RemoveRange (0, restCount);
currentColumn = 0;
}
UpdateWrapModel ();
SetNeedsDisplay (new Rect (0, currentRow - topRow, Frame.Width, Frame.Height));
lastWasKill = setLastWasKill;
break;
@@ -2148,6 +2141,65 @@ namespace Terminal.Gui {
Adjust ();
break;
case Key.DeleteChar | Key.CtrlMask: // kill-word-forwards
if (isReadOnly)
break;
currentLine = GetCurrentLine ();
if (currentLine.Count == 0 || currentColumn == currentLine.Count) {
DeleteTextForwards ();
return true;
}
newPos = WordForward (currentColumn, currentRow);
restCount = 0;
if (newPos.HasValue && currentRow == newPos.Value.row) {
restCount = newPos.Value.col - currentColumn;
currentLine.RemoveRange (currentColumn, restCount);
} else if (newPos.HasValue) {
restCount = currentLine.Count - currentColumn;
currentLine.RemoveRange (currentColumn, restCount);
}
if (wordWrap && wrapManager.RemoveRange (currentRow, currentColumn, restCount)) {
wrapNeeded = true;
}
if (wrapNeeded) {
SetNeedsDisplay ();
} else {
SetNeedsDisplay (new Rect (0, currentRow - topRow, Frame.Width, Frame.Height));
}
break;
case Key.Backspace | Key.CtrlMask: // kill-word-backwards
if (isReadOnly)
break;
currentLine = GetCurrentLine ();
if (currentColumn == 0) {
DeleteTextBackwards ();
return true;
}
newPos = WordBackward (currentColumn, currentRow);
if (newPos.HasValue && currentRow == newPos.Value.row) {
restCount = currentColumn - newPos.Value.col;
currentLine.RemoveRange (newPos.Value.col, restCount);
if (wordWrap && wrapManager.RemoveRange (currentRow, newPos.Value.col, restCount)) {
wrapNeeded = true;
}
currentColumn = newPos.Value.col;
} else if (newPos.HasValue) {
restCount = currentLine.Count - currentColumn;
currentLine.RemoveRange (currentColumn, restCount);
if (wordWrap && wrapManager.RemoveRange (currentRow, currentColumn, restCount)) {
wrapNeeded = true;
}
currentColumn = newPos.Value.col;
currentRow = newPos.Value.row;
}
if (wrapNeeded) {
SetNeedsDisplay ();
} else {
SetNeedsDisplay (new Rect (0, currentRow - topRow, Frame.Width, Frame.Height));
}
break;
case Key.Enter:
if (isReadOnly)
break;
@@ -2255,13 +2307,88 @@ namespace Terminal.Gui {
}
}
bool DeleteTextForwards ()
{
var currentLine = GetCurrentLine ();
if (currentColumn == currentLine.Count) {
if (currentRow + 1 == model.Count)
return true;
var nextLine = model.GetLine (currentRow + 1);
currentLine.AddRange (nextLine);
model.RemoveLine (currentRow + 1);
if (wordWrap && wrapManager.RemoveLine (currentRow, currentColumn, out _)) {
wrapNeeded = true;
}
var sr = currentRow - topRow;
SetNeedsDisplay (new Rect (0, sr, Frame.Width, sr + 1));
} else {
currentLine.RemoveAt (currentColumn);
if (wordWrap && wrapManager.RemoveAt (currentRow, currentColumn)) {
wrapNeeded = true;
}
var r = currentRow - topRow;
SetNeedsDisplay (new Rect (currentColumn - leftColumn, r, Frame.Width, r + 1));
}
return false;
}
bool DeleteTextBackwards ()
{
if (currentColumn > 0) {
// Delete backwards
var currentLine = GetCurrentLine ();
currentLine.RemoveAt (currentColumn - 1);
if (wordWrap && wrapManager.RemoveAt (currentRow, currentColumn - 1)) {
wrapNeeded = true;
}
currentColumn--;
if (currentColumn < leftColumn) {
leftColumn--;
SetNeedsDisplay ();
} else
SetNeedsDisplay (new Rect (0, currentRow - topRow, 1, Frame.Width));
} else {
// Merges the current line with the previous one.
if (currentRow == 0)
return true;
var prowIdx = currentRow - 1;
var prevRow = model.GetLine (prowIdx);
var prevCount = prevRow.Count;
model.GetLine (prowIdx).AddRange (GetCurrentLine ());
model.RemoveLine (currentRow);
bool lineRemoved = false;
if (wordWrap && wrapManager.RemoveLine (currentRow, currentColumn, out lineRemoved, false)) {
wrapNeeded = true;
}
currentRow--;
if (wrapNeeded && !lineRemoved) {
currentColumn = Math.Max (prevCount - 1, 0);
} else {
currentColumn = prevCount;
}
Adjust ();
}
return false;
}
bool copyWithoutSelection;
/// <summary>
/// Copy the selected text to the clipboard contents.
/// </summary>
public void Copy ()
{
SetWrapModel ();
SetClipboard (GetRegion ());
if (selecting) {
SetClipboard (GetRegion ());
copyWithoutSelection = false;
} else {
var currentLine = GetCurrentLine ();
SetClipboard (ustring.Make (currentLine));
copyWithoutSelection = true;
}
UpdateWrapModel ();
DoNeededAction ();
}
@@ -2291,10 +2418,17 @@ namespace Terminal.Gui {
}
SetWrapModel ();
if (selecting) {
ClearRegion ();
if (copyWithoutSelection) {
var runeList = Clipboard.Contents == null ? new List<Rune> () : Clipboard.Contents.ToRuneList ();
model.AddLine (currentRow, runeList);
currentRow++;
} else {
if (selecting) {
ClearRegion ();
}
InsertText (Clipboard.Contents);
copyWithoutSelection = false;
}
InsertText (Clipboard.Contents);
UpdateWrapModel ();
selecting = false;
DoNeededAction ();
@@ -2538,15 +2672,22 @@ namespace Terminal.Gui {
}
}
if (nRow != fromRow && (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune))) {
if (lastValidCol > -1) {
nCol = lastValidCol;
}
return;
}
while (MovePrev (ref nCol, ref nRow, out nRune)) {
if (!Rune.IsLetterOrDigit (nRune) && !Rune.IsPunctuation (nRune))
break;
if (nRow != fromRow) {
break;
}
lastValidCol = nCol;
}
if (lastValidCol > -1) {
nCol = lastValidCol;
nRow = fromRow;
}
} else {
if (!MovePrev (ref nCol, ref nRow, out nRune)) {

View File

@@ -1,4 +1,5 @@
using Xunit;
using System;
using Xunit;
namespace Terminal.Gui {
public class TextViewTests {
@@ -648,6 +649,549 @@ namespace Terminal.Gui {
}
}
[Fact]
public void WordBackward_Multiline_With_Selection ()
{
// 4 3 2 1
// 87654321098765432109876 54321098765432109876543210-Length
// 1 2 1 2
// 01234567890123456789012 0123456789012345678901234
_textView.Text = "This is the first line.\nThis is the second line.";
_textView.MoveEnd ();
_textView.SelectionStartColumn = _textView.CurrentColumn;
_textView.SelectionStartRow = _textView.CurrentRow;
var iteration = 0;
bool iterationsFinished = false;
while (!iterationsFinished) {
_textView.ProcessKey (new KeyEvent (Key.CursorLeft | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (19, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal (24, _textView.SelectionStartColumn);
Assert.Equal (1, _textView.SelectionStartRow);
Assert.Equal (5, _textView.SelectedLength);
Assert.Equal ("line.", _textView.SelectedText);
break;
case 1:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal (24, _textView.SelectionStartColumn);
Assert.Equal (1, _textView.SelectionStartRow);
Assert.Equal (12, _textView.SelectedLength);
Assert.Equal ("second line.", _textView.SelectedText);
break;
case 2:
Assert.Equal (8, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal (24, _textView.SelectionStartColumn);
Assert.Equal (1, _textView.SelectionStartRow);
Assert.Equal (16, _textView.SelectedLength);
Assert.Equal ("the second line.", _textView.SelectedText);
break;
case 3:
Assert.Equal (5, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal (24, _textView.SelectionStartColumn);
Assert.Equal (1, _textView.SelectionStartRow);
Assert.Equal (19, _textView.SelectedLength);
Assert.Equal ("is the second line.", _textView.SelectedText);
break;
case 4:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal (24, _textView.SelectionStartColumn);
Assert.Equal (1, _textView.SelectionStartRow);
Assert.Equal (24, _textView.SelectedLength);
Assert.Equal ("This is the second line.", _textView.SelectedText);
break;
case 5:
Assert.Equal (23, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (24, _textView.SelectionStartColumn);
Assert.Equal (1, _textView.SelectionStartRow);
Assert.Equal (25, _textView.SelectedLength);
Assert.Equal ("\nThis is the second line.", _textView.SelectedText);
break;
case 6:
Assert.Equal (18, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (24, _textView.SelectionStartColumn);
Assert.Equal (1, _textView.SelectionStartRow);
Assert.Equal (30, _textView.SelectedLength);
Assert.Equal ("line.\nThis is the second line.", _textView.SelectedText);
break;
case 7:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (24, _textView.SelectionStartColumn);
Assert.Equal (1, _textView.SelectionStartRow);
Assert.Equal (36, _textView.SelectedLength);
Assert.Equal ("first line.\nThis is the second line.", _textView.SelectedText);
break;
case 8:
Assert.Equal (8, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (24, _textView.SelectionStartColumn);
Assert.Equal (1, _textView.SelectionStartRow);
Assert.Equal (40, _textView.SelectedLength);
Assert.Equal ("the first line.\nThis is the second line.", _textView.SelectedText);
break;
case 9:
Assert.Equal (5, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (24, _textView.SelectionStartColumn);
Assert.Equal (1, _textView.SelectionStartRow);
Assert.Equal (43, _textView.SelectedLength);
Assert.Equal ("is the first line.\nThis is the second line.", _textView.SelectedText);
break;
case 10:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (24, _textView.SelectionStartColumn);
Assert.Equal (1, _textView.SelectionStartRow);
Assert.Equal (48, _textView.SelectedLength);
Assert.Equal ("This is the first line.\nThis is the second line.", _textView.SelectedText);
break;
default:
iterationsFinished = true;
break;
}
iteration++;
}
}
[Fact]
public void WordForward_Multiline_With_Selection ()
{
// 1 2 3 4
// 01234567890123456789012 34567890123456789012345678-Length
// 1 2 1 2
// 01234567890123456789012 0123456789012345678901234
_textView.Text = "This is the first line.\nThis is the second line.";
_textView.SelectionStartColumn = _textView.CurrentColumn;
_textView.SelectionStartRow = _textView.CurrentRow;
var iteration = 0;
bool iterationsFinished = false;
while (!iterationsFinished) {
_textView.ProcessKey (new KeyEvent (Key.CursorRight | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (5, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (5, _textView.SelectedLength);
Assert.Equal ("This ", _textView.SelectedText);
break;
case 1:
Assert.Equal (8, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (8, _textView.SelectedLength);
Assert.Equal ("This is ", _textView.SelectedText);
break;
case 2:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (12, _textView.SelectedLength);
Assert.Equal ("This is the ", _textView.SelectedText);
break;
case 3:
Assert.Equal (18, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (18, _textView.SelectedLength);
Assert.Equal ("This is the first ", _textView.SelectedText);
break;
case 4:
Assert.Equal (23, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (23, _textView.SelectedLength);
Assert.Equal ("This is the first line.", _textView.SelectedText);
break;
case 5:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (24, _textView.SelectedLength);
Assert.Equal ("This is the first line.\n", _textView.SelectedText);
break;
case 6:
Assert.Equal (5, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (29, _textView.SelectedLength);
Assert.Equal ("This is the first line.\nThis ", _textView.SelectedText);
break;
case 7:
Assert.Equal (8, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (32, _textView.SelectedLength);
Assert.Equal ("This is the first line.\nThis is ", _textView.SelectedText);
break;
case 8:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (36, _textView.SelectedLength);
Assert.Equal ("This is the first line.\nThis is the ", _textView.SelectedText);
break;
case 9:
Assert.Equal (19, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (43, _textView.SelectedLength);
Assert.Equal ("This is the first line.\nThis is the second ", _textView.SelectedText);
break;
case 10:
Assert.Equal (24, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (48, _textView.SelectedLength);
Assert.Equal ("This is the first line.\nThis is the second line.", _textView.SelectedText);
break;
default:
iterationsFinished = true;
break;
}
iteration++;
}
}
[Fact]
public void Kill_To_End_Delete_Forwards_And_Copy_To_The_Clipboard ()
{
_textView.Text = "This is the first line.\nThis is the second line.";
var iteration = 0;
bool iterationsFinished = false;
while (!iterationsFinished) {
_textView.ProcessKey (new KeyEvent (Key.DeleteChar | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ($"{System.Environment.NewLine}This is the second line.", _textView.Text);
break;
case 1:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("This is the second line.", _textView.Text);
break;
case 2:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("", _textView.Text);
_textView.Paste ();
Assert.Equal ("This is the second line.", _textView.Text);
break;
default:
iterationsFinished = true;
break;
}
iteration++;
}
}
[Fact]
public void Kill_To_Start_Delete_Backwards_And_Copy_To_The_Clipboard ()
{
_textView.Text = "This is the first line.\nThis is the second line.";
_textView.MoveEnd ();
var iteration = 0;
bool iterationsFinished = false;
while (!iterationsFinished) {
_textView.ProcessKey (new KeyEvent (Key.Backspace | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal ($"This is the first line.{System.Environment.NewLine}", _textView.Text);
break;
case 1:
Assert.Equal (23, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("This is the first line.", _textView.Text);
break;
case 2:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("", _textView.Text);
_textView.Paste ();
Assert.Equal ("This is the first line.", _textView.Text);
break;
default:
iterationsFinished = true;
break;
}
iteration++;
}
}
[Fact]
public void Kill_Delete_WordForward ()
{
_textView.Text = "This is the first line.";
var iteration = 0;
bool iterationsFinished = false;
while (!iterationsFinished) {
_textView.ProcessKey (new KeyEvent (Key.DeleteChar | Key.CtrlMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("is the first line.", _textView.Text);
break;
case 1:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("the first line.", _textView.Text);
break;
case 2:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("first line.", _textView.Text);
break;
case 3:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("line.", _textView.Text);
break;
case 4:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("", _textView.Text);
break;
default:
iterationsFinished = true;
break;
}
iteration++;
}
}
[Fact]
public void Kill_Delete_WordBackward ()
{
_textView.Text = "This is the first line.";
_textView.MoveEnd ();
var iteration = 0;
bool iterationsFinished = false;
while (!iterationsFinished) {
_textView.ProcessKey (new KeyEvent (Key.Backspace | Key.CtrlMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (18, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("This is the first ", _textView.Text);
break;
case 1:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("This is the ", _textView.Text);
break;
case 2:
Assert.Equal (8, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("This is ", _textView.Text);
break;
case 3:
Assert.Equal (5, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("This ", _textView.Text);
break;
case 4:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("", _textView.Text);
break;
default:
iterationsFinished = true;
break;
}
iteration++;
}
}
[Fact]
public void Kill_Delete_WordForward_Multiline ()
{
_textView.Text = "This is the first line.\nThis is the second line.";
_textView.Width = 4;
var iteration = 0;
bool iterationsFinished = false;
while (!iterationsFinished) {
_textView.ProcessKey (new KeyEvent (Key.DeleteChar | Key.CtrlMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("is the first line." + Environment.NewLine
+ "This is the second line.", _textView.Text);
break;
case 1:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("the first line." + Environment.NewLine
+ "This is the second line.", _textView.Text);
break;
case 2:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("first line." + Environment.NewLine
+ "This is the second line.", _textView.Text);
break;
case 3:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("line." + Environment.NewLine
+ "This is the second line.", _textView.Text);
break;
case 4:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("" + Environment.NewLine
+ "This is the second line.", _textView.Text);
break;
case 5:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("This is the second line.", _textView.Text);
break;
case 6:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("is the second line.", _textView.Text);
break;
case 7:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("the second line.", _textView.Text);
break;
case 8:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("second line.", _textView.Text);
break;
case 9:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("line.", _textView.Text);
break;
case 10:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("", _textView.Text);
break;
default:
iterationsFinished = true;
break;
}
iteration++;
}
}
[Fact]
public void Kill_Delete_WordBackward_Multiline ()
{
_textView.Text = "This is the first line.\nThis is the second line.";
_textView.Width = 4;
_textView.MoveEnd ();
var iteration = 0;
bool iterationsFinished = false;
while (!iterationsFinished) {
_textView.ProcessKey (new KeyEvent (Key.Backspace | Key.CtrlMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (19, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal ("This is the first line." + Environment.NewLine
+ "This is the second ", _textView.Text);
break;
case 1:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal ("This is the first line." + Environment.NewLine
+ "This is the ", _textView.Text);
break;
case 2:
Assert.Equal (8, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal ("This is the first line." + Environment.NewLine
+ "This is ", _textView.Text);
break;
case 3:
Assert.Equal (5, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal ("This is the first line." + Environment.NewLine
+ "This ", _textView.Text);
break;
case 4:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (1, _textView.CursorPosition.Y);
Assert.Equal ("This is the first line." + Environment.NewLine, _textView.Text);
break;
case 5:
Assert.Equal (23, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("This is the first line.", _textView.Text);
break;
case 6:
Assert.Equal (18, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("This is the first ", _textView.Text);
break;
case 7:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("This is the ", _textView.Text);
break;
case 8:
Assert.Equal (8, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("This is ", _textView.Text);
break;
case 9:
Assert.Equal (5, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("This ", _textView.Text);
break;
case 10:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal ("", _textView.Text);
break;
default:
iterationsFinished = true;
break;
}
iteration++;
}
}
[Fact]
public void Copy_Or_Cut_Null_If_No_Selection ()
{
@@ -793,5 +1337,23 @@ namespace Terminal.Gui {
_textView.ProcessKey (new KeyEvent ((Key)0x64, new KeyModifiers ())); // d
Assert.Equal ("TAB to jumusedtween text fields.", _textView.Text);
}
[Fact]
public void Copy_Without_Selection ()
{
_textView.Text = "This is the first line.\nThis is the second line.\n";
_textView.CursorPosition = new Point (0, _textView.Lines - 1);
_textView.ProcessKey (new KeyEvent (Key.C | Key.CtrlMask, new KeyModifiers ()));
_textView.Paste ();
Assert.Equal ($"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}{Environment.NewLine}", _textView.Text);
_textView.CursorPosition = new Point (3, 1);
_textView.ProcessKey (new KeyEvent (Key.C | Key.CtrlMask, new KeyModifiers ()));
_textView.Paste ();
Assert.Equal ($"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the second line.{Environment.NewLine}{Environment.NewLine}", _textView.Text);
Assert.Equal (new Point (3, 2), _textView.CursorPosition);
_textView.Paste ();
Assert.Equal ($"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the second line.{Environment.NewLine}{Environment.NewLine}", _textView.Text);
Assert.Equal (new Point (3, 3), _textView.CursorPosition);
}
}
}