Skip to content

Commit ba5294f

Browse files
authored
Make edit group more stable in VI mode (#1526)
1 parent 88a21e4 commit ba5294f

File tree

3 files changed

+84
-9
lines changed

3 files changed

+84
-9
lines changed

PSReadLine/History.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public class HistoryItem
8585
internal bool _sensitive;
8686
internal List<EditItem> _edits;
8787
internal int _undoEditIndex;
88+
internal int _editGroupStart;
8889
}
8990

9091
// History state
@@ -119,6 +120,7 @@ private void ClearSavedCurrentLine()
119120
_savedCurrentLine.CommandLine = null;
120121
_savedCurrentLine._edits = null;
121122
_savedCurrentLine._undoEditIndex = 0;
123+
_savedCurrentLine._editGroupStart = -1;
122124
}
123125

124126
private AddToHistoryOption GetAddToHistoryOption(string line)
@@ -194,6 +196,7 @@ private string MaybeAddToHistory(
194196
CommandLine = result,
195197
_edits = edits,
196198
_undoEditIndex = undoEditIndex,
199+
_editGroupStart = -1,
197200
_saved = fromHistoryFile,
198201
FromOtherSession = fromDifferentSession,
199202
FromHistoryFile = fromInitialRead,
@@ -477,12 +480,14 @@ private void UpdateFromHistory(HistoryMoveCursor moveCursor)
477480
line = _savedCurrentLine.CommandLine;
478481
_edits = new List<EditItem>(_savedCurrentLine._edits);
479482
_undoEditIndex = _savedCurrentLine._undoEditIndex;
483+
_editGroupStart = _savedCurrentLine._editGroupStart;
480484
}
481485
else
482486
{
483487
line = _history[_currentHistoryIndex].CommandLine;
484488
_edits = new List<EditItem>(_history[_currentHistoryIndex]._edits);
485489
_undoEditIndex = _history[_currentHistoryIndex]._undoEditIndex;
490+
_editGroupStart = _history[_currentHistoryIndex]._editGroupStart;
486491
}
487492
_buffer.Clear();
488493
_buffer.Append(line);
@@ -519,6 +524,7 @@ private void SaveCurrentLine()
519524
_savedCurrentLine.CommandLine = _buffer.ToString();
520525
_savedCurrentLine._edits = _edits;
521526
_savedCurrentLine._undoEditIndex = _undoEditIndex;
527+
_savedCurrentLine._editGroupStart = _editGroupStart;
522528
}
523529
}
524530

PSReadLine/UndoRedo.cs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ private void RemoveEditsAfterUndo()
1818
if (removeCount > 0)
1919
{
2020
_edits.RemoveRange(_undoEditIndex, removeCount);
21-
if (_editGroupStart >= 0)
21+
if (_edits.Count < _editGroupStart)
2222
{
23-
// Adjust the edit group start if we are started a group.
24-
_editGroupStart -= removeCount;
23+
// Reset the group start index if any edits before setting the start mark were undone.
24+
_editGroupStart = -1;
2525
}
2626
}
2727
}
@@ -54,10 +54,27 @@ private void StartEditGroup()
5454

5555
private void EndEditGroup(Action<ConsoleKeyInfo?, object> instigator = null, object instigatorArg = null)
5656
{
57+
// Remove the undone edits when closing an edit group, so the generated group
58+
// doesn't contain those edits that were already undone.
59+
RemoveEditsAfterUndo();
60+
61+
// If any edits before the start mark were done, the start mark will be reset
62+
// and no need to generate the edit group.
63+
if (_editGroupStart < 0)
64+
{
65+
return;
66+
}
67+
5768
var groupEditCount = _edits.Count - _editGroupStart;
58-
var groupedEditItems = _edits.GetRange(_editGroupStart, groupEditCount);
59-
_edits.RemoveRange(_editGroupStart, groupEditCount);
60-
SaveEditItem(GroupedEdit.Create(groupedEditItems, instigator, instigatorArg));
69+
70+
// It's possible that just enough edits were undone and now 'groupEditCount' is 0.
71+
// We don't generate the edit group in that case.
72+
if (groupEditCount > 0)
73+
{
74+
var groupedEditItems = _edits.GetRange(_editGroupStart, groupEditCount);
75+
_edits.RemoveRange(_editGroupStart, groupEditCount);
76+
SaveEditItem(GroupedEdit.Create(groupedEditItems, instigator, instigatorArg));
77+
}
6178
_editGroupStart = -1;
6279
}
6380

test/UndoRedoTest.cs

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,60 @@
1-
namespace Test
1+
using Xunit;
2+
3+
namespace Test
24
{
3-
// Disgusting language hack to make it easier to read a sequence of keys.
4-
55
public partial class ReadLine
66
{
7+
[SkippableFact]
8+
public void UndoneEditsShouldBeRemovedBeforeEndingEditGroup()
9+
{
10+
TestSetup(KeyMode.Vi);
11+
12+
Test("yuiogh", Keys(
13+
"yuiogh", _.Escape, CheckThat(() => AssertLineIs("yuiogh")),
14+
_.C, CheckThat(() => AssertLineIs("yuiog")),
15+
"897", CheckThat(() => AssertLineIs("yuiog897")),
16+
_.Ctrl_z, CheckThat(() => AssertLineIs("yuiog89")),
17+
_.Escape, _.u, CheckThat(() => AssertLineIs("yuiogh"))
18+
));
19+
}
20+
21+
[SkippableFact]
22+
public void ProperlyUpdateEditGroupStartMarkWhenRemovingUndoneEdits()
23+
{
24+
TestSetup(KeyMode.Vi);
25+
26+
Test("yuiogh", Keys(
27+
"yuiogh", _.Escape, CheckThat(() => AssertLineIs("yuiogh")),
28+
_.LeftArrow, _.C, CheckThat(() => AssertLineIs("yuio")),
29+
"789", CheckThat(() => AssertLineIs("yuio789")),
30+
_.Ctrl_z, CheckThat(() => AssertLineIs("yuio78")),
31+
'1', _.Escape, _.u, CheckThat(() => AssertLineIs("yuiogh"))
32+
));
33+
}
34+
35+
[SkippableFact]
36+
public void ProperlySetEditGroupStartMarkWhenLoopInHistory()
37+
{
38+
TestSetup(KeyMode.Vi);
39+
40+
Test("ok", Keys("ok"));
41+
42+
// The _editGroupStart mark for an history entry should always be -1, meaning no start mark.
43+
Test("ok", Keys(
44+
"yuiogh", _.Escape, CheckThat(() => AssertLineIs("yuiogh")),
45+
_.C, CheckThat(() => AssertLineIs("yuiog")),
46+
_.UpArrow, CheckThat(() => AssertLineIs("ok")),
47+
_.Escape));
48+
49+
// The _editGroupStart mark should be restored when loop back to the current command line.
50+
Test("yuiogh", Keys(
51+
"yuiogh", _.Escape, CheckThat(() => AssertLineIs("yuiogh")),
52+
_.C, CheckThat(() => AssertLineIs("yuiog")),
53+
_.UpArrow, CheckThat(() => AssertLineIs("ok")),
54+
_.DownArrow, CheckThat(() => AssertLineIs("yuiog")),
55+
"123", CheckThat(() => AssertLineIs("yuiog123")),
56+
_.Escape, _.u, CheckThat(() => AssertLineIs("yuiogh"))
57+
));
58+
}
759
}
860
}

0 commit comments

Comments
 (0)