Skip to content

Commit a45ab81

Browse files
authored
vi-mode: Add dgg to delete from the beginning of the buffer to the current logical line (#1752)
1 parent 7024968 commit a45ab81

File tree

5 files changed

+139
-37
lines changed

5 files changed

+139
-37
lines changed

PSReadLine/KeyBindings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ public static KeyHandlerGroup GetDisplayGrouping(string function)
400400
case nameof(DeleteCharOrExit):
401401
case nameof(DeleteEndOfBuffer):
402402
case nameof(DeleteEndOfWord):
403+
case nameof(DeleteRelativeLines):
403404
case nameof(DeleteLine):
404405
case nameof(DeleteLineToFirstChar):
405406
case nameof(DeleteNextLines):

PSReadLine/KeyBindings.vi.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ internal static ConsoleColor AlternateBackground(ConsoleColor bg)
4343
private static Dictionary<PSKeyInfo, KeyHandler> _viChordGTable;
4444
private static Dictionary<PSKeyInfo, KeyHandler> _viChordCTable;
4545
private static Dictionary<PSKeyInfo, KeyHandler> _viChordYTable;
46+
private static Dictionary<PSKeyInfo, KeyHandler> _viChordDGTable;
4647

4748
private static Dictionary<PSKeyInfo, Dictionary<PSKeyInfo, KeyHandler>> _viCmdChordTable;
4849
private static Dictionary<PSKeyInfo, Dictionary<PSKeyInfo, KeyHandler>> _viInsChordTable;
@@ -226,6 +227,7 @@ private void SetDefaultViBindings()
226227
{ Keys.W, MakeKeyHandler( DeleteWord, "DeleteWord") },
227228
{ Keys.ucW, MakeKeyHandler( ViDeleteGlob, "ViDeleteGlob") },
228229
{ Keys.E, MakeKeyHandler( DeleteEndOfWord, "DeleteEndOfWord") },
230+
{ Keys.G, MakeKeyHandler( ViDGChord, "ViDGChord") },
229231
{ Keys.ucG, MakeKeyHandler( DeleteEndOfBuffer, "DeleteEndOfBuffer") },
230232
{ Keys.ucE, MakeKeyHandler( ViDeleteEndOfGlob, "ViDeleteEndOfGlob") },
231233
{ Keys.H, MakeKeyHandler( BackwardDeleteChar, "BackwardDeleteChar") },
@@ -287,6 +289,11 @@ private void SetDefaultViBindings()
287289
{ Keys.Percent, MakeKeyHandler( ViYankPercent, "ViYankPercent") },
288290
};
289291

292+
_viChordDGTable = new Dictionary<PSKeyInfo, KeyHandler>
293+
{
294+
{ Keys.G, MakeKeyHandler( DeleteRelativeLines, "DeleteRelativeLines") },
295+
};
296+
290297
_viCmdChordTable = new Dictionary<PSKeyInfo, Dictionary<PSKeyInfo, KeyHandler>>();
291298
_viInsChordTable = new Dictionary<PSKeyInfo, Dictionary<PSKeyInfo, KeyHandler>>();
292299

PSReadLine/PSReadLineResources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,4 +811,7 @@ Or not saving history with:
811811
<data name="DeleteNextLinesDescription" xml:space="preserve">
812812
<value>Deletes the current and next n logical lines in a multiline buffer</value>
813813
</data>
814+
<data name="DeleteRelativeLinesDescription" xml:space="preserve">
815+
<value>Delete from the current logical line to the n-th requested logical line in a multiline buffer</value>
816+
</data>
814817
</root>

PSReadLine/ReadLine.vi.cs

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ public static void DeleteEndOfWord(ConsoleKeyInfo? key = null, object arg = null
368368
_singleton._buffer.Remove(_singleton._current, 1 + endPoint - _singleton._current);
369369
if (_singleton._current >= _singleton._buffer.Length)
370370
{
371-
_singleton._current = Math.Max(0,_singleton._buffer.Length - 1);
371+
_singleton._current = Math.Max(0, _singleton._buffer.Length - 1);
372372
}
373373
_singleton.Render();
374374
}
@@ -522,11 +522,11 @@ internal static IDisposable UseViCommandModeTables()
522522
_singleton._dispatchTable = _viCmdKeyMap;
523523
_singleton._chordDispatchTable = _viCmdChordTable;
524524

525-
return new Disposable( () =>
526-
{
527-
_singleton._dispatchTable = oldDispatchTable;
528-
_singleton._chordDispatchTable = oldChordDispatchTable;
529-
} );
525+
return new Disposable(() =>
526+
{
527+
_singleton._dispatchTable = oldDispatchTable;
528+
_singleton._chordDispatchTable = oldChordDispatchTable;
529+
});
530530
}
531531

532532
/// <summary>
@@ -540,11 +540,11 @@ internal static IDisposable UseViInsertModeTables()
540540
_singleton._dispatchTable = _viInsKeyMap;
541541
_singleton._chordDispatchTable = _viInsChordTable;
542542

543-
return new Disposable( () =>
544-
{
545-
_singleton._dispatchTable = oldDispatchTable;
546-
_singleton._chordDispatchTable = oldChordDispatchTable;
547-
} );
543+
return new Disposable(() =>
544+
{
545+
_singleton._dispatchTable = oldDispatchTable;
546+
_singleton._chordDispatchTable = oldChordDispatchTable;
547+
});
548548
}
549549

550550
private void ViIndicateCommandMode()
@@ -849,6 +849,38 @@ public static void DeletePreviousLines(ConsoleKeyInfo? key = null, object arg =
849849
}
850850
}
851851

852+
/// <summary>
853+
/// Delete from the current logical line to the n-th requested logical line in a multiline buffer
854+
/// </summary>
855+
private static void DeleteRelativeLines(ConsoleKeyInfo? key = null, object arg = null)
856+
{
857+
if (TryGetArgAsInt(arg, out var requestedLineNumber, 1))
858+
{
859+
var currentLineIndex = _singleton.GetLogicalLineNumber() - 1;
860+
var requestedLineIndex = requestedLineNumber - 1;
861+
if (requestedLineIndex < 0)
862+
{
863+
requestedLineIndex = 0;
864+
}
865+
866+
var logicalLineCount = _singleton.GetLogicalLineCount();
867+
if (requestedLineIndex >= logicalLineCount)
868+
{
869+
requestedLineIndex = logicalLineCount - 1;
870+
}
871+
872+
var requestedLineCount = requestedLineIndex - currentLineIndex;
873+
if (requestedLineCount < 0)
874+
{
875+
DeletePreviousLines(null, -requestedLineCount);
876+
}
877+
else
878+
{
879+
DeleteNextLines(null, requestedLineCount);
880+
}
881+
}
882+
}
883+
852884
/// <summary>
853885
/// Deletes the previous word.
854886
/// </summary>
@@ -1106,39 +1138,54 @@ private static void ViChord(ConsoleKeyInfo? key = null, object arg = null)
11061138

11071139
if (_singleton._chordDispatchTable.TryGetValue(PSKeyInfo.FromConsoleKeyInfo(key.Value), out var secondKeyDispatchTable))
11081140
{
1109-
var secondKey = ReadKey();
1110-
if (secondKeyDispatchTable.TryGetValue(secondKey, out var handler))
1141+
ViChordHandler(secondKeyDispatchTable, arg);
1142+
}
1143+
}
1144+
1145+
private static void ViChordHandler(Dictionary<PSKeyInfo, KeyHandler> secondKeyDispatchTable, object arg = null)
1146+
{
1147+
var secondKey = ReadKey();
1148+
if (secondKeyDispatchTable.TryGetValue(secondKey, out var handler))
1149+
{
1150+
_singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: arg);
1151+
}
1152+
else if (!IsNumeric(secondKey))
1153+
{
1154+
_singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: arg);
1155+
}
1156+
else
1157+
{
1158+
var argBuffer = _singleton._statusBuffer;
1159+
argBuffer.Clear();
1160+
_singleton._statusLinePrompt = "digit-argument: ";
1161+
while (IsNumeric(secondKey))
11111162
{
1112-
_singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: arg);
1163+
argBuffer.Append(secondKey.KeyChar);
1164+
_singleton.Render();
1165+
secondKey = ReadKey();
11131166
}
1114-
else if (!IsNumeric(secondKey))
1167+
int numericArg = int.Parse(argBuffer.ToString());
1168+
if (secondKeyDispatchTable.TryGetValue(secondKey, out handler))
11151169
{
1116-
_singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: arg);
1170+
_singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: numericArg);
11171171
}
11181172
else
11191173
{
1120-
var argBuffer = _singleton._statusBuffer;
1121-
argBuffer.Clear();
1122-
_singleton._statusLinePrompt = "digit-argument: ";
1123-
while (IsNumeric(secondKey))
1124-
{
1125-
argBuffer.Append(secondKey.KeyChar);
1126-
_singleton.Render();
1127-
secondKey = ReadKey();
1128-
}
1129-
int numericArg = int.Parse(argBuffer.ToString());
1130-
if (secondKeyDispatchTable.TryGetValue(secondKey, out handler))
1131-
{
1132-
_singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: numericArg);
1133-
}
1134-
else
1135-
{
1136-
Ding();
1137-
}
1138-
argBuffer.Clear();
1139-
_singleton.ClearStatusMessage(render: true);
1174+
Ding();
11401175
}
1176+
argBuffer.Clear();
1177+
_singleton.ClearStatusMessage(render: true);
1178+
}
1179+
}
1180+
1181+
private static void ViDGChord(ConsoleKeyInfo? key = null, object arg = null)
1182+
{
1183+
if (!key.HasValue)
1184+
{
1185+
throw new ArgumentNullException(nameof(key));
11411186
}
1187+
1188+
ViChordHandler(_viChordDGTable, arg);
11421189
}
11431190

11441191
private static bool IsNumeric(PSKeyInfo key)
@@ -1247,7 +1294,7 @@ public static void ViInsertLine(ConsoleKeyInfo? key = null, object arg = null)
12471294
_singleton.MoveToBeginningOfPhrase();
12481295
_singleton._buffer.Insert(_singleton._current, '\n');
12491296
//_singleton._current = Math.Max(0, _singleton._current - 1);
1250-
_singleton.SaveEditItem(EditItemInsertChar.Create( '\n', _singleton._current));
1297+
_singleton.SaveEditItem(EditItemInsertChar.Create('\n', _singleton._current));
12511298
_singleton.Render();
12521299
ViInsertMode();
12531300
}

test/BasicEditingTest.VI.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,50 @@ public void ViDeleteNextLines()
567567
));
568568
}
569569

570+
[SkippableFact]
571+
public void ViDeleteRelativeLines()
572+
{
573+
TestSetup(KeyMode.Vi);
574+
575+
var continuationPrefixLength = PSConsoleReadLineOptions.DefaultContinuationPrompt.Length;
576+
577+
Test("\"\nthree\n\"", Keys(
578+
_.DQuote, _.Enter,
579+
"one", _.Enter,
580+
"two", _.Enter,
581+
"three", _.Enter,
582+
_.DQuote, _.Escape,
583+
"kkl", // go to the 'wo' portion of "two"
584+
// delete from line 2 to the current line (3)
585+
"2dgg",
586+
CheckThat(() => AssertCursorLeftIs(continuationPrefixLength + 0))
587+
));
588+
589+
Test("\"\none\nthree\n\"", Keys(
590+
_.DQuote, _.Enter,
591+
"one", _.Enter,
592+
"two", _.Enter,
593+
"three", _.Enter,
594+
_.DQuote, _.Escape,
595+
"kkl", // go to the 'wo' portion of "two"
596+
// delete the current line (3)
597+
"3dgg",
598+
CheckThat(() => AssertCursorLeftIs(continuationPrefixLength + 0))
599+
));
600+
601+
Test("\"\none\n\"", Keys(
602+
_.DQuote, _.Enter,
603+
"one", _.Enter,
604+
"two", _.Enter,
605+
"three", _.Enter,
606+
_.DQuote, _.Escape,
607+
"kkl", // go to the 'wo' portion of "two"
608+
// delete from the current line (3) to line 4
609+
"4dgg",
610+
CheckThat(() => AssertCursorLeftIs(continuationPrefixLength + 0))
611+
));
612+
}
613+
570614
[SkippableFact]
571615
public void ViGlobDelete()
572616
{

0 commit comments

Comments
 (0)