mirror of
https://github.com/PowerShell/PSReadLine
synced 2026-06-08 12:12:13 +00:00
Implement yank-last-arg/yank-nth-arg
Support for yank-last-arg and yank-nth-arg has been added. Combined with digit-argument, these functions provide a nice way to copy arguments from previous commands fairly easily. For example, to copy the 2nd argument from a command 2 entries back, you can use: Alt+2 Alt+. Alt+. I also tweaked digit-argument slightly so that when you start with a negative argument (Alt--) the first digit can override the -1. In Bash, to enter something like -2, you have to think backwards and type Alt-2 Alt-- because Alt-- Alt-2 ends up giving you -12.
This commit is contained in:
+10
-8
@@ -443,14 +443,16 @@ namespace PSConsoleUtilities
|
||||
|
||||
// ValidateSet attribute is generated by the script GenerateBuiltinList
|
||||
[ValidateSet("Abort", "AcceptLine", "AddLine", "BackwardChar", "BackwardDeleteChar",
|
||||
"BackwardDeleteLine", "BackwardKillLine", "BeginningOfHistory", "BeginningOfLine", "CancelLine",
|
||||
"ClearScreen", "Complete", "DeleteChar", "DisableDemoMode", "EnableDemoMode",
|
||||
"EndOfHistory", "EndOfLine", "ExchangePointAndMark", "ForwardChar", "ForwardDeleteLine",
|
||||
"ForwardSearchHistory", "GotoBrace", "HistorySearchBackward", "HistorySearchForward", "ShellBackwardKillWord",
|
||||
"KillLine", "ShellKillWord", "NextHistory", "Paste", "PossibleCompletions",
|
||||
"PreviousHistory", "Redo", "ReverseSearchHistory", "RevertLine", "SetKeyHandler",
|
||||
"SetMark", "ShellBackwardWord", "ShellForwardWord", "TabCompleteNext", "TabCompletePrevious",
|
||||
"Undo", "Yank", "YankPop")]
|
||||
"BackwardDeleteLine", "BackwardKillLine", "BackwardKillWord", "BackwardWord", "BeginningOfHistory",
|
||||
"BeginningOfLine", "CancelLine", "ClearScreen", "Complete", "DeleteChar",
|
||||
"DigitArgument", "DisableDemoMode", "EnableDemoMode", "EndOfHistory", "EndOfLine",
|
||||
"ExchangePointAndMark", "ForwardChar", "ForwardDeleteLine", "ForwardSearchHistory", "ForwardWord",
|
||||
"GotoBrace", "HistorySearchBackward", "HistorySearchForward", "KillLine", "KillWord",
|
||||
"NextHistory", "NextWord", "Paste", "PossibleCompletions", "PreviousHistory",
|
||||
"Redo", "ReverseSearchHistory", "RevertLine", "SelfInsert", "SetKeyHandler",
|
||||
"SetMark", "ShellBackwardKillWord", "ShellBackwardWord", "ShellForwardWord", "ShellKillWord",
|
||||
"TabCompleteNext", "TabCompletePrevious", "Undo", "UnixWordRubout", "Yank",
|
||||
"YankLastArg", "YankNthArg", "YankPop")]
|
||||
[Parameter(Position = 1, Mandatory = true, ParameterSetName = "Function")]
|
||||
public string Function { get; set; }
|
||||
|
||||
|
||||
@@ -109,6 +109,7 @@ namespace PSConsoleUtilities
|
||||
public static ConsoleKeyInfo Equals = new ConsoleKeyInfo('=', ConsoleKey.OemPlus, false, false, false);
|
||||
|
||||
public static ConsoleKeyInfo CtrlAt = new ConsoleKeyInfo((char)0, ConsoleKey.D2, true, false, true);
|
||||
public static ConsoleKeyInfo AltUnderbar = new ConsoleKeyInfo('_', ConsoleKey.OemMinus, true, true, false);
|
||||
public static ConsoleKeyInfo CtrlUnderbar = new ConsoleKeyInfo((char)31, ConsoleKey.OemMinus, true, false, true);
|
||||
public static ConsoleKeyInfo AltEquals = new ConsoleKeyInfo('=', ConsoleKey.OemPlus, false, true, false);
|
||||
public static ConsoleKeyInfo Space = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false);
|
||||
@@ -118,6 +119,7 @@ namespace PSConsoleUtilities
|
||||
public static ConsoleKeyInfo AltLess = new ConsoleKeyInfo('<', ConsoleKey.OemComma, true, true, false);
|
||||
public static ConsoleKeyInfo AltGreater = new ConsoleKeyInfo('>', ConsoleKey.OemPeriod, true, true, false);
|
||||
public static ConsoleKeyInfo CtrlRBracket = new ConsoleKeyInfo((char)29, ConsoleKey.Oem6, false, false, true);
|
||||
public static ConsoleKeyInfo AltPeriod = new ConsoleKeyInfo('.', ConsoleKey.OemPeriod, false, true, false);
|
||||
|
||||
public static ConsoleKeyInfo Alt0 = new ConsoleKeyInfo('0', ConsoleKey.D0, false, true, false);
|
||||
public static ConsoleKeyInfo Alt1 = new ConsoleKeyInfo('1', ConsoleKey.D1, false, true, false);
|
||||
@@ -184,6 +186,8 @@ namespace PSConsoleUtilities
|
||||
public static ConsoleKeyInfo CtrlY = new ConsoleKeyInfo((char)25, ConsoleKey.Y, false, false, true);
|
||||
public static ConsoleKeyInfo CtrlZ = new ConsoleKeyInfo((char)26, ConsoleKey.Z, false, false, true);
|
||||
|
||||
public static ConsoleKeyInfo AltCtrlY = new ConsoleKeyInfo((char)0, ConsoleKey.Y, false, true, true);
|
||||
|
||||
public static ConsoleKeyInfo Backspace = new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false);
|
||||
public static ConsoleKeyInfo CtrlBackspace = new ConsoleKeyInfo((char)0x7f, ConsoleKey.Backspace, false, false, true);
|
||||
public static ConsoleKeyInfo AltBackspace = new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, true, false);
|
||||
|
||||
+18
@@ -537,6 +537,24 @@ namespace PSConsoleUtilities {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copy the text of the last argument to the input.
|
||||
/// </summary>
|
||||
internal static string YankLastArgDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("YankLastArgDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copy the text of the first argument to the input.
|
||||
/// </summary>
|
||||
internal static string YankNthArgDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("YankNthArgDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Replace the previously yanked text with the text from the next kill ring position.
|
||||
/// </summary>
|
||||
|
||||
@@ -279,4 +279,10 @@
|
||||
<data name="UnixWordRuboutDescription" xml:space="preserve">
|
||||
<value>Move the text from the cursor to the start of the current or previous whitespace delimited word to the kill ring</value>
|
||||
</data>
|
||||
<data name="YankLastArgDescription" xml:space="preserve">
|
||||
<value>Copy the text of the last argument to the input</value>
|
||||
</data>
|
||||
<data name="YankNthArgDescription" xml:space="preserve">
|
||||
<value>Copy the text of the first argument to the input</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -169,6 +169,15 @@ namespace PSConsoleUtilities
|
||||
private int _killCommandCount;
|
||||
private int _yankCommandCount;
|
||||
private int _yankStartPoint;
|
||||
private int _yankLastArgCommandCount;
|
||||
class YankLastArgState
|
||||
{
|
||||
internal int argument;
|
||||
internal int historyIndex;
|
||||
internal int historyIncrement;
|
||||
internal int startPoint = -1;
|
||||
}
|
||||
private YankLastArgState _yankLastArgState;
|
||||
|
||||
// Tab completion state
|
||||
private int _tabCommandCount;
|
||||
@@ -313,6 +322,7 @@ namespace PSConsoleUtilities
|
||||
var yankCommandCount = _yankCommandCount;
|
||||
var tabCommandCount = _tabCommandCount;
|
||||
var searchHistoryCommandCount = _searchHistoryCommandCount;
|
||||
var yankLastArgCommandCount = _yankLastArgCommandCount;
|
||||
|
||||
var key = ReadKey();
|
||||
ProcessOneKey(key, _dispatchTable, ignoreIfNoAction: false, arg: null);
|
||||
@@ -331,6 +341,12 @@ namespace PSConsoleUtilities
|
||||
// Reset yank command count if it didn't change
|
||||
_yankCommandCount = 0;
|
||||
}
|
||||
if (yankLastArgCommandCount == _yankLastArgCommandCount)
|
||||
{
|
||||
// Reset yank last arg command count if it didn't change
|
||||
_yankLastArgCommandCount = 0;
|
||||
_yankLastArgState = null;
|
||||
}
|
||||
if (tabCommandCount == _tabCommandCount)
|
||||
{
|
||||
// Reset tab command count if it didn't change
|
||||
@@ -514,6 +530,9 @@ namespace PSConsoleUtilities
|
||||
{ Keys.AltBackspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") },
|
||||
{ Keys.AltEquals, MakeKeyHandler(PossibleCompletions, "PossibleCompletions") },
|
||||
{ Keys.AltSpace, MakeKeyHandler(SetMark, "SetMark") }, // useless entry here for completeness - brings up system menu on Windows
|
||||
{ Keys.AltPeriod, MakeKeyHandler(YankLastArg, "YankLastArg") },
|
||||
{ Keys.AltUnderbar, MakeKeyHandler(YankLastArg, "YankLastArg") },
|
||||
{ Keys.AltCtrlY, MakeKeyHandler(YankNthArg, "YankNthArg") },
|
||||
{ Keys.VolumeDown, MakeKeyHandler(Ignore, "Ignore") },
|
||||
{ Keys.VolumeUp, MakeKeyHandler(Ignore, "Ignore") },
|
||||
{ Keys.VolumeMute, MakeKeyHandler(Ignore, "Ignore") },
|
||||
@@ -526,7 +545,10 @@ namespace PSConsoleUtilities
|
||||
{ Keys.F, MakeKeyHandler(ForwardWord, "ForwardWord") },
|
||||
{ Keys.R, MakeKeyHandler(RevertLine, "RevertLine") },
|
||||
{ Keys.Y, MakeKeyHandler(YankPop, "YankPop") },
|
||||
{ Keys.CtrlY, MakeKeyHandler(YankNthArg, "YankNthArg") },
|
||||
{ Keys.Backspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") },
|
||||
{ Keys.Period, MakeKeyHandler(YankLastArg, "YankLastArg") },
|
||||
{ Keys.Underbar, MakeKeyHandler(YankLastArg, "YankLastArg") },
|
||||
};
|
||||
|
||||
_emacsCtrlXMap = new Dictionary<ConsoleKeyInfo, KeyHandler>(new ConsoleKeyInfoComparer())
|
||||
@@ -1657,12 +1679,14 @@ namespace PSConsoleUtilities
|
||||
return;
|
||||
}
|
||||
|
||||
bool firstKeyAfterNegative = false;
|
||||
_singleton._statusLinePrompt = "digit-argument: ";
|
||||
var argBuffer = _singleton._statusBuffer;
|
||||
argBuffer.Append(key.Value.KeyChar);
|
||||
if (key.Value.KeyChar == '-')
|
||||
{
|
||||
argBuffer.Append('1');
|
||||
firstKeyAfterNegative = true;
|
||||
}
|
||||
|
||||
_singleton.Render(); // Render prompt
|
||||
@@ -1682,11 +1706,17 @@ namespace PSConsoleUtilities
|
||||
{
|
||||
argBuffer.Insert(0, '-');
|
||||
}
|
||||
_singleton.Render(); // Render prompt
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nextKey.KeyChar >= '0' && nextKey.KeyChar <= '9')
|
||||
{
|
||||
if (firstKeyAfterNegative)
|
||||
{
|
||||
argBuffer.Remove(1, 1);
|
||||
firstKeyAfterNegative = false;
|
||||
}
|
||||
argBuffer.Append(nextKey.KeyChar);
|
||||
_singleton.Render(); // Render prompt
|
||||
continue;
|
||||
@@ -1907,6 +1937,109 @@ namespace PSConsoleUtilities
|
||||
_singleton.YankPopImpl();
|
||||
}
|
||||
|
||||
void YankArgImpl(YankLastArgState yankLastArgState)
|
||||
{
|
||||
Debug.Assert(yankLastArgState.historyIndex >= 0 && yankLastArgState.historyIndex < _history.Count);
|
||||
|
||||
Token[] tokens;
|
||||
ParseError[] errors;
|
||||
var buffer = _history[yankLastArgState.historyIndex];
|
||||
Parser.ParseInput(buffer._line, out tokens, out errors);
|
||||
|
||||
int arg = (yankLastArgState.argument < 0)
|
||||
? tokens.Length + yankLastArgState.argument - 1
|
||||
: yankLastArgState.argument;
|
||||
if (arg < 0 || arg >= tokens.Length)
|
||||
{
|
||||
Ding();
|
||||
return;
|
||||
}
|
||||
|
||||
var argText = tokens[arg].Text;
|
||||
if (yankLastArgState.startPoint < 0)
|
||||
{
|
||||
yankLastArgState.startPoint = _current;
|
||||
Insert(argText);
|
||||
}
|
||||
else
|
||||
{
|
||||
Replace(yankLastArgState.startPoint, _current - yankLastArgState.startPoint, argText);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Yank the first argument (after the command) from the previous history line.
|
||||
/// With an argument, yank the nth argument (starting from 0), if the argument
|
||||
/// is negative, start from the last argument.
|
||||
/// </summary>
|
||||
public static void YankNthArg(ConsoleKeyInfo? key = null, object arg = null)
|
||||
{
|
||||
var yankLastArgState = new YankLastArgState
|
||||
{
|
||||
argument = (arg is int) ? (int)arg : 1,
|
||||
historyIndex = _singleton._currentHistoryIndex - 1,
|
||||
};
|
||||
_singleton.YankArgImpl(yankLastArgState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Yank the last argument from the previous history line. With an argument,
|
||||
/// the first time it is invoked, behaves just like YankNthArg. If invoked
|
||||
/// multiple times, instead it iterates through history and arg sets the direction
|
||||
/// (negative reverses the direction.)
|
||||
/// </summary>
|
||||
public static void YankLastArg(ConsoleKeyInfo? key = null, object arg = null)
|
||||
{
|
||||
_singleton._yankLastArgCommandCount += 1;
|
||||
|
||||
if (_singleton._yankLastArgCommandCount == 1)
|
||||
{
|
||||
_singleton._yankLastArgState = new YankLastArgState
|
||||
{
|
||||
argument = (arg is int) ? (int)arg : -1,
|
||||
historyIncrement = -1,
|
||||
historyIndex = _singleton._currentHistoryIndex - 1
|
||||
};
|
||||
|
||||
_singleton.YankArgImpl(_singleton._yankLastArgState);
|
||||
return;
|
||||
}
|
||||
|
||||
var yankLastArgState = _singleton._yankLastArgState;
|
||||
|
||||
if (arg != null)
|
||||
{
|
||||
if (!(arg is int))
|
||||
{
|
||||
Ding();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int)arg < 0)
|
||||
{
|
||||
yankLastArgState.historyIncrement = -yankLastArgState.historyIncrement;
|
||||
}
|
||||
}
|
||||
|
||||
yankLastArgState.historyIndex += yankLastArgState.historyIncrement;
|
||||
|
||||
// Don't increment more than 1 out of range so it's quick to get back to being in range.
|
||||
if (yankLastArgState.historyIndex < 0)
|
||||
{
|
||||
Ding();
|
||||
yankLastArgState.historyIndex = 0;
|
||||
}
|
||||
else if (yankLastArgState.historyIndex >= _singleton._history.Count)
|
||||
{
|
||||
Ding();
|
||||
yankLastArgState.historyIndex = _singleton._history.Count - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_singleton.YankArgImpl(yankLastArgState);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Kill/Yank
|
||||
|
||||
private enum FindTokenMode
|
||||
|
||||
Reference in New Issue
Block a user