Skip to content

Commit

Permalink
Fix a few VI key handlers to close edit group properly (#3845)
Browse files Browse the repository at this point in the history
  • Loading branch information
daxian-dbw authored Oct 24, 2023
1 parent bfd88e4 commit fbdf7fa
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 9 deletions.
2 changes: 1 addition & 1 deletion PSReadLine/Completion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ private void CompleteImpl(bool menuSelect)
if (InViInsertMode()) // must close out the current edit group before engaging menu completion
{
ViCommandMode();
ViInsertWithAppend();
ViInsertWithAppendImpl();
}

// Do not show suggestion text during tab completion.
Expand Down
8 changes: 7 additions & 1 deletion PSReadLine/ReadLine.vi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,12 @@ public static void ViInsertAtEnd(ConsoleKeyInfo? key = null, object arg = null)
/// Append from the current line position.
/// </summary>
public static void ViInsertWithAppend(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton._groupUndoHelper.StartGroup(ViInsertWithAppend, arg);
ViInsertWithAppendImpl(key, arg);
}

private static void ViInsertWithAppendImpl(ConsoleKeyInfo? key = null, object arg = null)
{
ViInsertMode(key, arg);
ForwardChar(key, arg);
Expand Down Expand Up @@ -1304,7 +1310,7 @@ public static void ViAppendLine(ConsoleKeyInfo? key = null, object arg = null)
}
_singleton.SaveEditItem(EditItemInsertChar.Create('\n', insertPoint));
_singleton.Render();
ViInsertWithAppend();
ViInsertWithAppendImpl();
}

private void MoveToEndOfPhrase()
Expand Down
28 changes: 21 additions & 7 deletions PSReadLine/Replace.vi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ private static void ViReplaceWord(ConsoleKeyInfo? key, object arg)
&& !_singleton.IsDelimiter(_singleton._lastWordDelimiter, _singleton.Options.WordDelimiters)
&& _singleton._shouldAppend)
{
ViInsertWithAppend(key, arg);
ViInsertWithAppendImpl(key, arg);
}
else
{
Expand All @@ -180,7 +180,7 @@ private static void ViReplaceGlob(ConsoleKeyInfo? key, object arg)
}
if (_singleton._current == _singleton._buffer.Length - 1)
{
ViInsertWithAppend(key, arg);
ViInsertWithAppendImpl(key, arg);
}
else
{
Expand All @@ -194,7 +194,7 @@ private static void ViReplaceEndOfWord(ConsoleKeyInfo? key, object arg)
DeleteEndOfWord(key, arg);
if (_singleton._current == _singleton._buffer.Length - 1)
{
ViInsertWithAppend(key, arg);
ViInsertWithAppendImpl(key, arg);
}
else
{
Expand All @@ -208,7 +208,7 @@ private static void ViReplaceEndOfGlob(ConsoleKeyInfo? key, object arg)
ViDeleteEndOfGlob(key, arg);
if (_singleton._current == _singleton._buffer.Length - 1)
{
ViInsertWithAppend(key, arg);
ViInsertWithAppendImpl(key, arg);
}
else
{
Expand Down Expand Up @@ -270,13 +270,17 @@ private static void ViReplaceToChar(char keyChar, ConsoleKeyInfo? key = null, ob
{
if (_singleton._current < initialCurrent || _singleton._current >= _singleton._buffer.Length)
{
ViInsertWithAppend(key, arg);
ViInsertWithAppendImpl(key, arg);
}
else
{
ViInsertMode(key, arg);
}
}
else
{
_singleton._groupUndoHelper.EndGroup();
}
}

/// <summary>
Expand All @@ -295,6 +299,10 @@ private static void ViReplaceToCharBack(char keyChar, ConsoleKeyInfo? key = null
{
ViInsertMode(key, arg);
}
else
{
_singleton._groupUndoHelper.EndGroup();
}
}

/// <summary>
Expand All @@ -314,6 +322,10 @@ private static void ViReplaceToBeforeChar(char keyChar, ConsoleKeyInfo? key = nu
{
ViInsertMode(key, arg);
}
else
{
_singleton._groupUndoHelper.EndGroup();
}
}

/// <summary>
Expand All @@ -332,8 +344,10 @@ private static void ViReplaceToBeforeCharBack(char keyChar, ConsoleKeyInfo? key
{
ViInsertMode(key, arg);
}
else
{
_singleton._groupUndoHelper.EndGroup();
}
}


}
}
83 changes: 83 additions & 0 deletions test/BasicEditingTest.VI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1121,5 +1121,88 @@ public void ViInsertModeMoveCursor()
_.RightArrow, // 'RightArrow' again does nothing, but doesn't crash
"c"));
}

[SkippableFact]
public void ViDefect1281_1()
{
TestSetup(KeyMode.Vi);

Test("bcd", Keys(
"abcdabcd", _.Escape,

// return to the [B]eginning of the word,
// then [c]hange text un[t]il just before the [2]nd [b] character
// this leaves the cursor at the current position (0) but erases
// the "abcda" text portion, / switches to edit mode and
// positions the cursor just before the "bcd" text portion.

"Bc2tb",

// going back to normal mode again without having modified the buffer further
// even though the [c] command started an edit group, going back to normal
// mode closes the pending edit group.

_.Escape, CheckThat(() => AssertCursorLeftIs(0)),

// attempt to [c]hange text un[t]il just before the [2]nd [b] character again
// because the [b] character only appears once further down in the buffer
// relative to where the cursor position is – currently set to 0 - the command
// fails. Therefore, we are still in normal mode.
//
// as the command failed, the current edit group is now correctly closed.

"c2tb", CheckThat(() => AssertLineIs("bcd")),

// attempt to [c]hange text un[t]il just before the [2]nd [b] character a third time.
// this exercises a code path where starting a edit group while another
// pending edit group was previously started crashed PSRL.
//
// this should no longer crash as any started pending group is now properly closed if
// the command fails
"c2tb"
));
}

[SkippableFact]
public void ViDefect1281_2()
{
TestSetup(KeyMode.Vi);

Test("abc", Keys(
"abc", _.Escape,

// 'cff' triggers `ViReplaceToChar` to delete until the character 'f'. But 'abc' doesn't
// have the letter 'f', so the started edit group should be ended and cursor is not moved.
"cff",
CheckThat(() => AssertCursorLeftIs(2)),

// the subsequent 'cc' calls `ViReplaceLine` to replace the current line with 'i', which
// starts a new edit group.
"ccip",
CheckThat(() => AssertLineIs("ip")),

// now we undo the 'cci' step, and accept the current command line, which should be 'abc'.
_.Escape, "u"
));
}

[SkippableFact]
public void ViDefect1281_3()
{
TestSetup(KeyMode.Vi);

Test("bcd", Keys(
"bcd", _.Escape, _.LeftArrow, _.LeftArrow,

// 'a' triggers `ViInsertWithAppend` and we append 'iii' after 'b'.
"aiii",
CheckThat(() => AssertCursorLeftIs(4)),
CheckThat(() => AssertLineIs("biiicd")),

// now we undo the 'aiii' step, and accept the current command line,
// which should be 'bcd'.
_.Escape, "u"
));
}
}
}

0 comments on commit fbdf7fa

Please sign in to comment.