diff --git a/Examples/UICatalog/Scenarios/Editor.cs b/Examples/UICatalog/Scenarios/Editor.cs index 9cf02dc4d..b005fec55 100644 --- a/Examples/UICatalog/Scenarios/Editor.cs +++ b/Examples/UICatalog/Scenarios/Editor.cs @@ -201,6 +201,8 @@ public class Editor : Scenario CreateAutocomplete (), CreateAllowsTabChecked (), CreateReadOnlyChecked (), + CreateUseSameRuneTypeForWords (), + CreateSelectWordOnlyOnDoubleClick (), new MenuItem ( "Colors", "", @@ -776,6 +778,26 @@ public class Editor : Scenario return new [] { item }; } + private MenuItem CreateSelectWordOnlyOnDoubleClick () + { + var item = new MenuItem { Title = "SelectWordOnlyOnDoubleClick" }; + item.CheckType |= MenuItemCheckStyle.Checked; + item.Checked = _textView.SelectWordOnlyOnDoubleClick; + item.Action += () => _textView.SelectWordOnlyOnDoubleClick = (bool)(item.Checked = !item.Checked); + + return item; + } + + private MenuItem CreateUseSameRuneTypeForWords () + { + var item = new MenuItem { Title = "UseSameRuneTypeForWords" }; + item.CheckType |= MenuItemCheckStyle.Checked; + item.Checked = _textView.UseSameRuneTypeForWords; + item.Action += () => _textView.UseSameRuneTypeForWords = (bool)(item.Checked = !item.Checked); + + return item; + } + private MenuItem CreateReadOnlyChecked () { var item = new MenuItem { Title = "Read Only" }; diff --git a/Terminal.Gui/Views/TextInput/TextField.cs b/Terminal.Gui/Views/TextInput/TextField.cs index 0eaa40181..559b7d8a2 100644 --- a/Terminal.Gui/Views/TextInput/TextField.cs +++ b/Terminal.Gui/Views/TextInput/TextField.cs @@ -570,6 +570,19 @@ public class TextField : View, IDesignable /// public bool Used { get; set; } + /// + /// Gets or sets whether the word forward and word backward navigation should use the same or equivalent rune type. + /// Default is false meaning using equivalent rune type. + /// + public bool UseSameRuneTypeForWords { get; set; } + + /// + /// Gets or sets whether the word navigation should select only the word itself without spaces around it or with the + /// spaces at right. + /// Default is false meaning that the spaces at right are included in the selection. + /// + public bool SelectWordOnlyOnDoubleClick { get; set; } + /// Clear the selected text. public void ClearAllSelection () { @@ -754,7 +767,7 @@ public class TextField : View, IDesignable public virtual void KillWordBackwards () { ClearAllSelection (); - (int col, int row)? newPos = GetModel ().WordBackward (_cursorPosition, 0); + (int col, int row)? newPos = GetModel ().WordBackward (_cursorPosition, 0, UseSameRuneTypeForWords); if (newPos is null) { @@ -777,7 +790,7 @@ public class TextField : View, IDesignable public virtual void KillWordForwards () { ClearAllSelection (); - (int col, int row)? newPos = GetModel ().WordForward (_cursorPosition, 0); + (int col, int row)? newPos = GetModel ().WordForward (_cursorPosition, 0, UseSameRuneTypeForWords); if (newPos is null) { @@ -857,43 +870,15 @@ public class TextField : View, IDesignable { EnsureHasFocus (); int x = PositionCursor (ev); - int sbw = x; + (int startCol, int col, int row)? newPos = GetModel ().ProcessDoubleClickSelection (x, x, 0, UseSameRuneTypeForWords, SelectWordOnlyOnDoubleClick); - if (x == _text.Count - || (x > 0 && (char)_text [x - 1].Value != ' ') - || (x > 0 && (char)_text [x].Value == ' ')) - { - (int col, int row)? newPosBw = GetModel ().WordBackward (x, 0); - - if (newPosBw is null) - { - return true; - } - - sbw = newPosBw.Value.col; - } - - if (sbw != -1) - { - x = sbw; - PositionCursor (x); - } - - (int col, int row)? newPosFw = GetModel ().WordForward (x, 0); - - if (newPosFw is null) + if (newPos is null) { return true; } - ClearAllSelection (); - - if (newPosFw.Value.col != -1 && sbw != -1) - { - _cursorPosition = newPosFw.Value.col; - } - - PrepareSelection (sbw, newPosFw.Value.col - sbw); + SelectedStart = newPos.Value.startCol; + CursorPosition = newPos.Value.col; } else if (ev.Flags == MouseFlags.Button1TripleClicked) { @@ -1502,7 +1487,7 @@ public class TextField : View, IDesignable private void MoveWordLeft () { ClearAllSelection (); - (int col, int row)? newPos = GetModel ().WordBackward (_cursorPosition, 0); + (int col, int row)? newPos = GetModel ().WordBackward (_cursorPosition, 0, UseSameRuneTypeForWords); if (newPos is null) { @@ -1528,7 +1513,7 @@ public class TextField : View, IDesignable if (x > 0) { - (int col, int row)? newPos = GetModel ().WordBackward (x, 0); + (int col, int row)? newPos = GetModel ().WordBackward (x, 0, UseSameRuneTypeForWords); if (newPos is null) { @@ -1548,7 +1533,7 @@ public class TextField : View, IDesignable private void MoveWordRight () { ClearAllSelection (); - (int col, int row)? newPos = GetModel ().WordForward (_cursorPosition, 0); + (int col, int row)? newPos = GetModel ().WordForward (_cursorPosition, 0, UseSameRuneTypeForWords); if (newPos is null) { @@ -1568,7 +1553,7 @@ public class TextField : View, IDesignable if (_cursorPosition < _text.Count) { int x = _start > -1 && _start > _cursorPosition ? _start : _cursorPosition; - (int col, int row)? newPos = GetModel ().WordForward (x, 0); + (int col, int row)? newPos = GetModel ().WordForward (x, 0, UseSameRuneTypeForWords); if (newPos is null) { diff --git a/Terminal.Gui/Views/TextInput/TextModel.cs b/Terminal.Gui/Views/TextInput/TextModel.cs index b76955ba5..275c8a908 100644 --- a/Terminal.Gui/Views/TextInput/TextModel.cs +++ b/Terminal.Gui/Views/TextInput/TextModel.cs @@ -206,7 +206,7 @@ internal class TextModel return sb.ToString (); } - public (int col, int row)? WordBackward (int fromCol, int fromRow) + public (int col, int row)? WordBackward (int fromCol, int fromRow, bool useSameRuneType) { if (fromRow == 0 && fromCol == 0) { @@ -245,7 +245,7 @@ internal class TextModel RuneType runeType = GetRuneType (rune); - int lastValidCol = IsSameRuneType (rune, runeType) && (Rune.IsLetterOrDigit (rune) || Rune.IsPunctuation (rune) || Rune.IsSymbol (rune)) + int lastValidCol = IsSameRuneType (rune, runeType, useSameRuneType) && (Rune.IsLetterOrDigit (rune) || Rune.IsPunctuation (rune) || Rune.IsSymbol (rune)) ? col : -1; @@ -253,21 +253,29 @@ internal class TextModel { if (Rune.IsWhiteSpace (nRune)) { - while (MovePrev (ref nCol, ref nRow, out nRune)) + while (MovePrev (ref nCol, ref nRow, out nRune, useSameRuneType)) { + lastValidCol = nCol; + if (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune)) { - lastValidCol = nCol; - - if (runeType == RuneType.IsWhiteSpace || runeType == RuneType.IsUnknown) - { - runeType = GetRuneType (nRune); - } - - break; + rune = nRune; + runeType = GetRuneType (nRune); } } + if (lastValidCol > -1) + { + nCol = lastValidCol; + nRow = fromRow; + } + + if ((!Rune.IsWhiteSpace (nRune) && Rune.IsWhiteSpace (rune)) + || (Rune.IsWhiteSpace (nRune) && !Rune.IsWhiteSpace (rune))) + { + return; + } + if (nRow != fromRow && (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune))) { List line = GetLine (nRow); @@ -276,38 +284,18 @@ internal class TextModel { nCol = lastValidCol + Math.Max (lastValidCol, line.Count); } - - return; - } - - while (MovePrev (ref nCol, ref nRow, out nRune)) - { - if (!Rune.IsLetterOrDigit (nRune) && !Rune.IsPunctuation (nRune) && !Rune.IsSymbol (nRune)) - { - break; - } - - if (nRow != fromRow) - { - break; - } - - lastValidCol = - (IsSameRuneType (nRune, runeType) && Rune.IsLetterOrDigit (nRune)) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune) - ? nCol - : lastValidCol; - } - - if (lastValidCol > -1) - { - nCol = lastValidCol; - nRow = fromRow; } } else { - if (!MovePrev (ref nCol, ref nRow, out nRune)) + if (!MovePrev (ref nCol, ref nRow, out nRune, useSameRuneType)) { + if (lastValidCol > -1) + { + nCol = lastValidCol; + nRow = fromRow; + } + return; } @@ -321,7 +309,7 @@ internal class TextModel } lastValidCol = - (IsSameRuneType (nRune, runeType) && Rune.IsLetterOrDigit (nRune)) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune) + (IsSameRuneType (nRune, runeType, useSameRuneType) && Rune.IsLetterOrDigit (nRune)) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune) ? nCol : lastValidCol; @@ -350,6 +338,15 @@ internal class TextModel return (col, row); } + if (fromCol == col && fromRow == row && row > 0) + { + row--; + List line = GetLine (row); + col = line.Count; + + return (col, row); + } + return null; } catch (Exception) @@ -358,7 +355,7 @@ internal class TextModel } } - public (int col, int row)? WordForward (int fromCol, int fromRow) + public (int col, int row)? WordForward (int fromCol, int fromRow, bool useSameRuneType) { if (fromRow == _lines.Count - 1 && fromCol == GetLine (_lines.Count - 1).Count) { @@ -370,10 +367,10 @@ internal class TextModel try { - Rune rune = RuneAt (col, row)!.Value.Rune; + Rune rune = _lines [row].Count > 0 ? RuneAt (col, row)!.Value.Rune : default (Rune); RuneType runeType = GetRuneType (rune); - int lastValidCol = IsSameRuneType (rune, runeType) && (Rune.IsLetterOrDigit (rune) || Rune.IsPunctuation (rune) || Rune.IsSymbol (rune)) + int lastValidCol = IsSameRuneType (rune, runeType, useSameRuneType) && (Rune.IsLetterOrDigit (rune) || Rune.IsPunctuation (rune) || Rune.IsSymbol (rune)) ? col : -1; @@ -381,16 +378,23 @@ internal class TextModel { if (Rune.IsWhiteSpace (nRune)) { - while (MoveNext (ref nCol, ref nRow, out nRune)) + while (MoveNext (ref nCol, ref nRow, out nRune, useSameRuneType)) { + lastValidCol = nCol; + if (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune)) { - lastValidCol = nCol; - return; } } + lastValidCol = nCol; + + if (!Rune.IsWhiteSpace (nRune) && Rune.IsWhiteSpace (rune)) + { + return; + } + if (nRow != fromRow && (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune))) { if (lastValidCol > -1) @@ -401,24 +405,6 @@ internal class TextModel return; } - while (MoveNext (ref nCol, ref nRow, out nRune)) - { - if (!Rune.IsLetterOrDigit (nRune) && !Rune.IsPunctuation (nRune) && !Rune.IsSymbol (nRune)) - { - break; - } - - if (nRow != fromRow) - { - break; - } - - lastValidCol = - (IsSameRuneType (nRune, runeType) && Rune.IsLetterOrDigit (nRune)) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune) - ? nCol - : lastValidCol; - } - if (lastValidCol > -1) { nCol = lastValidCol; @@ -427,12 +413,14 @@ internal class TextModel } else { - if (!MoveNext (ref nCol, ref nRow, out nRune)) + if (!MoveNext (ref nCol, ref nRow, out nRune, useSameRuneType)) { return; } - if (!IsSameRuneType (nRune, runeType) && !Rune.IsWhiteSpace (nRune)) + lastValidCol = nCol; + + if (!IsSameRuneType (nRune, runeType, useSameRuneType) && !Rune.IsWhiteSpace (nRune)) { return; } @@ -446,11 +434,6 @@ internal class TextModel return; } - lastValidCol = - (IsSameRuneType (nRune, runeType) && Rune.IsLetterOrDigit (nRune)) || Rune.IsPunctuation (nRune) || Rune.IsSymbol (nRune) - ? nCol - : lastValidCol; - if (fromRow != nRow) { nCol = 0; @@ -477,6 +460,64 @@ internal class TextModel } } + public (int startCol, int col, int row)? ProcessDoubleClickSelection (int fromStartCol, int fromCol, int fromRow, bool useSameRuneType, bool selectWordOnly) + { + List line = GetLine (fromRow); + + int startCol = fromStartCol; + int col = fromCol; + int row = fromRow; + + (int col, int row)? newPos = WordForward (col, row, useSameRuneType); + + if (newPos.HasValue) + { + col = row == newPos.Value.row ? newPos.Value.col : 0; + } + + if (startCol > 0 + && StringExtensions.ToString (line.GetRange (startCol, col - startCol).Select (c => c.Rune).ToList ()).Trim () == "" + && (col - startCol > 1 || (col - startCol > 0 && line [startCol - 1].Rune == (Rune)' '))) + { + while (startCol > 0 && line [startCol - 1].Rune == (Rune)' ') + { + startCol--; + } + } + else + { + newPos = WordBackward (col, row, useSameRuneType); + + if (newPos is { }) + { + startCol = row == newPos.Value.row ? newPos.Value.col : line.Count; + } + } + + if (selectWordOnly) + { + List selRunes = line.GetRange (startCol, col - startCol).Select (c => c.Rune).ToList (); + + if (StringExtensions.ToString (selRunes).Trim () != "") + { + for (int i = selRunes.Count - 1; i > -1; i--) + { + if (selRunes [i] == (Rune)' ') + { + col--; + } + } + } + } + + if (fromStartCol != startCol || fromCol != col || fromRow != row) + { + return (startCol, col, row); + } + + return null; + } + internal static int CalculateLeftColumn (List t, int start, int end, int width, int tabWidth = 0) { List runes = new (); @@ -966,11 +1007,27 @@ internal class TextModel return RuneType.IsUnknown; } - private bool IsSameRuneType (Rune newRune, RuneType runeType) + private bool IsSameRuneType (Rune newRune, RuneType runeType, bool useSameRuneType) { RuneType rt = GetRuneType (newRune); - return rt == runeType; + if (useSameRuneType) + { + return rt == runeType; + } + + switch (runeType) + { + case RuneType.IsSymbol: + case RuneType.IsPunctuation: + return rt is RuneType.IsSymbol or RuneType.IsPunctuation; + case RuneType.IsWhiteSpace: + case RuneType.IsLetterOrDigit: + case RuneType.IsUnknown: + return rt == runeType; + default: + throw new ArgumentOutOfRangeException (nameof (runeType), runeType, null); + } } private bool MatchWholeWord (string source, string matchText, int index = 0) @@ -992,7 +1049,7 @@ internal class TextModel return false; } - private bool MoveNext (ref int col, ref int row, out Rune rune) + private bool MoveNext (ref int col, ref int row, out Rune rune, bool useSameRuneType) { List line = GetLine (row); @@ -1001,39 +1058,40 @@ internal class TextModel col++; rune = line [col].Rune; - if (col + 1 == line.Count && !Rune.IsLetterOrDigit (rune) && !Rune.IsWhiteSpace (line [col - 1].Rune)) + if (col + 1 == line.Count + && !Rune.IsLetterOrDigit (rune) + && !Rune.IsWhiteSpace (line [col - 1].Rune) + && IsSameRuneType (line [col - 1].Rune, GetRuneType (rune), useSameRuneType)) { col++; } + if (!Rune.IsWhiteSpace (rune) + && (Rune.IsWhiteSpace (line [col - 1].Rune) || !IsSameRuneType (line [col - 1].Rune, GetRuneType (rune), useSameRuneType))) + { + return false; + } + return true; } if (col + 1 == line.Count) { col++; + rune = default (Rune); + + return false; } - while (row + 1 < Count) - { - col = 0; - row++; - line = GetLine (row); - - if (line.Count > 0) - { - rune = line [0].Rune; - - return true; - } - } - + // End of line + col = 0; + row++; rune = default (Rune); return false; } - private bool MovePrev (ref int col, ref int row, out Rune rune) + private bool MovePrev (ref int col, ref int row, out Rune rune, bool useSameRuneType) { List line = GetLine (row); @@ -1042,28 +1100,15 @@ internal class TextModel col--; rune = line [col].Rune; - return true; - } - - if (row == 0) - { - rune = default (Rune); - - return false; - } - - while (row > 0) - { - row--; - line = GetLine (row); - col = line.Count - 1; - - if (col >= 0) + if ((!Rune.IsWhiteSpace (rune) + && !Rune.IsWhiteSpace (line [col + 1].Rune) + && !IsSameRuneType (line [col + 1].Rune, GetRuneType (rune), useSameRuneType)) + || (Rune.IsWhiteSpace (rune) && !Rune.IsWhiteSpace (line [col + 1].Rune))) { - rune = line [col].Rune; - - return true; + return false; } + + return true; } rune = default (Rune); diff --git a/Terminal.Gui/Views/TextInput/TextView.cs b/Terminal.Gui/Views/TextInput/TextView.cs index bd392e984..6d4d7b7c6 100644 --- a/Terminal.Gui/Views/TextInput/TextView.cs +++ b/Terminal.Gui/Views/TextInput/TextView.cs @@ -1015,6 +1015,19 @@ public class TextView : View, IDesignable } } + /// + /// Gets or sets whether the word forward and word backward navigation should use the same or equivalent rune type. + /// Default is false meaning using equivalent rune type. + /// + public bool UseSameRuneTypeForWords { get; set; } + + /// + /// Gets or sets whether the word navigation should select only the word itself without spaces around it or with the + /// spaces at right. + /// Default is false meaning that the spaces at right are included in the selection. + /// + public bool SelectWordOnlyOnDoubleClick { get; set; } + /// Allows clearing the items updating the original text. public void ClearHistoryChanges () { _historyText?.Clear (_model.GetAllLines ()); } @@ -1689,29 +1702,19 @@ public class TextView : View, IDesignable } ProcessMouseClick (ev, out List line); - (int col, int row)? newPos; - - if (CurrentColumn == line.Count - || (CurrentColumn > 0 && (line [CurrentColumn - 1].Rune.Value != ' ' || line [CurrentColumn].Rune.Value == ' '))) - { - newPos = _model.WordBackward (CurrentColumn, CurrentRow); - - if (newPos.HasValue) - { - CurrentColumn = CurrentRow == newPos.Value.row ? newPos.Value.col : 0; - } - } if (!IsSelecting) { StartSelecting (); } - newPos = _model.WordForward (CurrentColumn, CurrentRow); + (int startCol, int col, int row)? newPos = _model.ProcessDoubleClickSelection (SelectionStartColumn, CurrentColumn, CurrentRow, UseSameRuneTypeForWords, SelectWordOnlyOnDoubleClick); - if (newPos is { } && newPos.HasValue) + if (newPos.HasValue) { - CurrentColumn = CurrentRow == newPos.Value.row ? newPos.Value.col : line.Count; + SelectionStartColumn = newPos.Value.startCol; + CurrentColumn = newPos.Value.col; + CurrentRow = newPos.Value.row; } PositionCursor (); @@ -3380,7 +3383,7 @@ public class TextView : View, IDesignable return; } - (int col, int row)? newPos = _model.WordBackward (CurrentColumn, CurrentRow); + (int col, int row)? newPos = _model.WordBackward (CurrentColumn, CurrentRow, UseSameRuneTypeForWords); if (newPos.HasValue && CurrentRow == newPos.Value.row) { @@ -3464,7 +3467,7 @@ public class TextView : View, IDesignable return; } - (int col, int row)? newPos = _model.WordForward (CurrentColumn, CurrentRow); + (int col, int row)? newPos = _model.WordForward (CurrentColumn, CurrentRow, UseSameRuneTypeForWords); var restCount = 0; if (newPos.HasValue && CurrentRow == newPos.Value.row) @@ -3754,7 +3757,7 @@ public class TextView : View, IDesignable private void MoveWordBackward () { - (int col, int row)? newPos = _model.WordBackward (CurrentColumn, CurrentRow); + (int col, int row)? newPos = _model.WordBackward (CurrentColumn, CurrentRow, UseSameRuneTypeForWords); if (newPos.HasValue) { @@ -3767,7 +3770,7 @@ public class TextView : View, IDesignable private void MoveWordForward () { - (int col, int row)? newPos = _model.WordForward (CurrentColumn, CurrentRow); + (int col, int row)? newPos = _model.WordForward (CurrentColumn, CurrentRow, UseSameRuneTypeForWords); if (newPos.HasValue) { diff --git a/Tests/UnitTests/Views/TextFieldTests.cs b/Tests/UnitTests/Views/TextFieldTests.cs index 4f808c21f..822871a55 100644 --- a/Tests/UnitTests/Views/TextFieldTests.cs +++ b/Tests/UnitTests/Views/TextFieldTests.cs @@ -607,6 +607,8 @@ public class TextFieldTests (ITestOutputHelper output) Assert.True (tf.NewKeyDownEvent (Key.CursorRight.WithShift.WithCtrl)); #endif Assert.Equal ("is is a test.", tf.Text); + Assert.Equal ("is a test", tf.SelectedText); + Assert.True (tf.NewKeyDownEvent (Key.CursorRight.WithShift.WithCtrl)); Assert.Equal ("is a test.", tf.SelectedText); Assert.Equal (13, tf.CursorPosition); Assert.True (tf.NewKeyDownEvent (Key.CursorLeft)); @@ -1340,6 +1342,13 @@ public class TextFieldTests (ITestOutputHelper output) break; case 5: + Assert.Equal (31, _textField.CursorPosition); + Assert.Equal (-1, _textField.SelectedStart); + Assert.Equal (0, _textField.SelectedLength); + Assert.Null (_textField.SelectedText); + + break; + case 6: Assert.Equal (32, _textField.CursorPosition); Assert.Equal (-1, _textField.SelectedStart); Assert.Equal (0, _textField.SelectedLength); @@ -1501,6 +1510,13 @@ public class TextFieldTests (ITestOutputHelper output) break; case 5: + Assert.Equal (31, _textField.CursorPosition); + Assert.Equal (0, _textField.SelectedStart); + Assert.Equal (31, _textField.SelectedLength); + Assert.Equal ("TAB to jump between text fields", _textField.SelectedText); + + break; + case 6: Assert.Equal (32, _textField.CursorPosition); Assert.Equal (0, _textField.SelectedStart); Assert.Equal (32, _textField.SelectedLength); @@ -1550,6 +1566,13 @@ public class TextFieldTests (ITestOutputHelper output) break; case 3: + Assert.Equal (31, _textField.CursorPosition); + Assert.Equal (10, _textField.SelectedStart); + Assert.Equal (21, _textField.SelectedLength); + Assert.Equal ("p between text fields", _textField.SelectedText); + + break; + case 4: Assert.Equal (32, _textField.CursorPosition); Assert.Equal (10, _textField.SelectedStart); Assert.Equal (22, _textField.SelectedLength); diff --git a/Tests/UnitTests/Views/TextViewTests.cs b/Tests/UnitTests/Views/TextViewTests.cs index 3a63de1e4..b0b0bbed4 100644 --- a/Tests/UnitTests/Views/TextViewTests.cs +++ b/Tests/UnitTests/Views/TextViewTests.cs @@ -176,57 +176,6 @@ public class TextViewTests Assert.Equal ("B to jump between ", _textView.SelectedText); } - [Fact] - public void CloseFile_Throws_If_FilePath_Is_Null () - { - var tv = new TextView (); - Assert.Throws (() => tv.CloseFile ()); - } - - [Fact] - public void ContentsChanged_Event_Fires_ClearHistoryChanges () - { - var eventcount = 0; - - var text = "This is the first line.\nThis is the second line.\nThis is the third line."; - var tv = new TextView { Width = 50, Height = 10, Text = text }; - tv.ContentsChanged += (s, e) => { eventcount++; }; - - Assert.True (tv.NewKeyDownEvent (Key.Enter)); - - Assert.Equal ( - $"{Environment.NewLine}This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - - var expectedEventCount = 1; // for ENTER key - Assert.Equal (expectedEventCount, eventcount); - - tv.ClearHistoryChanges (); - expectedEventCount = 2; - Assert.Equal (expectedEventCount, eventcount); - } - - [Fact] - public void ContentsChanged_Event_Fires_LoadStream_By_Calling_HistoryText_Clear () - { - var eventcount = 0; - - var tv = new TextView { Width = 50, Height = 10 }; - tv.ContentsChanged += (s, e) => { eventcount++; }; - - var text = "This is the first line.\r\nThis is the second line.\r\n"; - tv.Load (new MemoryStream (Encoding.ASCII.GetBytes (text))); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", - tv.Text - ); - - Assert.Equal (1, eventcount); - } - [Fact] [AutoInitShutdown] public void ContentsChanged_Event_Fires_On_Init () @@ -283,29 +232,6 @@ public class TextViewTests Assert.Equal (10, eventcount); } - [Fact] - public void ContentsChanged_Event_Fires_On_LoadFile_By_Calling_HistoryText_Clear () - { - var eventcount = 0; - - var tv = new TextView { Width = 50, Height = 10 }; - tv.BeginInit (); - tv.EndInit (); - - tv.ContentsChanged += (s, e) => { eventcount++; }; - - var fileName = "textview.txt"; - File.WriteAllText (fileName, "This is the first line.\r\nThis is the second line.\r\n"); - - tv.Load (fileName); - Assert.Equal (1, eventcount); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", - tv.Text - ); - } - [Fact] [AutoInitShutdown] public void ContentsChanged_Event_Fires_On_Set_Text () @@ -1114,167 +1040,6 @@ This is the second line. Application.Shutdown (); } - [Fact] - public void GetRegion_StringFromRunes_Environment_NewLine () - { - var tv = new TextView { Text = $"1{Environment.NewLine}2" }; - - Assert.Equal ($"1{Environment.NewLine}2", tv.Text); - Assert.Equal ("", tv.SelectedText); - - tv.SelectAll (); - Assert.Equal ($"1{Environment.NewLine}2", tv.Text); - Assert.Equal ($"1{Environment.NewLine}2", tv.SelectedText); - } - - [Fact] - public void HistoryText_ClearHistoryChanges () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line."; - var tv = new TextView { Text = text }; - - Assert.True (tv.NewKeyDownEvent (Key.Enter)); - - Assert.Equal ( - $"{Environment.NewLine}This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - Assert.True (tv.IsDirty); - Assert.True (tv.HasHistoryChanges); - - tv.ClearHistoryChanges (); - - Assert.Equal ( - $"{Environment.NewLine}This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - Assert.False (tv.IsDirty); - Assert.False (tv.HasHistoryChanges); - } - - [Fact] - public void HistoryText_Exceptions () - { - var ht = new HistoryText (); - - foreach (object ls in Enum.GetValues (typeof (TextEditingLineStatus))) - { - if ((TextEditingLineStatus)ls != TextEditingLineStatus.Original) - { - Assert.Throws ( - () => ht.Add ( - new List> (), - Point.Empty, - (TextEditingLineStatus)ls - ) - ); - } - } - - Assert.Null (Record.Exception (() => ht.Add (new () { new () }, Point.Empty))); - } - - [Fact] - public void HistoryText_IsDirty_HasHistoryChanges () - { - var tv = new TextView (); - - Assert.Equal ("", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - Assert.False (tv.IsDirty); - Assert.False (tv.HasHistoryChanges); - - Assert.True (tv.NewKeyDownEvent (Key.D1)); - Assert.Equal ("1", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (1, 0), tv.CursorPosition); - Assert.True (tv.IsDirty); - Assert.True (tv.HasHistoryChanges); - - Assert.True (tv.NewKeyDownEvent (Key.Enter)); - Assert.Equal ($"1{Environment.NewLine}", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - Assert.True (tv.IsDirty); - Assert.True (tv.HasHistoryChanges); - - Assert.True (tv.NewKeyDownEvent (Key.D2)); - Assert.Equal ($"1{Environment.NewLine}2", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (1, 1), tv.CursorPosition); - Assert.True (tv.IsDirty); - Assert.True (tv.HasHistoryChanges); - - Assert.True (tv.NewKeyDownEvent (Key.Backspace)); - Assert.Equal ($"1{Environment.NewLine}", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - Assert.True (tv.IsDirty); - Assert.True (tv.HasHistoryChanges); - - Assert.True (tv.NewKeyDownEvent (Key.Backspace)); - Assert.Equal ("1", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (1, 0), tv.CursorPosition); - Assert.True (tv.IsDirty); - Assert.True (tv.HasHistoryChanges); - - Assert.True (tv.NewKeyDownEvent (Key.Backspace)); - Assert.Equal ("", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - // IsDirty cannot be based on HasHistoryChanges because HasHistoryChanges is greater than 0 - // The only way is comparing from the original text - Assert.False (tv.IsDirty); - - // Still true because HasHistoryChanges is greater than 0 - Assert.True (tv.HasHistoryChanges); - } - - [Fact] - public void HistoryText_Undo_Redo_Changing_On_Middle_Clear_History_Forwards () - { - var tv = new TextView (); - - Assert.True (tv.NewKeyDownEvent (Key.D1)); - Assert.Equal ("1", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (1, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.D2)); - Assert.Equal ("12", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (2, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.D3)); - Assert.Equal ("123", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (3, 0), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ("12", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (2, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.D4)); - Assert.Equal ("124", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (3, 0), tv.CursorPosition); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ("124", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (3, 0), tv.CursorPosition); - } - [Fact] [AutoInitShutdown (useFakeClipboard: true)] public void HistoryText_Undo_Redo_Copy_Without_Selection_Multi_Line_Paste () @@ -1486,40 +1251,6 @@ This is the second line. Assert.Equal (new (18, 1), tv.CursorPosition); } - [Fact] - public void HistoryText_Undo_Redo_Disabled_On_WordWrap () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line.\n"; - var tv = new TextView { Width = 80, Height = 5, Text = text }; - - Assert.False (tv.WordWrap); - tv.WordWrap = true; - - tv.SelectionStartColumn = 12; - tv.CursorPosition = new (12, 2); - - Assert.True (tv.NewKeyDownEvent (Key.Enter)); - Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.A)); - Assert.Equal ($"This is the {Environment.NewLine}athird line.{Environment.NewLine}", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (1, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - Assert.True (tv.IsDirty); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"This is the {Environment.NewLine}athird line.{Environment.NewLine}", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (1, 1), tv.CursorPosition); - } - [Fact] [AutoInitShutdown] public void HistoryText_Undo_Redo_Empty_Copy_Without_Selection_Multi_Line_Selected_Paste () @@ -1567,190 +1298,6 @@ This is the second line. Assert.Equal (new (0, 1), tv.CursorPosition); } - [Fact] - public void HistoryText_Undo_Redo_Ending_With_Newline_Multi_Line_Selected_Almost_All_Return_And_InsertText () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line.\n"; - var tv = new TextView { Text = text }; - - tv.SelectionStartColumn = 12; - tv.CursorPosition = new (12, 2); - - Assert.True (tv.NewKeyDownEvent (Key.Enter)); - Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.A)); - Assert.Equal ($"This is the {Environment.NewLine}athird line.{Environment.NewLine}", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (1, 1), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - Assert.True (tv.IsDirty); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.{Environment.NewLine}", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (12, 2), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"This is the {Environment.NewLine}athird line.{Environment.NewLine}", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (1, 1), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - Assert.True (tv.IsDirty); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.{Environment.NewLine}", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (12, 2), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"This is the {Environment.NewLine}athird line.{Environment.NewLine}", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (1, 1), tv.CursorPosition); - } - - [Fact] - public void HistoryText_Undo_Redo_First_Line_Selected_Return_And_InsertText () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line."; - var tv = new TextView { Text = text }; - - tv.SelectionStartColumn = 12; - tv.CursorPosition = new (17, 0); - - Assert.True (tv.NewKeyDownEvent (Key.Enter)); - - Assert.Equal ( - $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.A)); - - Assert.Equal ( - $"This is the {Environment.NewLine}a line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (1, 1), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - Assert.True (tv.IsDirty); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (17, 0), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the {Environment.NewLine}a line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (1, 1), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - Assert.True (tv.IsDirty); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (17, 0), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the {Environment.NewLine}a line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (1, 1), tv.CursorPosition); - } - [Fact] [AutoInitShutdown] public void HistoryText_Undo_Redo_KillToEndOfLine () @@ -1879,218 +1426,6 @@ This is the second line. Assert.Equal (Point.Empty, tv.CursorPosition); } - [Fact] - public void HistoryText_Undo_Redo_KillWordBackward () - { - var text = "First line.\nSecond line."; - var tv = new TextView { Text = text }; - - Assert.True (tv.NewKeyDownEvent (Key.End.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}Second line.", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (12, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}Second line", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (11, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}Second ", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (7, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); - Assert.Equal ("First line.", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (11, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); - Assert.Equal ("First line", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (10, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); - Assert.Equal ("First ", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (6, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); - Assert.Equal ("", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ("First ", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (6, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ("First line", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (10, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ("First line.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (11, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}Second ", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (7, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}Second line", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (11, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}Second line.", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (12, 1), tv.CursorPosition); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}Second line", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (11, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}Second ", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (7, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ("First line.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (11, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ("First line", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (10, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ("First ", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (6, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ("", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - } - - [Fact] - public void HistoryText_Undo_Redo_KillWordForward () - { - var text = "First line.\nSecond line."; - var tv = new TextView { Text = text }; - - Assert.True (tv.NewKeyDownEvent (Key.Delete.WithCtrl)); - Assert.Equal ($"line.{Environment.NewLine}Second line.", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (2, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Delete.WithCtrl)); - Assert.Equal ($"{Environment.NewLine}Second line.", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Delete.WithCtrl)); - Assert.Equal ("Second line.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Delete.WithCtrl)); - Assert.Equal ("line.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Delete.WithCtrl)); - Assert.Equal ("", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ("line.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ("Second line.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"{Environment.NewLine}Second line.", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"line.{Environment.NewLine}Second line.", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}Second line.", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"line.{Environment.NewLine}Second line.", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"{Environment.NewLine}Second line.", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ("Second line.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ("line.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ("", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - } - [Fact] [AutoInitShutdown] public void HistoryText_Undo_Redo_Multi_Line_DeleteCharLeft () @@ -2565,88 +1900,6 @@ This is the second line. top.Dispose (); } - [Fact] - public void HistoryText_Undo_Redo_Multi_Line_Selected_All_Return_And_InsertText () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line."; - var tv = new TextView { Text = text }; - - Assert.True (tv.NewKeyDownEvent (Key.End.WithCtrl.WithShift)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (23, 2), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Enter)); - Assert.Equal ($"{Environment.NewLine}", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.A)); - Assert.Equal ($"{Environment.NewLine}a", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (1, 1), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"{Environment.NewLine}", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - Assert.True (tv.IsDirty); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (23, 2), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"{Environment.NewLine}", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"{Environment.NewLine}a", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (1, 1), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"{Environment.NewLine}", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - Assert.True (tv.IsDirty); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (23, 2), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"{Environment.NewLine}", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"{Environment.NewLine}a", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (1, 1), tv.CursorPosition); - } - [Fact] [AutoInitShutdown] public void HistoryText_Undo_Redo_Multi_Line_Selected_Copy_Simple_Paste_Starting_On_Letter () @@ -2752,138 +2005,6 @@ This is the second line. Assert.Equal (new (18, 2), tv.CursorPosition); } - [Fact] - public void HistoryText_Undo_Redo_Multi_Line_Selected_DeleteCharLeft_All () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line."; - var tv = new TextView { Text = text }; - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - Assert.False (tv.IsDirty); - Assert.False (tv.HasHistoryChanges); - - Assert.True (tv.NewKeyDownEvent (Key.End.WithCtrl.WithShift)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.SelectedText - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (23, 2), tv.CursorPosition); - Assert.Equal (70 + Environment.NewLine.Length * 2, tv.SelectedLength); - Assert.False (tv.IsDirty); - Assert.False (tv.HasHistoryChanges); - - Assert.True (tv.NewKeyDownEvent (Key.Backspace)); - Assert.Equal ("", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - Assert.Equal (0, tv.SelectedLength); - Assert.True (tv.IsDirty); - Assert.True (tv.HasHistoryChanges); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (23, 2), tv.CursorPosition); - Assert.Equal (0, tv.SelectedLength); - Assert.False (tv.IsDirty); - Assert.True (tv.HasHistoryChanges); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ("", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - Assert.Equal (0, tv.SelectedLength); - Assert.True (tv.IsDirty); - Assert.True (tv.HasHistoryChanges); - } - - [Fact] - public void HistoryText_Undo_Redo_Multi_Line_Selected_DeleteCharRight_All () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line."; - var tv = new TextView { Text = text }; - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - Assert.False (tv.IsDirty); - Assert.False (tv.HasHistoryChanges); - - Assert.True (tv.NewKeyDownEvent (Key.End.WithCtrl.WithShift)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.SelectedText - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (23, 2), tv.CursorPosition); - Assert.Equal (70 + Environment.NewLine.Length * 2, tv.SelectedLength); - Assert.False (tv.IsDirty); - Assert.False (tv.HasHistoryChanges); - - Assert.True (tv.NewKeyDownEvent (Key.Delete)); - Assert.Equal ("", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - Assert.Equal (0, tv.SelectedLength); - Assert.True (tv.IsDirty); - Assert.True (tv.HasHistoryChanges); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (23, 2), tv.CursorPosition); - Assert.Equal (0, tv.SelectedLength); - Assert.False (tv.IsDirty); - Assert.True (tv.HasHistoryChanges); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ("", tv.Text); - Assert.Equal ("", tv.SelectedText); - Assert.Equal (1, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - Assert.Equal (0, tv.SelectedLength); - Assert.True (tv.IsDirty); - Assert.True (tv.HasHistoryChanges); - } - [Fact] [AutoInitShutdown] public void HistoryText_Undo_Redo_Multi_Line_Selected_InsertText () @@ -3820,103 +2941,6 @@ This is the second line. top.Dispose (); } - [Fact] - public void HistoryText_Undo_Redo_Multiline_Selected_Tab_BackTab () - { - var text = "First line.\nSecond line.\nThird line."; - var tv = new TextView { Width = 80, Height = 5, Text = text }; - - tv.SelectionStartColumn = 6; - tv.CursorPosition = new (6, 2); - - Assert.True (tv.NewKeyDownEvent (Key.Tab)); - Assert.Equal ("First \tline.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (7, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Tab.WithShift)); - Assert.Equal ("First line.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (6, 0), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ("First \tline.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (7, 0), tv.CursorPosition); - Assert.True (tv.IsDirty); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (6, 2), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ("First \tline.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (7, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ("First line.", tv.Text); - Assert.Equal (1, tv.Lines); - Assert.Equal (new (6, 0), tv.CursorPosition); - } - - [Fact] - public void HistoryText_Undo_Redo_Multiline_Simples_Tab_BackTab () - { - var text = "First line.\nSecond line.\nThird line."; - var tv = new TextView { Width = 80, Height = 5, Text = text }; - - Assert.True (tv.NewKeyDownEvent (Key.Tab)); - - Assert.Equal ( - $"\tFirst line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (1, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.Tab.WithShift)); - Assert.Equal ($"First line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"\tFirst line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (1, 0), tv.CursorPosition); - Assert.True (tv.IsDirty); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"\tFirst line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (1, 0), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"First line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", tv.Text); - Assert.Equal (3, tv.Lines); - Assert.Equal (Point.Empty, tv.CursorPosition); - } - [Fact] [AutoInitShutdown] public void HistoryText_Undo_Redo_Setting_Clipboard_Multi_Line_Selected_Paste () @@ -4378,515 +3402,6 @@ This is the second line. top.Dispose (); } - [Fact] - public void HistoryText_Undo_Redo_Single_Line_Selected_Return () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line."; - var tv = new TextView { Text = text }; - - tv.SelectionStartColumn = 12; - tv.CursorPosition = new (17, 0); - - Assert.True (tv.NewKeyDownEvent (Key.Enter)); - - Assert.Equal ( - $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (17, 0), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (17, 0), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - } - - [Fact] - public void HistoryText_Undo_Redo_Single_Second_Line_Selected_Return () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line."; - var tv = new TextView { Text = text }; - - tv.SelectionStartColumn = 12; - tv.SelectionStartRow = 1; - tv.CursorPosition = new (18, 1); - - Assert.True (tv.NewKeyDownEvent (Key.Enter)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 2), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (18, 1), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 2), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (18, 1), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 2), tv.CursorPosition); - } - - [Fact] - public void HistoryText_Undo_Redo_Single_Second_Line_Selected_Return_And_InsertText () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line."; - var tv = new TextView { Text = text }; - - tv.SelectionStartColumn = 12; - tv.SelectionStartRow = 1; - tv.CursorPosition = new (18, 1); - - Assert.True (tv.NewKeyDownEvent (Key.Enter)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 2), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.A)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine}a line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (1, 2), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 2), tv.CursorPosition); - Assert.True (tv.IsDirty); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (18, 1), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 2), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine}a line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (1, 2), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 2), tv.CursorPosition); - Assert.True (tv.IsDirty); - - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (18, 1), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (0, 2), tv.CursorPosition); - - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine}a line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (4, tv.Lines); - Assert.Equal (new (1, 2), tv.CursorPosition); - } - - [Fact] - public void HistoryText_Undo_Redo_Three_Line_Selected_Return () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line."; - var tv = new TextView { Text = text }; - - tv.SelectionStartColumn = 12; - tv.CursorPosition = new (17, 2); - - Assert.True (tv.NewKeyDownEvent (Key.Enter)); - Assert.Equal ($"This is the {Environment.NewLine} line.", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (17, 2), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"This is the {Environment.NewLine} line.", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (17, 2), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - Assert.Equal ($"This is the {Environment.NewLine} line.", tv.Text); - Assert.Equal (2, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - } - - [Fact] - public void HistoryText_Undo_Redo_Two_Line_Selected_Return () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line."; - var tv = new TextView { Text = text }; - - tv.SelectionStartColumn = 12; - tv.CursorPosition = new (18, 1); - - Assert.True (tv.NewKeyDownEvent (Key.Enter)); - - Assert.Equal ( - $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (18, 1), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (18, 1), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - Assert.Equal ( - $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", - tv.Text - ); - Assert.Equal (3, tv.Lines); - Assert.Equal (new (0, 1), tv.CursorPosition); - } - - [Fact] - public void HistoryText_Undo_Redo_ApplyCellsAttribute () - { - var text = "This is the first line.\nThis is the second line.\nThis is the third line."; - var tv = new TextView { Text = text }; - - tv.SelectionStartColumn = 12; - tv.CursorPosition = new (18, 1); - - if (Environment.NewLine.Length == 2) - { - Assert.Equal (31, tv.SelectedLength); - } - else - { - Assert.Equal (30, tv.SelectedLength); - } - - Assert.Equal ($"first line.{Environment.NewLine}This is the second", tv.SelectedText); - Assert.Equal ($"first line.{Environment.NewLine}This is the second", Cell.ToString (tv.SelectedCellsList)); - Assert.Equal (new (18, 1), tv.CursorPosition); - Assert.False (tv.IsDirty); - - AssertNullAttribute (); - - tv.ApplyCellsAttribute (new (Color.Red, Color.Green)); - - AssertRedGreenAttribute (); - - Assert.Equal (0, tv.SelectedLength); - Assert.Equal ("", tv.SelectedText); - Assert.Equal ($"first line.{Environment.NewLine}This is the second", Cell.ToString (tv.SelectedCellsList)); - Assert.Equal (new (18, 1), tv.CursorPosition); - Assert.True (tv.IsDirty); - - // Undo - Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); - - AssertNullAttribute (); - - Assert.Equal (12, tv.SelectionStartColumn); - Assert.Equal (0, tv.SelectionStartRow); - Assert.Equal (0, tv.SelectedLength); - Assert.Equal ("", tv.SelectedText); - Assert.Empty (tv.SelectedCellsList); - Assert.Equal (new (12, 0), tv.CursorPosition); - Assert.False (tv.IsDirty); - - // Redo - Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); - - AssertRedGreenAttribute (); - - Assert.Equal (12, tv.SelectionStartColumn); - Assert.Equal (0, tv.SelectionStartRow); - Assert.Equal (0, tv.SelectedLength); - Assert.Equal ("", tv.SelectedText); - Assert.Empty (tv.SelectedCellsList); - Assert.Equal (new (12, 0), tv.CursorPosition); - Assert.True (tv.IsDirty); - - void AssertNullAttribute () - { - tv.GetRegion (out List> region, 0, 12, 1, 18); - - foreach (List cells in region) - { - foreach (Cell cell in cells) - { - Assert.Null (cell.Attribute); - } - } - } - - void AssertRedGreenAttribute () - { - tv.GetRegion (out List> region, 0, 12, 1, 18); - - foreach (List cells in region) - { - foreach (Cell cell in cells) - { - Assert.Equal ("[Red,Green,None]", cell.Attribute.ToString ()); - } - } - } - } - - [Fact] - public void Internal_Tests () - { - var txt = "This is a text."; - List txtRunes = Cell.StringToCells (txt); - Assert.Equal (txt.Length, txtRunes.Count); - Assert.Equal ('T', txtRunes [0].Rune.Value); - Assert.Equal ('h', txtRunes [1].Rune.Value); - Assert.Equal ('i', txtRunes [2].Rune.Value); - Assert.Equal ('s', txtRunes [3].Rune.Value); - Assert.Equal (' ', txtRunes [4].Rune.Value); - Assert.Equal ('i', txtRunes [5].Rune.Value); - Assert.Equal ('s', txtRunes [6].Rune.Value); - Assert.Equal (' ', txtRunes [7].Rune.Value); - Assert.Equal ('a', txtRunes [8].Rune.Value); - Assert.Equal (' ', txtRunes [9].Rune.Value); - Assert.Equal ('t', txtRunes [10].Rune.Value); - Assert.Equal ('e', txtRunes [11].Rune.Value); - Assert.Equal ('x', txtRunes [12].Rune.Value); - Assert.Equal ('t', txtRunes [13].Rune.Value); - Assert.Equal ('.', txtRunes [^1].Rune.Value); - - var col = 0; - Assert.True (TextModel.SetCol (ref col, 80, 79)); - Assert.False (TextModel.SetCol (ref col, 80, 80)); - Assert.Equal (79, col); - - var start = 0; - var x = 8; - Assert.Equal (8, TextModel.GetColFromX (txtRunes, start, x)); - Assert.Equal ('a', txtRunes [start + x].Rune.Value); - start = 1; - x = 7; - Assert.Equal (7, TextModel.GetColFromX (txtRunes, start, x)); - Assert.Equal ('a', txtRunes [start + x].Rune.Value); - - Assert.Equal ((15, 15), TextModel.DisplaySize (txtRunes)); - Assert.Equal ((6, 6), TextModel.DisplaySize (txtRunes, 1, 7)); - - Assert.Equal (0, TextModel.CalculateLeftColumn (txtRunes, 0, 7, 8)); - Assert.Equal (1, TextModel.CalculateLeftColumn (txtRunes, 0, 8, 8)); - Assert.Equal (2, TextModel.CalculateLeftColumn (txtRunes, 0, 9, 8)); - - var tm = new TextModel (); - tm.AddLine (0, Cell.StringToCells ("This is first line.")); - tm.AddLine (1, Cell.StringToCells ("This is last line.")); - Assert.Equal ((new Point (2, 0), true), tm.FindNextText ("is", out bool gaveFullTurn)); - Assert.False (gaveFullTurn); - Assert.Equal ((new Point (5, 0), true), tm.FindNextText ("is", out gaveFullTurn)); - Assert.False (gaveFullTurn); - Assert.Equal ((new Point (2, 1), true), tm.FindNextText ("is", out gaveFullTurn)); - Assert.False (gaveFullTurn); - Assert.Equal ((new Point (5, 1), true), tm.FindNextText ("is", out gaveFullTurn)); - Assert.False (gaveFullTurn); - Assert.Equal ((new Point (2, 0), true), tm.FindNextText ("is", out gaveFullTurn)); - Assert.True (gaveFullTurn); - tm.ResetContinuousFind (Point.Empty); - Assert.Equal ((new Point (5, 1), true), tm.FindPreviousText ("is", out gaveFullTurn)); - Assert.False (gaveFullTurn); - Assert.Equal ((new Point (2, 1), true), tm.FindPreviousText ("is", out gaveFullTurn)); - Assert.False (gaveFullTurn); - Assert.Equal ((new Point (5, 0), true), tm.FindPreviousText ("is", out gaveFullTurn)); - Assert.False (gaveFullTurn); - Assert.Equal ((new Point (2, 0), true), tm.FindPreviousText ("is", out gaveFullTurn)); - Assert.False (gaveFullTurn); - Assert.Equal ((new Point (5, 1), true), tm.FindPreviousText ("is", out gaveFullTurn)); - Assert.True (gaveFullTurn); - - Assert.Equal ((new Point (9, 1), true), tm.ReplaceAllText ("is", false, false, "really")); - Assert.Equal (Cell.StringToCells ("Threally really first line."), tm.GetLine (0)); - Assert.Equal (Cell.StringToCells ("Threally really last line."), tm.GetLine (1)); - tm = new (); - tm.AddLine (0, Cell.StringToCells ("This is first line.")); - tm.AddLine (1, Cell.StringToCells ("This is last line.")); - Assert.Equal ((new Point (5, 1), true), tm.ReplaceAllText ("is", false, true, "really")); - Assert.Equal (Cell.StringToCells ("This really first line."), tm.GetLine (0)); - Assert.Equal (Cell.StringToCells ("This really last line."), tm.GetLine (1)); - } - [Fact] [AutoInitShutdown (useFakeClipboard: true)] public void KeyBindings_Command () @@ -5352,6 +3867,26 @@ This is the second line. Assert.False (tv.IsSelecting); Assert.True (tv.NewKeyDownEvent (Key.CursorLeft.WithCtrl)); + Assert.Equal ( + $"{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.first", + tv.Text + ); + Assert.Equal (new (23, 2), tv.CursorPosition); + Assert.Equal (0, tv.SelectedLength); + Assert.Equal ("", tv.SelectedText); + Assert.False (tv.IsSelecting); + Assert.True (tv.NewKeyDownEvent (Key.CursorLeft.WithCtrl)); + + Assert.Equal ( + $"{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.first", + tv.Text + ); + Assert.Equal (new (22, 2), tv.CursorPosition); + Assert.Equal (0, tv.SelectedLength); + Assert.Equal ("", tv.SelectedText); + Assert.False (tv.IsSelecting); + Assert.True (tv.NewKeyDownEvent (Key.CursorLeft.WithCtrl)); + Assert.Equal ( $"{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.first", tv.Text @@ -5453,6 +3988,18 @@ This is the second line. Assert.Equal ("", tv.SelectedText); Assert.False (tv.IsSelecting); Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); + Assert.Equal ($"This is the second line.{Environment.NewLine}This is the third line.", tv.Text); + Assert.Equal (new (23, 1), tv.CursorPosition); + Assert.Equal (0, tv.SelectedLength); + Assert.Equal ("", tv.SelectedText); + Assert.False (tv.IsSelecting); + Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); + Assert.Equal ($"This is the second line.{Environment.NewLine}This is the third line", tv.Text); + Assert.Equal (new (22, 1), tv.CursorPosition); + Assert.Equal (0, tv.SelectedLength); + Assert.Equal ("", tv.SelectedText); + Assert.False (tv.IsSelecting); + Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); Assert.Equal ($"This is the second line.{Environment.NewLine}This is the third ", tv.Text); Assert.Equal (new (18, 1), tv.CursorPosition); Assert.Equal (0, tv.SelectedLength); @@ -5807,6 +4354,12 @@ This is the second line. break; case 4: + Assert.Equal (0, _textView.CursorPosition.X); + Assert.Equal (0, _textView.CursorPosition.Y); + Assert.Equal (".", _textView.Text); + + break; + case 5: Assert.Equal (0, _textView.CursorPosition.X); Assert.Equal (0, _textView.CursorPosition.Y); Assert.Equal ("", _textView.Text); @@ -5890,7 +4443,7 @@ This is the second line. Assert.Equal (0, _textView.CursorPosition.Y); Assert.Equal ( - "" + "." + Environment.NewLine + "This is the second line.", _textView.Text @@ -5900,34 +4453,52 @@ This is the second line. case 5: Assert.Equal (0, _textView.CursorPosition.X); Assert.Equal (0, _textView.CursorPosition.Y); - Assert.Equal ("This is the second line.", _textView.Text); + + Assert.Equal ( + "" + + Environment.NewLine + + "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); + Assert.Equal ("This 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); + Assert.Equal ("is 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); + Assert.Equal ("the second line.", _textView.Text); break; case 9: Assert.Equal (0, _textView.CursorPosition.X); Assert.Equal (0, _textView.CursorPosition.Y); - Assert.Equal ("line.", _textView.Text); + Assert.Equal ("second line.", _textView.Text); break; case 10: + Assert.Equal (0, _textView.CursorPosition.X); + Assert.Equal (0, _textView.CursorPosition.Y); + Assert.Equal ("line.", _textView.Text); + + break; + case 11: + Assert.Equal (0, _textView.CursorPosition.X); + Assert.Equal (0, _textView.CursorPosition.Y); + Assert.Equal (".", _textView.Text); + + break; + case 12: Assert.Equal (0, _textView.CursorPosition.X); Assert.Equal (0, _textView.CursorPosition.Y); Assert.Equal ("", _textView.Text); @@ -6068,139 +4639,6 @@ This is the second line. } } - [Fact] - public void LeftColumn_Add_One_If_Text_Length_Is_Equal_To_Width () - { - var tv = new TextView { Width = 10, Text = "1234567890" }; - - Assert.Equal (Point.Empty, tv.CursorPosition); - Assert.Equal (0, tv.LeftColumn); - - tv.CursorPosition = new (9, 0); - Assert.Equal (new (9, 0), tv.CursorPosition); - Assert.Equal (0, tv.LeftColumn); - - Assert.True (tv.NewKeyDownEvent (Key.CursorRight)); - tv.CursorPosition = new (10, 0); - Assert.Equal (new (10, 0), tv.CursorPosition); - Assert.Equal (1, tv.LeftColumn); - } - - [Fact] - public void LoadFile_Throws_If_File_Is_Empty () - { - var result = false; - var tv = new TextView (); - Assert.Throws (() => result = tv.Load ("")); - Assert.False (result); - } - - [Fact] - public void LoadFile_Throws_If_File_Is_Null () - { - var result = false; - var tv = new TextView (); - Assert.Throws (() => result = tv.Load ((string)null)); - Assert.False (result); - } - - [Fact] - public void LoadFile_Throws_If_File_Not_Exist () - { - var result = false; - var tv = new TextView (); - Assert.Throws (() => result = tv.Load ("blabla")); - Assert.False (result); - } - - [Fact] - public void LoadStream_CRLF () - { - var text = "This is the first line.\r\nThis is the second line.\r\n"; - var tv = new TextView (); - tv.Load (new MemoryStream (Encoding.ASCII.GetBytes (text))); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", - tv.Text - ); - } - - [Fact] - public void LoadStream_IsDirty () - { - var text = "Testing"; - - using (var stream = new MemoryStream ()) - { - var writer = new StreamWriter (stream); - writer.Write (text); - writer.Flush (); - stream.Position = 0; - - var tv = new TextView (); - tv.Load (stream); - - Assert.Equal (7, text.Length); - Assert.Equal (text.Length, tv.Text.Length); - Assert.Equal (text, tv.Text); - Assert.False (tv.IsDirty); - } - } - - [Fact] - public void LoadStream_IsDirty_With_Null_On_The_Text () - { - var text = "Test\0ing"; - - using (var stream = new MemoryStream ()) - { - var writer = new StreamWriter (stream); - writer.Write (text); - writer.Flush (); - stream.Position = 0; - - var tv = new TextView (); - tv.Load (stream); - - Assert.Equal (8, text.Length); - Assert.Equal (text.Length, tv.Text.Length); - Assert.Equal (8, text.Length); - Assert.Equal (8, tv.Text.Length); - Assert.Equal (text, tv.Text); - Assert.False (tv.IsDirty); - Assert.Equal ((Rune)'\u2400', ((Rune)tv.Text [4]).MakePrintable ()); - } - } - - [Fact] - public void LoadStream_LF () - { - var text = "This is the first line.\nThis is the second line.\n"; - var tv = new TextView (); - tv.Load (new MemoryStream (Encoding.ASCII.GetBytes (text))); - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", - tv.Text - ); - } - - [Fact] - public void LoadStream_Stream_Is_Empty () - { - var tv = new TextView (); - tv.Load (new MemoryStream ()); - Assert.Equal ("", tv.Text); - } - - [Fact] - public void LoadStream_Throws_If_Stream_Is_Null () - { - var tv = new TextView (); - Assert.Throws (() => tv.Load ((Stream)null)); - } - [Fact] [TextViewTestsAutoInitShutdown] public void Mouse_Button_Shift_Preserves_Selection () @@ -6331,18 +4769,6 @@ This is the second line. Assert.Equal ("", _textView.SelectedText); } - [Fact] - public void ReplaceAllText_Does_Not_Throw_Exception () - { - var textToFind = "hello! hello!"; - var textToReplace = "hello!"; - var tv = new TextView { Width = 20, Height = 3, Text = textToFind }; - - Exception exception = Record.Exception (() => tv.ReplaceAllText (textToFind, false, false, textToReplace)); - Assert.Null (exception); - Assert.Equal (textToReplace, tv.Text); - } - [Fact] [AutoInitShutdown] public void ScrollDownTillCaretOffscreen_ThenType () @@ -6470,32 +4896,6 @@ This is the second line. Assert.Equal ("", _textView.SelectedText); } - [Fact] - public void StringToRunes_Slipts_CRLF () - { - var text = "This is the first line.\r\nThis is the second line.\r\n"; - var tv = new TextView (); - tv.Text = text; - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", - tv.Text - ); - } - - [Fact] - public void StringToRunes_Slipts_LF () - { - var text = "This is the first line.\nThis is the second line.\n"; - var tv = new TextView (); - tv.Text = text; - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", - tv.Text - ); - } - [Fact] [TextViewTestsAutoInitShutdown] public void Tab_Test_Follow_By_BackTab () @@ -6994,20 +5394,6 @@ TAB to jump between text field", top.Dispose (); } - [Fact] - public void TextView_MultiLine_But_Without_Tabs () - { - var view = new TextView (); - - // the default for TextView - Assert.True (view.Multiline); - - view.AllowsTab = false; - Assert.False (view.AllowsTab); - - Assert.True (view.Multiline); - } - [Fact] [TextViewTestsAutoInitShutdown] public void TextView_SpaceHandling () @@ -7704,17 +6090,6 @@ line. } } - [Fact] - public void WordBackward_WordForward_Limits_Return_Null () - { - var model = new TextModel (); - model.LoadString ("Test"); - (int col, int row)? newPos = model.WordBackward (0, 0); - Assert.Null (newPos); - newPos = model.WordForward (4, 0); - Assert.Null (newPos); - } - [Fact] [TextViewTestsAutoInitShutdown] public void WordForward_Multiline_With_Selection () @@ -7733,9 +6108,7 @@ line. while (!iterationsFinished) { _textView.NewKeyDownEvent ( - new ( - KeyCode.CursorRight | KeyCode.CtrlMask | KeyCode.ShiftMask - ) + Key.CursorRight.WithCtrl.WithShift ); switch (iteration) @@ -7777,6 +6150,15 @@ line. break; case 4: + Assert.Equal (22, _textView.CursorPosition.X); + Assert.Equal (0, _textView.CursorPosition.Y); + Assert.Equal (0, _textView.SelectionStartColumn); + Assert.Equal (0, _textView.SelectionStartRow); + Assert.Equal (22, _textView.SelectedLength); + Assert.Equal ("This is the first line", _textView.SelectedText); + + break; + case 5: Assert.Equal (23, _textView.CursorPosition.X); Assert.Equal (0, _textView.CursorPosition.Y); Assert.Equal (0, _textView.SelectionStartColumn); @@ -7785,7 +6167,7 @@ line. Assert.Equal ("This is the first line.", _textView.SelectedText); break; - case 5: + case 6: Assert.Equal (0, _textView.CursorPosition.X); Assert.Equal (1, _textView.CursorPosition.Y); Assert.Equal (0, _textView.SelectionStartColumn); @@ -7794,7 +6176,7 @@ line. Assert.Equal ($"This is the first line.{Environment.NewLine}", _textView.SelectedText); break; - case 6: + case 7: Assert.Equal (5, _textView.CursorPosition.X); Assert.Equal (1, _textView.CursorPosition.Y); Assert.Equal (0, _textView.SelectionStartColumn); @@ -7807,7 +6189,7 @@ line. ); break; - case 7: + case 8: Assert.Equal (8, _textView.CursorPosition.X); Assert.Equal (1, _textView.CursorPosition.Y); Assert.Equal (0, _textView.SelectionStartColumn); @@ -7820,7 +6202,7 @@ line. ); break; - case 8: + case 9: Assert.Equal (12, _textView.CursorPosition.X); Assert.Equal (1, _textView.CursorPosition.Y); Assert.Equal (0, _textView.SelectionStartColumn); @@ -7833,7 +6215,7 @@ line. ); break; - case 9: + case 10: Assert.Equal (19, _textView.CursorPosition.X); Assert.Equal (1, _textView.CursorPosition.Y); Assert.Equal (0, _textView.SelectionStartColumn); @@ -7846,7 +6228,20 @@ line. ); break; - case 10: + case 11: + Assert.Equal (23, _textView.CursorPosition.X); + Assert.Equal (1, _textView.CursorPosition.Y); + Assert.Equal (0, _textView.SelectionStartColumn); + Assert.Equal (0, _textView.SelectionStartRow); + Assert.Equal (46 + Environment.NewLine.Length, _textView.SelectedLength); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line", + _textView.SelectedText + ); + + break; + case 12: Assert.Equal (24, _textView.CursorPosition.X); Assert.Equal (1, _textView.CursorPosition.Y); Assert.Equal (0, _textView.SelectionStartColumn); @@ -7928,6 +6323,15 @@ line. break; case 5: + Assert.Equal (31, _textView.CursorPosition.X); + Assert.Equal (0, _textView.CursorPosition.Y); + Assert.Equal (0, _textView.SelectionStartColumn); + Assert.Equal (0, _textView.SelectionStartRow); + Assert.Equal (0, _textView.SelectedLength); + Assert.Equal ("", _textView.SelectedText); + + break; + case 6: Assert.Equal (32, _textView.CursorPosition.X); Assert.Equal (0, _textView.CursorPosition.Y); Assert.Equal (0, _textView.SelectionStartColumn); @@ -8075,9 +6479,7 @@ line. while (_textView.CursorPosition.X < _textView.Text.Length) { _textView.NewKeyDownEvent ( - new ( - KeyCode.CursorRight | KeyCode.CtrlMask | KeyCode.ShiftMask - ) + Key.CursorRight.WithCtrl.WithShift ); switch (iteration) @@ -8128,6 +6530,15 @@ line. break; case 5: + Assert.Equal (31, _textView.CursorPosition.X); + Assert.Equal (0, _textView.CursorPosition.Y); + Assert.Equal (0, _textView.SelectionStartColumn); + Assert.Equal (0, _textView.SelectionStartRow); + Assert.Equal (31, _textView.SelectedLength); + Assert.Equal ("TAB to jump between text fields", _textView.SelectedText); + + break; + case 6: Assert.Equal (32, _textView.CursorPosition.X); Assert.Equal (0, _textView.CursorPosition.Y); Assert.Equal (0, _textView.SelectionStartColumn); @@ -8155,9 +6566,7 @@ line. while (_textView.CursorPosition.X < _textView.Text.Length) { _textView.NewKeyDownEvent ( - new ( - KeyCode.CursorRight | KeyCode.CtrlMask | KeyCode.ShiftMask - ) + Key.CursorRight.WithCtrl.WithShift ); switch (iteration) @@ -8190,6 +6599,15 @@ line. break; case 3: + Assert.Equal (31, _textView.CursorPosition.X); + Assert.Equal (0, _textView.CursorPosition.Y); + Assert.Equal (10, _textView.SelectionStartColumn); + Assert.Equal (0, _textView.SelectionStartRow); + Assert.Equal (21, _textView.SelectedLength); + Assert.Equal ("p between text fields", _textView.SelectedText); + + break; + case 4: Assert.Equal (32, _textView.CursorPosition.X); Assert.Equal (0, _textView.CursorPosition.Y); Assert.Equal (10, _textView.SelectionStartColumn); @@ -8323,15 +6741,6 @@ Line 2.", top.Dispose (); } - [Fact] - public void WordWrap_Gets_Sets () - { - var tv = new TextView { WordWrap = true }; - Assert.True (tv.WordWrap); - tv.WordWrap = false; - Assert.False (tv.WordWrap); - } - [Fact] [AutoInitShutdown] public void WordWrap_Not_Throw_If_Width_Is_Less_Than_Zero () @@ -8437,25 +6846,6 @@ line. } } - [Fact] - public void WordWrap_True_Text_Always_Returns_Unwrapped () - { - var text = "This is the first line.\nThis is the second line.\n"; - var tv = new TextView { Width = 10 }; - tv.Text = text; - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", - tv.Text - ); - tv.WordWrap = true; - - Assert.Equal ( - $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", - tv.Text - ); - } - [Fact] [TextViewTestsAutoInitShutdown] public void WordWrap_WrapModel_Output () @@ -8582,305 +6972,6 @@ line. } } - [Fact] - public void HotKey_Command_SetsFocus () - { - var view = new TextView (); - - view.CanFocus = true; - Assert.False (view.HasFocus); - view.InvokeCommand (Command.HotKey); - Assert.True (view.HasFocus); - } - - [Fact] - public void HotKey_Command_Does_Not_Accept () - { - var view = new TextView (); - var accepted = false; - view.Accepting += OnAccept; - view.InvokeCommand (Command.HotKey); - - Assert.False (accepted); - - return; - - void OnAccept (object sender, CommandEventArgs e) { accepted = true; } - } - - [Theory] - [InlineData (false, 1)] - [InlineData (true, 1)] - public void Accepted_Command_Raises_Accepted_Regardles_Of_AllowsReturn (bool allowsReturn, int expectedAcceptEvents) - { - var view = new TextView - { - AllowsReturn = allowsReturn - }; - - var acceptedEvents = 0; - view.Accepting += Accept; - view.InvokeCommand (Command.Accept); - Assert.Equal (expectedAcceptEvents, acceptedEvents); - - return; - - void Accept (object sender, CommandEventArgs e) { acceptedEvents++; } - } - - [Theory] - [InlineData (false, 1)] - [InlineData (true, 0)] - public void Enter_Key_Fires_Accepted_BasedOn_AllowsReturn (bool allowsReturn, int expectedAccepts) - { - var view = new TextView - { - Multiline = allowsReturn - }; - - var accepted = 0; - view.Accepting += Accept; - view.NewKeyDownEvent (Key.Enter); - Assert.Equal (expectedAccepts, accepted); - - return; - - void Accept (object sender, CommandEventArgs e) { accepted++; } - } - - [Theory] - [InlineData (false, 1)] - [InlineData (true, 0)] - public void Enter_Key_Fires_Accepted_BasedOn_Multiline (bool multiline, int expectedAccepts) - { - var view = new TextView - { - Multiline = multiline - }; - - var accepted = 0; - view.Accepting += Accept; - view.NewKeyDownEvent (Key.Enter); - Assert.Equal (expectedAccepts, accepted); - - return; - - void Accept (object sender, CommandEventArgs e) { accepted++; } - } - - [Fact] - public void Space_Key_Types_Space () - { - var view = new TextView (); - - view.NewKeyDownEvent (Key.Space); - - Assert.Equal (" ", view.Text); - } - - [Theory] - [InlineData (false, false, 1, 1)] - [InlineData (false, true, 1, 0)] - [InlineData (true, false, 0, 0)] - [InlineData (true, true, 0, 0)] - public void Accepted_Event_Handled_Prevents_Default_Button_Accept (bool multiline, bool handleAccept, int expectedAccepts, int expectedButtonAccepts) - { - var superView = new Window (); - - var tv = new TextView - { - Multiline = multiline - }; - - var button = new Button - { - IsDefault = true - }; - - superView.Add (tv, button); - - var buttonAccept = 0; - button.Accepting += ButtonAccept; - - var textViewAccept = 0; - tv.Accepting += TextViewAccept; - - tv.SetFocus (); - Assert.True (tv.HasFocus); - - superView.NewKeyDownEvent (Key.Enter); - Assert.Equal (expectedAccepts, textViewAccept); - Assert.Equal (expectedButtonAccepts, buttonAccept); - - button.SetFocus (); - superView.NewKeyDownEvent (Key.Enter); - Assert.Equal (expectedAccepts, textViewAccept); - Assert.Equal (expectedButtonAccepts + 1, buttonAccept); - - return; - - void TextViewAccept (object sender, CommandEventArgs e) - { - textViewAccept++; - e.Handled = handleAccept; - } - - void ButtonAccept (object sender, CommandEventArgs e) { buttonAccept++; } - } - - [Theory] - [InlineData (true, 0)] - [InlineData (false, 1)] - public void Accepted_No_Handler_Enables_Default_Button_Accept (bool multiline, int expectedButtonAccept) - { - var superView = new Window (); - - var tv = new TextView - { - Multiline = multiline - }; - - var button = new Button - { - IsDefault = true - }; - - superView.Add (tv, button); - - var buttonAccept = 0; - button.Accepting += ButtonAccept; - - tv.SetFocus (); - Assert.True (tv.HasFocus); - - superView.NewKeyDownEvent (Key.Enter); - Assert.Equal (expectedButtonAccept, buttonAccept); - - button.SetFocus (); - superView.NewKeyDownEvent (Key.Enter); - Assert.Equal (expectedButtonAccept + 1, buttonAccept); - - return; - - void ButtonAccept (object sender, CommandEventArgs e) { buttonAccept++; } - } - - [Fact] - public void Autocomplete_Popup_Added_To_SuperView_On_Init () - { - View superView = new () - { - CanFocus = true - }; - - TextView t = new (); - - superView.Add (t); - Assert.Single (superView.SubViews); - - superView.BeginInit (); - superView.EndInit (); - - Assert.Equal (2, superView.SubViews.Count); - } - - [Fact] - public void Autocomplete__Added_To_SuperView_On_Add () - { - View superView = new () - { - CanFocus = true, - Id = "superView" - }; - - superView.BeginInit (); - superView.EndInit (); - Assert.Empty (superView.SubViews); - - TextView t = new () - { - Id = "t" - }; - - superView.Add (t); - - Assert.Equal (2, superView.SubViews.Count); - } - - [Fact] - public void Autocomplete_Visible_False_By_Default () - { - View superView = new () - { - CanFocus = true - }; - - TextView t = new (); - - superView.Add (t); - superView.BeginInit (); - superView.EndInit (); - - Assert.Equal (2, superView.SubViews.Count); - - Assert.True (t.Visible); - 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 () @@ -8895,22 +6986,6 @@ line. tv.Dispose (); } - [Fact] - public void Equals_True () - { - var c1 = new Cell (); - var c2 = new Cell (); - Assert.True (c1.Equals (c2)); - Assert.True (c2.Equals (c1)); - - c1.Rune = new ('a'); - c1.Attribute = new (); - c2.Rune = new ('a'); - c2.Attribute = new (); - Assert.True (c1.Equals (c2)); - Assert.True (c2.Equals (c1)); - } - [Fact] [AutoInitShutdown] public void CellEventArgs_WordWrap_True () @@ -9117,32 +7192,6 @@ ror "; top.Dispose (); } - [Fact] - public void Cell_LoadCells_Without_Scheme_Is_Never_Null () - { - List cells = new () - { - new () { Rune = new ('T') }, - new () { Rune = new ('e') }, - new () { Rune = new ('s') }, - new () { Rune = new ('t') } - }; - TextView tv = CreateTextView (); - var top = new Toplevel (); - top.Add (tv); - tv.Load (cells); - - for (var i = 0; i < tv.Lines; i++) - { - List line = tv.GetLine (i); - - foreach (Cell c in line) - { - Assert.NotNull (c.Attribute); - } - } - } - [Fact] [TextViewTestsAutoInitShutdown] public void IsSelecting_False_If_SelectedLength_Is_Zero_On_Mouse_Click () diff --git a/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs b/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs index e9ad057bb..a38f6188b 100644 --- a/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs +++ b/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs @@ -348,6 +348,9 @@ public class TextFieldTests tf.BeginInit (); tf.EndInit (); + Assert.False (tf.UseSameRuneTypeForWords); + Assert.Equal (22, tf.CursorPosition); + tf.NewKeyDownEvent (Key.CursorLeft.WithCtrl); Assert.Equal (15, tf.CursorPosition); tf.NewKeyDownEvent (Key.CursorLeft.WithCtrl); @@ -402,14 +405,14 @@ public class TextFieldTests new () { Position = new (idx, 1), Flags = MouseFlags.Button1DoubleClicked, View = tf } ) ); - Assert.Equal ("movie.", tf.SelectedText); + Assert.Equal ("movie", tf.SelectedText); Assert.True ( tf.NewMouseEvent ( new () { Position = new (idx + 1, 1), Flags = MouseFlags.Button1DoubleClicked, View = tf } ) ); - Assert.Equal ("movie.", tf.SelectedText); + Assert.Equal ("movie", tf.SelectedText); } [Fact] diff --git a/Tests/UnitTestsParallelizable/Views/TextViewTests.cs b/Tests/UnitTestsParallelizable/Views/TextViewTests.cs new file mode 100644 index 000000000..ffe6a67e1 --- /dev/null +++ b/Tests/UnitTestsParallelizable/Views/TextViewTests.cs @@ -0,0 +1,2408 @@ +using System.Text; + +namespace Terminal.Gui.ViewsTests; + +public class TextViewTests +{ + [Fact] + public void CloseFile_Throws_If_FilePath_Is_Null () + { + var tv = new TextView (); + Assert.Throws (() => tv.CloseFile ()); + } + + [Fact] + public void ContentsChanged_Event_Fires_ClearHistoryChanges () + { + var eventcount = 0; + + var text = "This is the first line.\nThis is the second line.\nThis is the third line."; + var tv = new TextView { Width = 50, Height = 10, Text = text }; + tv.ContentsChanged += (s, e) => { eventcount++; }; + + Assert.True (tv.NewKeyDownEvent (Key.Enter)); + + Assert.Equal ( + $"{Environment.NewLine}This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + + var expectedEventCount = 1; // for ENTER key + Assert.Equal (expectedEventCount, eventcount); + + tv.ClearHistoryChanges (); + expectedEventCount = 2; + Assert.Equal (expectedEventCount, eventcount); + } + + [Fact] + public void ContentsChanged_Event_Fires_LoadStream_By_Calling_HistoryText_Clear () + { + var eventcount = 0; + + var tv = new TextView { Width = 50, Height = 10 }; + tv.ContentsChanged += (s, e) => { eventcount++; }; + + var text = "This is the first line.\r\nThis is the second line.\r\n"; + tv.Load (new MemoryStream (Encoding.ASCII.GetBytes (text))); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", + tv.Text + ); + + Assert.Equal (1, eventcount); + } + + [Fact] + public void ContentsChanged_Event_Fires_On_LoadFile_By_Calling_HistoryText_Clear () + { + var eventcount = 0; + + var tv = new TextView { Width = 50, Height = 10 }; + tv.BeginInit (); + tv.EndInit (); + + tv.ContentsChanged += (s, e) => { eventcount++; }; + + var fileName = "textview.txt"; + File.WriteAllText (fileName, "This is the first line.\r\nThis is the second line.\r\n"); + + tv.Load (fileName); + Assert.Equal (1, eventcount); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", + tv.Text + ); + } + + [Fact] + public void GetRegion_StringFromRunes_Environment_NewLine () + { + var tv = new TextView { Text = $"1{Environment.NewLine}2" }; + + Assert.Equal ($"1{Environment.NewLine}2", tv.Text); + Assert.Equal ("", tv.SelectedText); + + tv.SelectAll (); + Assert.Equal ($"1{Environment.NewLine}2", tv.Text); + Assert.Equal ($"1{Environment.NewLine}2", tv.SelectedText); + } + + [Fact] + public void HistoryText_ClearHistoryChanges () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line."; + var tv = new TextView { Text = text }; + + Assert.True (tv.NewKeyDownEvent (Key.Enter)); + + Assert.Equal ( + $"{Environment.NewLine}This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + Assert.True (tv.IsDirty); + Assert.True (tv.HasHistoryChanges); + + tv.ClearHistoryChanges (); + + Assert.Equal ( + $"{Environment.NewLine}This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + Assert.False (tv.IsDirty); + Assert.False (tv.HasHistoryChanges); + } + + [Fact] + public void HistoryText_Exceptions () + { + var ht = new HistoryText (); + + foreach (object ls in Enum.GetValues (typeof (TextEditingLineStatus))) + { + if ((TextEditingLineStatus)ls != TextEditingLineStatus.Original) + { + Assert.Throws ( + () => ht.Add ( + new List> (), + Point.Empty, + (TextEditingLineStatus)ls + ) + ); + } + } + + Assert.Null (Record.Exception (() => ht.Add (new () { new () }, Point.Empty))); + } + + [Fact] + public void HistoryText_IsDirty_HasHistoryChanges () + { + var tv = new TextView (); + + Assert.Equal ("", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + Assert.False (tv.IsDirty); + Assert.False (tv.HasHistoryChanges); + + Assert.True (tv.NewKeyDownEvent (Key.D1)); + Assert.Equal ("1", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (1, 0), tv.CursorPosition); + Assert.True (tv.IsDirty); + Assert.True (tv.HasHistoryChanges); + + Assert.True (tv.NewKeyDownEvent (Key.Enter)); + Assert.Equal ($"1{Environment.NewLine}", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + Assert.True (tv.IsDirty); + Assert.True (tv.HasHistoryChanges); + + Assert.True (tv.NewKeyDownEvent (Key.D2)); + Assert.Equal ($"1{Environment.NewLine}2", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (1, 1), tv.CursorPosition); + Assert.True (tv.IsDirty); + Assert.True (tv.HasHistoryChanges); + + Assert.True (tv.NewKeyDownEvent (Key.Backspace)); + Assert.Equal ($"1{Environment.NewLine}", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + Assert.True (tv.IsDirty); + Assert.True (tv.HasHistoryChanges); + + Assert.True (tv.NewKeyDownEvent (Key.Backspace)); + Assert.Equal ("1", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (1, 0), tv.CursorPosition); + Assert.True (tv.IsDirty); + Assert.True (tv.HasHistoryChanges); + + Assert.True (tv.NewKeyDownEvent (Key.Backspace)); + Assert.Equal ("", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + // IsDirty cannot be based on HasHistoryChanges because HasHistoryChanges is greater than 0 + // The only way is comparing from the original text + Assert.False (tv.IsDirty); + + // Still true because HasHistoryChanges is greater than 0 + Assert.True (tv.HasHistoryChanges); + } + + [Fact] + public void HistoryText_Undo_Redo_Changing_On_Middle_Clear_History_Forwards () + { + var tv = new TextView (); + + Assert.True (tv.NewKeyDownEvent (Key.D1)); + Assert.Equal ("1", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (1, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.D2)); + Assert.Equal ("12", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (2, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.D3)); + Assert.Equal ("123", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (3, 0), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ("12", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (2, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.D4)); + Assert.Equal ("124", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (3, 0), tv.CursorPosition); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ("124", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (3, 0), tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_Disabled_On_WordWrap () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line.\n"; + var tv = new TextView { Width = 80, Height = 5, Text = text }; + + Assert.False (tv.WordWrap); + tv.WordWrap = true; + + tv.SelectionStartColumn = 12; + tv.CursorPosition = new (12, 2); + + Assert.True (tv.NewKeyDownEvent (Key.Enter)); + Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.A)); + Assert.Equal ($"This is the {Environment.NewLine}athird line.{Environment.NewLine}", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (1, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + Assert.True (tv.IsDirty); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"This is the {Environment.NewLine}athird line.{Environment.NewLine}", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (1, 1), tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_Ending_With_Newline_Multi_Line_Selected_Almost_All_Return_And_InsertText () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line.\n"; + var tv = new TextView { Text = text }; + + tv.SelectionStartColumn = 12; + tv.CursorPosition = new (12, 2); + + Assert.True (tv.NewKeyDownEvent (Key.Enter)); + Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.A)); + Assert.Equal ($"This is the {Environment.NewLine}athird line.{Environment.NewLine}", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (1, 1), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + Assert.True (tv.IsDirty); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.{Environment.NewLine}", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (12, 2), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"This is the {Environment.NewLine}athird line.{Environment.NewLine}", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (1, 1), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + Assert.True (tv.IsDirty); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.{Environment.NewLine}", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (12, 2), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"This is the {Environment.NewLine}third line.{Environment.NewLine}", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"This is the {Environment.NewLine}athird line.{Environment.NewLine}", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (1, 1), tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_First_Line_Selected_Return_And_InsertText () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line."; + var tv = new TextView { Text = text }; + + tv.SelectionStartColumn = 12; + tv.CursorPosition = new (17, 0); + + Assert.True (tv.NewKeyDownEvent (Key.Enter)); + + Assert.Equal ( + $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.A)); + + Assert.Equal ( + $"This is the {Environment.NewLine}a line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (1, 1), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + Assert.True (tv.IsDirty); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (17, 0), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the {Environment.NewLine}a line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (1, 1), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + Assert.True (tv.IsDirty); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (17, 0), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the {Environment.NewLine}a line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (1, 1), tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_KillWordBackward () + { + var text = "First line.\nSecond line."; + var tv = new TextView { Text = text }; + + Assert.True (tv.NewKeyDownEvent (Key.End.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}Second line.", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (12, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}Second line", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (11, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}Second ", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (7, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); + Assert.Equal ("First line.", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (11, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); + Assert.Equal ("First line", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (10, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); + Assert.Equal ("First ", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (6, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Backspace.WithCtrl)); + Assert.Equal ("", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ("First ", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (6, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ("First line", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (10, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ("First line.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (11, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}Second ", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (7, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}Second line", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (11, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}Second line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (12, 1), tv.CursorPosition); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}Second line", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (11, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}Second ", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (7, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ("First line.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (11, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ("First line", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (10, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ("First ", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (6, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ("", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_KillWordForward () + { + var text = "First line.\nSecond line."; + var tv = new TextView { Text = text }; + + Assert.True (tv.NewKeyDownEvent (Key.Delete.WithCtrl)); + Assert.Equal ($"line.{Environment.NewLine}Second line.", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (2, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Delete.WithCtrl)); + Assert.Equal ($".{Environment.NewLine}Second line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Delete.WithCtrl)); + Assert.Equal ($"{Environment.NewLine}Second line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Delete.WithCtrl)); + Assert.Equal ("Second line.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Delete.WithCtrl)); + Assert.Equal ("line.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Delete.WithCtrl)); + Assert.Equal (".", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Delete.WithCtrl)); + Assert.Equal ("", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal (".", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ("line.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ("Second line.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"{Environment.NewLine}Second line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($".{Environment.NewLine}Second line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"line.{Environment.NewLine}Second line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}Second line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"line.{Environment.NewLine}Second line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($".{Environment.NewLine}Second line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"{Environment.NewLine}Second line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ("Second line.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ("line.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal (".", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ("", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_Multi_Line_Selected_All_Return_And_InsertText () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line."; + var tv = new TextView { Text = text }; + + Assert.True (tv.NewKeyDownEvent (Key.End.WithCtrl.WithShift)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (23, 2), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Enter)); + Assert.Equal ($"{Environment.NewLine}", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.A)); + Assert.Equal ($"{Environment.NewLine}a", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (1, 1), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"{Environment.NewLine}", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + Assert.True (tv.IsDirty); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (23, 2), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"{Environment.NewLine}", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"{Environment.NewLine}a", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (1, 1), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"{Environment.NewLine}", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + Assert.True (tv.IsDirty); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (23, 2), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"{Environment.NewLine}", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"{Environment.NewLine}a", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (1, 1), tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_Multi_Line_Selected_DeleteCharLeft_All () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line."; + var tv = new TextView { Text = text }; + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + Assert.False (tv.IsDirty); + Assert.False (tv.HasHistoryChanges); + + Assert.True (tv.NewKeyDownEvent (Key.End.WithCtrl.WithShift)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.SelectedText + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (23, 2), tv.CursorPosition); + Assert.Equal (70 + Environment.NewLine.Length * 2, tv.SelectedLength); + Assert.False (tv.IsDirty); + Assert.False (tv.HasHistoryChanges); + + Assert.True (tv.NewKeyDownEvent (Key.Backspace)); + Assert.Equal ("", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + Assert.Equal (0, tv.SelectedLength); + Assert.True (tv.IsDirty); + Assert.True (tv.HasHistoryChanges); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (23, 2), tv.CursorPosition); + Assert.Equal (0, tv.SelectedLength); + Assert.False (tv.IsDirty); + Assert.True (tv.HasHistoryChanges); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ("", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + Assert.Equal (0, tv.SelectedLength); + Assert.True (tv.IsDirty); + Assert.True (tv.HasHistoryChanges); + } + + [Fact] + public void HistoryText_Undo_Redo_Multi_Line_Selected_DeleteCharRight_All () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line."; + var tv = new TextView { Text = text }; + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + Assert.False (tv.IsDirty); + Assert.False (tv.HasHistoryChanges); + + Assert.True (tv.NewKeyDownEvent (Key.End.WithCtrl.WithShift)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.SelectedText + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (23, 2), tv.CursorPosition); + Assert.Equal (70 + Environment.NewLine.Length * 2, tv.SelectedLength); + Assert.False (tv.IsDirty); + Assert.False (tv.HasHistoryChanges); + + Assert.True (tv.NewKeyDownEvent (Key.Delete)); + Assert.Equal ("", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + Assert.Equal (0, tv.SelectedLength); + Assert.True (tv.IsDirty); + Assert.True (tv.HasHistoryChanges); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (23, 2), tv.CursorPosition); + Assert.Equal (0, tv.SelectedLength); + Assert.False (tv.IsDirty); + Assert.True (tv.HasHistoryChanges); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ("", tv.Text); + Assert.Equal ("", tv.SelectedText); + Assert.Equal (1, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + Assert.Equal (0, tv.SelectedLength); + Assert.True (tv.IsDirty); + Assert.True (tv.HasHistoryChanges); + } + + [Fact] + public void HistoryText_Undo_Redo_Multiline_Selected_Tab_BackTab () + { + var text = "First line.\nSecond line.\nThird line."; + var tv = new TextView { Width = 80, Height = 5, Text = text }; + + tv.SelectionStartColumn = 6; + tv.CursorPosition = new (6, 2); + + Assert.True (tv.NewKeyDownEvent (Key.Tab)); + Assert.Equal ("First \tline.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (7, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Tab.WithShift)); + Assert.Equal ("First line.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (6, 0), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ("First \tline.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (7, 0), tv.CursorPosition); + Assert.True (tv.IsDirty); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (6, 2), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ("First \tline.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (7, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ("First line.", tv.Text); + Assert.Equal (1, tv.Lines); + Assert.Equal (new (6, 0), tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_Multiline_Simples_Tab_BackTab () + { + var text = "First line.\nSecond line.\nThird line."; + var tv = new TextView { Width = 80, Height = 5, Text = text }; + + Assert.True (tv.NewKeyDownEvent (Key.Tab)); + + Assert.Equal ( + $"\tFirst line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (1, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.Tab.WithShift)); + Assert.Equal ($"First line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"\tFirst line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (1, 0), tv.CursorPosition); + Assert.True (tv.IsDirty); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"\tFirst line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (1, 0), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"First line.{Environment.NewLine}Second line.{Environment.NewLine}Third line.", tv.Text); + Assert.Equal (3, tv.Lines); + Assert.Equal (Point.Empty, tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_Single_Line_Selected_Return () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line."; + var tv = new TextView { Text = text }; + + tv.SelectionStartColumn = 12; + tv.CursorPosition = new (17, 0); + + Assert.True (tv.NewKeyDownEvent (Key.Enter)); + + Assert.Equal ( + $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (17, 0), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (17, 0), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_Single_Second_Line_Selected_Return () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line."; + var tv = new TextView { Text = text }; + + tv.SelectionStartColumn = 12; + tv.SelectionStartRow = 1; + tv.CursorPosition = new (18, 1); + + Assert.True (tv.NewKeyDownEvent (Key.Enter)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 2), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (18, 1), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 2), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (18, 1), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 2), tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_Single_Second_Line_Selected_Return_And_InsertText () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line."; + var tv = new TextView { Text = text }; + + tv.SelectionStartColumn = 12; + tv.SelectionStartRow = 1; + tv.CursorPosition = new (18, 1); + + Assert.True (tv.NewKeyDownEvent (Key.Enter)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 2), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.A)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine}a line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (1, 2), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 2), tv.CursorPosition); + Assert.True (tv.IsDirty); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (18, 1), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 2), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine}a line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (1, 2), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 2), tv.CursorPosition); + Assert.True (tv.IsDirty); + + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (18, 1), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (0, 2), tv.CursorPosition); + + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the {Environment.NewLine}a line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (4, tv.Lines); + Assert.Equal (new (1, 2), tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_Three_Line_Selected_Return () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line."; + var tv = new TextView { Text = text }; + + tv.SelectionStartColumn = 12; + tv.CursorPosition = new (17, 2); + + Assert.True (tv.NewKeyDownEvent (Key.Enter)); + Assert.Equal ($"This is the {Environment.NewLine} line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (17, 2), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"This is the {Environment.NewLine} line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (17, 2), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + Assert.Equal ($"This is the {Environment.NewLine} line.", tv.Text); + Assert.Equal (2, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_Two_Line_Selected_Return () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line."; + var tv = new TextView { Text = text }; + + tv.SelectionStartColumn = 12; + tv.CursorPosition = new (18, 1); + + Assert.True (tv.NewKeyDownEvent (Key.Enter)); + + Assert.Equal ( + $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (18, 1), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (18, 1), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + Assert.Equal ( + $"This is the {Environment.NewLine} line.{Environment.NewLine}This is the third line.", + tv.Text + ); + Assert.Equal (3, tv.Lines); + Assert.Equal (new (0, 1), tv.CursorPosition); + } + + [Fact] + public void HistoryText_Undo_Redo_ApplyCellsAttribute () + { + var text = "This is the first line.\nThis is the second line.\nThis is the third line."; + var tv = new TextView { Text = text }; + + tv.SelectionStartColumn = 12; + tv.CursorPosition = new (18, 1); + + if (Environment.NewLine.Length == 2) + { + Assert.Equal (31, tv.SelectedLength); + } + else + { + Assert.Equal (30, tv.SelectedLength); + } + + Assert.Equal ($"first line.{Environment.NewLine}This is the second", tv.SelectedText); + Assert.Equal ($"first line.{Environment.NewLine}This is the second", Cell.ToString (tv.SelectedCellsList)); + Assert.Equal (new (18, 1), tv.CursorPosition); + Assert.False (tv.IsDirty); + + AssertNullAttribute (); + + tv.ApplyCellsAttribute (new (Color.Red, Color.Green)); + + AssertRedGreenAttribute (); + + Assert.Equal (0, tv.SelectedLength); + Assert.Equal ("", tv.SelectedText); + Assert.Equal ($"first line.{Environment.NewLine}This is the second", Cell.ToString (tv.SelectedCellsList)); + Assert.Equal (new (18, 1), tv.CursorPosition); + Assert.True (tv.IsDirty); + + // Undo + Assert.True (tv.NewKeyDownEvent (Key.Z.WithCtrl)); + + AssertNullAttribute (); + + Assert.Equal (12, tv.SelectionStartColumn); + Assert.Equal (0, tv.SelectionStartRow); + Assert.Equal (0, tv.SelectedLength); + Assert.Equal ("", tv.SelectedText); + Assert.Empty (tv.SelectedCellsList); + Assert.Equal (new (12, 0), tv.CursorPosition); + Assert.False (tv.IsDirty); + + // Redo + Assert.True (tv.NewKeyDownEvent (Key.R.WithCtrl)); + + AssertRedGreenAttribute (); + + Assert.Equal (12, tv.SelectionStartColumn); + Assert.Equal (0, tv.SelectionStartRow); + Assert.Equal (0, tv.SelectedLength); + Assert.Equal ("", tv.SelectedText); + Assert.Empty (tv.SelectedCellsList); + Assert.Equal (new (12, 0), tv.CursorPosition); + Assert.True (tv.IsDirty); + + void AssertNullAttribute () + { + tv.GetRegion (out List> region, 0, 12, 1, 18); + + foreach (List cells in region) + { + foreach (Cell cell in cells) + { + Assert.Null (cell.Attribute); + } + } + } + + void AssertRedGreenAttribute () + { + tv.GetRegion (out List> region, 0, 12, 1, 18); + + foreach (List cells in region) + { + foreach (Cell cell in cells) + { + Assert.Equal ("[Red,Green,None]", cell.Attribute.ToString ()); + } + } + } + } + + [Fact] + public void Internal_Tests () + { + var txt = "This is a text."; + List txtRunes = Cell.StringToCells (txt); + Assert.Equal (txt.Length, txtRunes.Count); + Assert.Equal ('T', txtRunes [0].Rune.Value); + Assert.Equal ('h', txtRunes [1].Rune.Value); + Assert.Equal ('i', txtRunes [2].Rune.Value); + Assert.Equal ('s', txtRunes [3].Rune.Value); + Assert.Equal (' ', txtRunes [4].Rune.Value); + Assert.Equal ('i', txtRunes [5].Rune.Value); + Assert.Equal ('s', txtRunes [6].Rune.Value); + Assert.Equal (' ', txtRunes [7].Rune.Value); + Assert.Equal ('a', txtRunes [8].Rune.Value); + Assert.Equal (' ', txtRunes [9].Rune.Value); + Assert.Equal ('t', txtRunes [10].Rune.Value); + Assert.Equal ('e', txtRunes [11].Rune.Value); + Assert.Equal ('x', txtRunes [12].Rune.Value); + Assert.Equal ('t', txtRunes [13].Rune.Value); + Assert.Equal ('.', txtRunes [^1].Rune.Value); + + var col = 0; + Assert.True (TextModel.SetCol (ref col, 80, 79)); + Assert.False (TextModel.SetCol (ref col, 80, 80)); + Assert.Equal (79, col); + + var start = 0; + var x = 8; + Assert.Equal (8, TextModel.GetColFromX (txtRunes, start, x)); + Assert.Equal ('a', txtRunes [start + x].Rune.Value); + start = 1; + x = 7; + Assert.Equal (7, TextModel.GetColFromX (txtRunes, start, x)); + Assert.Equal ('a', txtRunes [start + x].Rune.Value); + + Assert.Equal ((15, 15), TextModel.DisplaySize (txtRunes)); + Assert.Equal ((6, 6), TextModel.DisplaySize (txtRunes, 1, 7)); + + Assert.Equal (0, TextModel.CalculateLeftColumn (txtRunes, 0, 7, 8)); + Assert.Equal (1, TextModel.CalculateLeftColumn (txtRunes, 0, 8, 8)); + Assert.Equal (2, TextModel.CalculateLeftColumn (txtRunes, 0, 9, 8)); + + var tm = new TextModel (); + tm.AddLine (0, Cell.StringToCells ("This is first line.")); + tm.AddLine (1, Cell.StringToCells ("This is last line.")); + Assert.Equal ((new Point (2, 0), true), tm.FindNextText ("is", out bool gaveFullTurn)); + Assert.False (gaveFullTurn); + Assert.Equal ((new Point (5, 0), true), tm.FindNextText ("is", out gaveFullTurn)); + Assert.False (gaveFullTurn); + Assert.Equal ((new Point (2, 1), true), tm.FindNextText ("is", out gaveFullTurn)); + Assert.False (gaveFullTurn); + Assert.Equal ((new Point (5, 1), true), tm.FindNextText ("is", out gaveFullTurn)); + Assert.False (gaveFullTurn); + Assert.Equal ((new Point (2, 0), true), tm.FindNextText ("is", out gaveFullTurn)); + Assert.True (gaveFullTurn); + tm.ResetContinuousFind (Point.Empty); + Assert.Equal ((new Point (5, 1), true), tm.FindPreviousText ("is", out gaveFullTurn)); + Assert.False (gaveFullTurn); + Assert.Equal ((new Point (2, 1), true), tm.FindPreviousText ("is", out gaveFullTurn)); + Assert.False (gaveFullTurn); + Assert.Equal ((new Point (5, 0), true), tm.FindPreviousText ("is", out gaveFullTurn)); + Assert.False (gaveFullTurn); + Assert.Equal ((new Point (2, 0), true), tm.FindPreviousText ("is", out gaveFullTurn)); + Assert.False (gaveFullTurn); + Assert.Equal ((new Point (5, 1), true), tm.FindPreviousText ("is", out gaveFullTurn)); + Assert.True (gaveFullTurn); + + Assert.Equal ((new Point (9, 1), true), tm.ReplaceAllText ("is", false, false, "really")); + Assert.Equal (Cell.StringToCells ("Threally really first line."), tm.GetLine (0)); + Assert.Equal (Cell.StringToCells ("Threally really last line."), tm.GetLine (1)); + tm = new (); + tm.AddLine (0, Cell.StringToCells ("This is first line.")); + tm.AddLine (1, Cell.StringToCells ("This is last line.")); + Assert.Equal ((new Point (5, 1), true), tm.ReplaceAllText ("is", false, true, "really")); + Assert.Equal (Cell.StringToCells ("This really first line."), tm.GetLine (0)); + Assert.Equal (Cell.StringToCells ("This really last line."), tm.GetLine (1)); + } + + [Fact] + public void LeftColumn_Add_One_If_Text_Length_Is_Equal_To_Width () + { + var tv = new TextView { Width = 10, Text = "1234567890" }; + + Assert.Equal (Point.Empty, tv.CursorPosition); + Assert.Equal (0, tv.LeftColumn); + + tv.CursorPosition = new (9, 0); + Assert.Equal (new (9, 0), tv.CursorPosition); + Assert.Equal (0, tv.LeftColumn); + + Assert.True (tv.NewKeyDownEvent (Key.CursorRight)); + tv.CursorPosition = new (10, 0); + Assert.Equal (new (10, 0), tv.CursorPosition); + Assert.Equal (1, tv.LeftColumn); + } + + [Fact] + public void LoadFile_Throws_If_File_Is_Empty () + { + var result = false; + var tv = new TextView (); + Assert.Throws (() => result = tv.Load ("")); + Assert.False (result); + } + + [Fact] + public void LoadFile_Throws_If_File_Is_Null () + { + var result = false; + var tv = new TextView (); + Assert.Throws (() => result = tv.Load ((string)null)); + Assert.False (result); + } + + [Fact] + public void LoadFile_Throws_If_File_Not_Exist () + { + var result = false; + var tv = new TextView (); + Assert.Throws (() => result = tv.Load ("blabla")); + Assert.False (result); + } + + [Fact] + public void LoadStream_CRLF () + { + var text = "This is the first line.\r\nThis is the second line.\r\n"; + var tv = new TextView (); + tv.Load (new MemoryStream (Encoding.ASCII.GetBytes (text))); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", + tv.Text + ); + } + + [Fact] + public void LoadStream_IsDirty () + { + var text = "Testing"; + + using (var stream = new MemoryStream ()) + { + var writer = new StreamWriter (stream); + writer.Write (text); + writer.Flush (); + stream.Position = 0; + + var tv = new TextView (); + tv.Load (stream); + + Assert.Equal (7, text.Length); + Assert.Equal (text.Length, tv.Text.Length); + Assert.Equal (text, tv.Text); + Assert.False (tv.IsDirty); + } + } + + [Fact] + public void LoadStream_IsDirty_With_Null_On_The_Text () + { + var text = "Test\0ing"; + + using (var stream = new MemoryStream ()) + { + var writer = new StreamWriter (stream); + writer.Write (text); + writer.Flush (); + stream.Position = 0; + + var tv = new TextView (); + tv.Load (stream); + + Assert.Equal (8, text.Length); + Assert.Equal (text.Length, tv.Text.Length); + Assert.Equal (8, text.Length); + Assert.Equal (8, tv.Text.Length); + Assert.Equal (text, tv.Text); + Assert.False (tv.IsDirty); + Assert.Equal ((Rune)'\u2400', ((Rune)tv.Text [4]).MakePrintable ()); + } + } + + [Fact] + public void LoadStream_LF () + { + var text = "This is the first line.\nThis is the second line.\n"; + var tv = new TextView (); + tv.Load (new MemoryStream (Encoding.ASCII.GetBytes (text))); + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", + tv.Text + ); + } + + [Fact] + public void LoadStream_Stream_Is_Empty () + { + var tv = new TextView (); + tv.Load (new MemoryStream ()); + Assert.Equal ("", tv.Text); + } + + [Fact] + public void LoadStream_Throws_If_Stream_Is_Null () + { + var tv = new TextView (); + Assert.Throws (() => tv.Load ((Stream)null)); + } + + [Fact] + public void ReplaceAllText_Does_Not_Throw_Exception () + { + var textToFind = "hello! hello!"; + var textToReplace = "hello!"; + var tv = new TextView { Width = 20, Height = 3, Text = textToFind }; + + Exception exception = Record.Exception (() => tv.ReplaceAllText (textToFind, false, false, textToReplace)); + Assert.Null (exception); + Assert.Equal (textToReplace, tv.Text); + } + + [Fact] + public void StringToRunes_Slipts_CRLF () + { + var text = "This is the first line.\r\nThis is the second line.\r\n"; + var tv = new TextView (); + tv.Text = text; + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", + tv.Text + ); + } + + [Fact] + public void StringToRunes_Slipts_LF () + { + var text = "This is the first line.\nThis is the second line.\n"; + var tv = new TextView (); + tv.Text = text; + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", + tv.Text + ); + } + + [Fact] + public void TextView_MultiLine_But_Without_Tabs () + { + var view = new TextView (); + + // the default for TextView + Assert.True (view.Multiline); + + view.AllowsTab = false; + Assert.False (view.AllowsTab); + + Assert.True (view.Multiline); + } + + [Fact] + public void WordBackward_WordForward_Limits_Return_Null () + { + var model = new TextModel (); + model.LoadString ("Test"); + (int col, int row)? newPos = model.WordBackward (0, 0, false); + Assert.Null (newPos); + newPos = model.WordForward (4, 0, false); + Assert.Null (newPos); + } + + [Fact] + public void WordWrap_Gets_Sets () + { + var tv = new TextView { WordWrap = true }; + Assert.True (tv.WordWrap); + tv.WordWrap = false; + Assert.False (tv.WordWrap); + } + + [Fact] + public void WordWrap_True_Text_Always_Returns_Unwrapped () + { + var text = "This is the first line.\nThis is the second line.\n"; + var tv = new TextView { Width = 10 }; + tv.Text = text; + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", + tv.Text + ); + tv.WordWrap = true; + + Assert.Equal ( + $"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", + tv.Text + ); + } + + [Fact] + public void HotKey_Command_SetsFocus () + { + var view = new TextView (); + + view.CanFocus = true; + Assert.False (view.HasFocus); + view.InvokeCommand (Command.HotKey); + Assert.True (view.HasFocus); + } + + [Fact] + public void HotKey_Command_Does_Not_Accept () + { + var view = new TextView (); + var accepted = false; + view.Accepting += OnAccept; + view.InvokeCommand (Command.HotKey); + + Assert.False (accepted); + + return; + + void OnAccept (object sender, CommandEventArgs e) { accepted = true; } + } + + [Theory] + [InlineData (false, 1)] + [InlineData (true, 1)] + public void Accepted_Command_Raises_Accepted_Regardles_Of_AllowsReturn (bool allowsReturn, int expectedAcceptEvents) + { + var view = new TextView + { + AllowsReturn = allowsReturn + }; + + var acceptedEvents = 0; + view.Accepting += Accept; + view.InvokeCommand (Command.Accept); + Assert.Equal (expectedAcceptEvents, acceptedEvents); + + return; + + void Accept (object sender, CommandEventArgs e) { acceptedEvents++; } + } + + [Theory] + [InlineData (false, 1)] + [InlineData (true, 0)] + public void Enter_Key_Fires_Accepted_BasedOn_AllowsReturn (bool allowsReturn, int expectedAccepts) + { + var view = new TextView + { + Multiline = allowsReturn + }; + + var accepted = 0; + view.Accepting += Accept; + view.NewKeyDownEvent (Key.Enter); + Assert.Equal (expectedAccepts, accepted); + + return; + + void Accept (object sender, CommandEventArgs e) { accepted++; } + } + + [Theory] + [InlineData (false, 1)] + [InlineData (true, 0)] + public void Enter_Key_Fires_Accepted_BasedOn_Multiline (bool multiline, int expectedAccepts) + { + var view = new TextView + { + Multiline = multiline + }; + + var accepted = 0; + view.Accepting += Accept; + view.NewKeyDownEvent (Key.Enter); + Assert.Equal (expectedAccepts, accepted); + + return; + + void Accept (object sender, CommandEventArgs e) { accepted++; } + } + + [Fact] + public void Space_Key_Types_Space () + { + var view = new TextView (); + + view.NewKeyDownEvent (Key.Space); + + Assert.Equal (" ", view.Text); + } + + [Theory] + [InlineData (false, false, 1, 1)] + [InlineData (false, true, 1, 0)] + [InlineData (true, false, 0, 0)] + [InlineData (true, true, 0, 0)] + public void Accepted_Event_Handled_Prevents_Default_Button_Accept (bool multiline, bool handleAccept, int expectedAccepts, int expectedButtonAccepts) + { + var superView = new Window (); + + var tv = new TextView + { + Multiline = multiline + }; + + var button = new Button + { + IsDefault = true + }; + + superView.Add (tv, button); + + var buttonAccept = 0; + button.Accepting += ButtonAccept; + + var textViewAccept = 0; + tv.Accepting += TextViewAccept; + + tv.SetFocus (); + Assert.True (tv.HasFocus); + + superView.NewKeyDownEvent (Key.Enter); + Assert.Equal (expectedAccepts, textViewAccept); + Assert.Equal (expectedButtonAccepts, buttonAccept); + + button.SetFocus (); + superView.NewKeyDownEvent (Key.Enter); + Assert.Equal (expectedAccepts, textViewAccept); + Assert.Equal (expectedButtonAccepts + 1, buttonAccept); + + return; + + void TextViewAccept (object sender, CommandEventArgs e) + { + textViewAccept++; + e.Handled = handleAccept; + } + + void ButtonAccept (object sender, CommandEventArgs e) { buttonAccept++; } + } + + [Theory] + [InlineData (true, 0)] + [InlineData (false, 1)] + public void Accepted_No_Handler_Enables_Default_Button_Accept (bool multiline, int expectedButtonAccept) + { + var superView = new Window (); + + var tv = new TextView + { + Multiline = multiline + }; + + var button = new Button + { + IsDefault = true + }; + + superView.Add (tv, button); + + var buttonAccept = 0; + button.Accepting += ButtonAccept; + + tv.SetFocus (); + Assert.True (tv.HasFocus); + + superView.NewKeyDownEvent (Key.Enter); + Assert.Equal (expectedButtonAccept, buttonAccept); + + button.SetFocus (); + superView.NewKeyDownEvent (Key.Enter); + Assert.Equal (expectedButtonAccept + 1, buttonAccept); + + return; + + void ButtonAccept (object sender, CommandEventArgs e) { buttonAccept++; } + } + + [Fact] + public void Autocomplete_Popup_Added_To_SuperView_On_Init () + { + View superView = new () + { + CanFocus = true + }; + + TextView t = new (); + + superView.Add (t); + Assert.Single (superView.SubViews); + + superView.BeginInit (); + superView.EndInit (); + + Assert.Equal (2, superView.SubViews.Count); + } + + [Fact] + public void Autocomplete__Added_To_SuperView_On_Add () + { + View superView = new () + { + CanFocus = true, + Id = "superView" + }; + + superView.BeginInit (); + superView.EndInit (); + Assert.Empty (superView.SubViews); + + TextView t = new () + { + Id = "t" + }; + + superView.Add (t); + + Assert.Equal (2, superView.SubViews.Count); + } + + [Fact] + public void Autocomplete_Visible_False_By_Default () + { + View superView = new () + { + CanFocus = true + }; + + TextView t = new (); + + superView.Add (t); + superView.BeginInit (); + superView.EndInit (); + + Assert.Equal (2, superView.SubViews.Count); + + Assert.True (t.Visible); + 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] + public void Equals_True () + { + var c1 = new Cell (); + var c2 = new Cell (); + Assert.True (c1.Equals (c2)); + Assert.True (c2.Equals (c1)); + + c1.Rune = new ('a'); + c1.Attribute = new (); + c2.Rune = new ('a'); + c2.Attribute = new (); + Assert.True (c1.Equals (c2)); + Assert.True (c2.Equals (c1)); + } + + [Fact] + public void Cell_LoadCells_Without_Scheme_Is_Never_Null () + { + List cells = new () + { + new () { Rune = new ('T') }, + new () { Rune = new ('e') }, + new () { Rune = new ('s') }, + new () { Rune = new ('t') } + }; + TextView tv = CreateTextView (); + var top = new Toplevel (); + top.Add (tv); + tv.Load (cells); + + for (var i = 0; i < tv.Lines; i++) + { + List line = tv.GetLine (i); + + foreach (Cell c in line) + { + Assert.NotNull (c.Attribute); + } + } + } + + [Theory] + [InlineData ("", false, "")] + [InlineData ("", true, "")] + [InlineData (" ", false, "")] + [InlineData (" ", true, "")] + [InlineData (" ", false, "")] + [InlineData (" ", true, "")] + [InlineData ("a", false, "")] + [InlineData ("a", true, "")] + [InlineData ("a ", false, "")] + [InlineData ("a ", true, "")] + [InlineData (" a ", false, "a ", "")] + [InlineData (" a ", true, "a ", "")] + [InlineData (" H1 ", false, "H1 ", "")] + [InlineData (" H1 ", true, "H1 ", "")] + [InlineData ("a$", false, "$", "")] + [InlineData ("a$", true, "$", "")] + [InlineData ("a$#", false, "$#", "")] + [InlineData ("a$#", true, "$#", "#", "")] + [InlineData (" a$# ", false, "a$# ", "$# ", "")] + [InlineData (" a$# ", true, "a$# ", "$# ", "# ", "")] + [InlineData ("\"$schema\"", false, "schema\"", "\"", "")] + [InlineData ("\"$schema\"", true, "$schema\"", "schema\"", "\"", "")] + [InlineData ("\": \"", false, "\"", "")] + [InlineData ("\": \"", true, "\"", "")] + [InlineData ("\"$schema\": \"", false, "schema\": \"", "\": \"", "\"", "")] + [InlineData ("\"$schema\": \"", true, "$schema\": \"", "schema\": \"", "\": \"", "\"", "")] + [InlineData ("1ºªA", false, "")] + [InlineData ("1ºªA", true, "")] + [InlineData ( + "ºª\\!\"#%&/()?'«»*;,:._-@{[]}]|$=+´`~^<>£€¨", + false, + "\\!\"#%&/()?'«»*;,:._-@{[]}]|$=+´`~^<>£€¨", + "")] + [InlineData ( + "ºª\\!\"#%&/()?'«»*;,:._-@{[]}]|$=+´`~^<>£€¨", + true, + "\\!\"#%&/()?'«»*;,:._-@{[]}]|$=+´`~^<>£€¨", + "|$=+´`~^<>£€¨", + "")] + [InlineData ( + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + false, + "\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + " \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "\"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "\"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + ".github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + ".io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + ".GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "/schemas/tui-config-schema.json\"\r\n}", + "schemas/tui-config-schema.json\"\r\n}", + "/tui-config-schema.json\"\r\n}", + "tui-config-schema.json\"\r\n}", + "-config-schema.json\"\r\n}", + "config-schema.json\"\r\n}", + "-schema.json\"\r\n}", + "schema.json\"\r\n}", + ".json\"\r\n}", + "json\"\r\n}", + "\"\r\n}", + "\r\n}", + "}", + "")] + [InlineData ( + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + true, + "\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + " \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "\"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "\"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + ".github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + ".io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + ".GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + "/schemas/tui-config-schema.json\"\r\n}", + "schemas/tui-config-schema.json\"\r\n}", + "/tui-config-schema.json\"\r\n}", + "tui-config-schema.json\"\r\n}", + "-config-schema.json\"\r\n}", + "config-schema.json\"\r\n}", + "-schema.json\"\r\n}", + "schema.json\"\r\n}", + ".json\"\r\n}", + "json\"\r\n}", + "\"\r\n}", + "\r\n}", + "}", + "")] + public void WordForward_WordWrap_False_True (string text, bool useSameRuneType, params string [] expectedText) + { + TextView tv = CreateTextView (); + tv.UseSameRuneTypeForWords = useSameRuneType; + + ProcessDeleteWithCtrl (); + + tv.WordWrap = true; + ProcessDeleteWithCtrl (); + + void ProcessDeleteWithCtrl () + { + tv.Text = text; + var idx = 0; + + while (!string.IsNullOrEmpty (tv.Text)) + { + tv.NewKeyDownEvent (Key.Delete.WithCtrl); + Assert.Equal (expectedText [idx].Replace ("\r\n", Environment.NewLine), tv.Text); + idx++; + } + } + } + + [Theory] + [InlineData ("", false, "")] + [InlineData ("", true, "")] + [InlineData (" ", false, "")] + [InlineData (" ", true, "")] + [InlineData (" ", false, "")] + [InlineData (" ", true, "")] + [InlineData ("a", false, "")] + [InlineData ("a", true, "")] + [InlineData ("a ", false, "")] + [InlineData ("a ", true, "")] + [InlineData (" a ", false, " ", "")] + [InlineData (" a ", true, " ", "")] + [InlineData (" H1 ", false, " ", "")] + [InlineData (" H1 ", true, " ", "")] + [InlineData ("a$", false, "a", "")] + [InlineData ("a$", true, "a", "")] + [InlineData ("a$#", false, "a", "")] + [InlineData ("a$#", true, "a$", "a", "")] + [InlineData (" a$# ", false, " a", " ", "")] + [InlineData (" a$# ", true, " a$", " a", " ", "")] + [InlineData ("\"$schema\"", false, "\"$schema", "\"$", "")] + [InlineData ("\"$schema\"", true, "\"$schema", "\"$", "\"", "")] + [InlineData ("\"$schema\": \"", false, "\"$schema\": ", "\"$schema", "\"$", "")] + [InlineData ("\"$schema\": \"", true, "\"$schema\": ", "\"$schema", "\"$", "\"", "")] + [InlineData ("1ºªA", false, "")] + [InlineData ("1ºªA", true, "")] + [InlineData ( + "ºª\\!\"#%&/()?'«»*;,:._-@{[]}]|$=+´`~^<>£€¨", + false, + "ºª", + "")] + [InlineData ( + "ºª\\!\"#%&/()?'«»*;,:._-@{[]}]|$=+´`~^<>£€¨", + true, + "ºª\\!\"#%&/()?'«»*;,:._-@{[]}]", + "ºª", + "")] + [InlineData ( + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + false, + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal", + "{\r\n \"$schema\": \"https://gui-cs.github.io/", + "{\r\n \"$schema\": \"https://gui-cs.github.io", + "{\r\n \"$schema\": \"https://gui-cs.github.", + "{\r\n \"$schema\": \"https://gui-cs.github", + "{\r\n \"$schema\": \"https://gui-cs.", + "{\r\n \"$schema\": \"https://gui-cs", + "{\r\n \"$schema\": \"https://gui-", + "{\r\n \"$schema\": \"https://gui", + "{\r\n \"$schema\": \"https://", + "{\r\n \"$schema\": \"https", + "{\r\n \"$schema\": \"", + "{\r\n \"$schema\": ", + "{\r\n \"$schema", + "{\r\n \"$", + "{\r\n ", + "{\r\n", + "{", + "")] + [InlineData ( + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n}", + true, + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"\r\n", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json\"", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/schemas", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs/", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.GuiV2Docs", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal.", + "{\r\n \"$schema\": \"https://gui-cs.github.io/Terminal", + "{\r\n \"$schema\": \"https://gui-cs.github.io/", + "{\r\n \"$schema\": \"https://gui-cs.github.io", + "{\r\n \"$schema\": \"https://gui-cs.github.", + "{\r\n \"$schema\": \"https://gui-cs.github", + "{\r\n \"$schema\": \"https://gui-cs.", + "{\r\n \"$schema\": \"https://gui-cs", + "{\r\n \"$schema\": \"https://gui-", + "{\r\n \"$schema\": \"https://gui", + "{\r\n \"$schema\": \"https://", + "{\r\n \"$schema\": \"https", + "{\r\n \"$schema\": \"", + "{\r\n \"$schema\": ", + "{\r\n \"$schema", + "{\r\n \"$", + "{\r\n \"", + "{\r\n ", + "{\r\n", + "{", + "")] + public void WordBackward_WordWrap_False_True (string text, bool useSameRuneType, params string [] expectedText) + { + TextView tv = CreateTextView (); + tv.UseSameRuneTypeForWords = useSameRuneType; + + ProcessBackspaceWithCtrl (); + + tv.WordWrap = true; + ProcessBackspaceWithCtrl (); + + void ProcessBackspaceWithCtrl () + { + tv.Text = text; + tv.MoveEnd (); + var idx = 0; + + while (!string.IsNullOrEmpty (tv.Text)) + { + tv.NewKeyDownEvent (Key.Backspace.WithCtrl); + Assert.Equal (expectedText [idx].Replace ("\r\n", Environment.NewLine), tv.Text); + idx++; + } + } + } + + [Theory] + [InlineData ("", 0, false, "")] + [InlineData ("", 0, true, "")] + [InlineData ("a", 0, false, "a")] + [InlineData ("a", 0, true, "a")] + [InlineData ("a:", 0, false, "a")] + [InlineData ("a:", 0, true, "a")] + [InlineData ("a:", 1, false, ":")] + [InlineData ("a:", 1, true, ":")] + [InlineData ("a ", 0, false, "a ")] + [InlineData ("a ", 0, true, "a")] + [InlineData ("a ", 1, false, "a ")] + [InlineData ("a ", 1, true, "a")] + [InlineData ("a b", 0, false, "a ")] + [InlineData ("a b", 0, true, "a")] + [InlineData ("a b", 1, false, "a ")] + [InlineData ("a b", 1, true, "a")] + [InlineData ("a b ", 2, false, "b ")] + [InlineData ("a b ", 2, true, "b")] + [InlineData ("a b ", 3, false, "b ")] + [InlineData ("a b ", 3, true, "b")] + [InlineData (" a b ", 0, false, " ")] + [InlineData (" a b ", 0, true, " ")] + [InlineData (" a b ", 2, false, " ")] + [InlineData (" a b ", 2, true, " ")] + [InlineData (" a b ", 3, false, " ")] + [InlineData (" a b ", 3, true, " ")] + [InlineData (" H1$you ", 2, false, "H1")] + [InlineData (" H1$you ", 2, true, "H1")] + [InlineData (" H1$you ", 3, false, "$&#")] + [InlineData (" H1$you ", 3, true, "$&#")] + [InlineData (" H1$you ", 4, false, "$&#")] + [InlineData (" H1$you ", 4, true, "$&#")] + [InlineData (" H1$you ", 5, false, "$&#")] + [InlineData (" H1$you ", 5, true, "$&#")] + [InlineData (" H1$you ", 6, false, "2you ")] + [InlineData (" H1$you ", 6, true, "2you")] + public void ProcessDoubleClickSelection_False_True (string text, int col, bool selectWordOnly, string expectedText) + { + TextView tv = CreateTextView (); + tv.Text = text; + tv.SelectWordOnlyOnDoubleClick = selectWordOnly; + + Assert.True (tv.NewMouseEvent (new () { Position = new (col, 0), Flags = MouseFlags.Button1DoubleClicked })); + Assert.Equal (expectedText, tv.SelectedText); + } + + private TextView CreateTextView () { return new () { Width = 30, Height = 10 }; } +}