diff --git a/PSReadLine/Cmdlets.cs b/PSReadLine/Cmdlets.cs
index 2917f6a..aef51c9 100644
--- a/PSReadLine/Cmdlets.cs
+++ b/PSReadLine/Cmdlets.cs
@@ -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; }
diff --git a/PSReadLine/Keys.cs b/PSReadLine/Keys.cs
index ffd9c59..609dfb0 100644
--- a/PSReadLine/Keys.cs
+++ b/PSReadLine/Keys.cs
@@ -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);
diff --git a/PSReadLine/PSReadLineResources.Designer.cs b/PSReadLine/PSReadLineResources.Designer.cs
index 59e87b1..426b4eb 100644
--- a/PSReadLine/PSReadLineResources.Designer.cs
+++ b/PSReadLine/PSReadLineResources.Designer.cs
@@ -537,6 +537,24 @@ namespace PSConsoleUtilities {
}
}
+ ///
+ /// Looks up a localized string similar to Copy the text of the last argument to the input.
+ ///
+ internal static string YankLastArgDescription {
+ get {
+ return ResourceManager.GetString("YankLastArgDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Copy the text of the first argument to the input.
+ ///
+ internal static string YankNthArgDescription {
+ get {
+ return ResourceManager.GetString("YankNthArgDescription", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Replace the previously yanked text with the text from the next kill ring position.
///
diff --git a/PSReadLine/PSReadLineResources.resx b/PSReadLine/PSReadLineResources.resx
index 599cda3..d628f97 100644
--- a/PSReadLine/PSReadLineResources.resx
+++ b/PSReadLine/PSReadLineResources.resx
@@ -279,4 +279,10 @@
Move the text from the cursor to the start of the current or previous whitespace delimited word to the kill ring
+
+ Copy the text of the last argument to the input
+
+
+ Copy the text of the first argument to the input
+
\ No newline at end of file
diff --git a/PSReadLine/ReadLine.cs b/PSReadLine/ReadLine.cs
index aaf0ab1..0107e7b 100644
--- a/PSReadLine/ReadLine.cs
+++ b/PSReadLine/ReadLine.cs
@@ -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(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);
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ 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);
+ }
+
+ ///
+ /// 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.)
+ ///
+ 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