mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2026-01-01 00:46:39 +01:00
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:
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user