/********************************************************************++ Copyright (c) Microsoft Corporation. All rights reserved. --********************************************************************/ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Management.Automation; using System.Runtime.InteropServices; using System.Text; using Microsoft.PowerShell.PSReadLine; namespace Microsoft.PowerShell { /// /// A group used for sorting key handlers. /// public enum KeyHandlerGroup { /// Basic editing functions Basic, /// Cursor movement functions CursorMovement, /// History functions History, /// Completion functions Completion, /// Prediction functions Prediction, /// Miscellaneous functions Miscellaneous, /// Selection functions Selection, /// Search functions Search, /// User defined functions Custom } /// /// The class is used as the output type for the cmdlet Get-PSReadLineKeyHandler /// public class KeyHandler { /// /// The key that is bound or unbound. /// public string Key { get; set; } /// /// The name of the function that a key is bound to, if any. /// public string Function { get; set; } /// /// A short description of the behavior of the function. /// public string Description { get { var result = _description; if (string.IsNullOrWhiteSpace(result)) result = PSReadLineResources.ResourceManager.GetString(Function + "Description"); if (string.IsNullOrWhiteSpace(result)) result = Function; return result; } set => _description = value; } private string _description; /// /// The group that this key handler belongs to. /// public KeyHandlerGroup Group { get; set; } /// /// Get the description of the group. /// public static string GetGroupingDescription(KeyHandlerGroup grouping) { switch (grouping) { case KeyHandlerGroup.Basic: return PSReadLineResources.BasicGrouping; case KeyHandlerGroup.CursorMovement: return PSReadLineResources.CursorMovementGrouping; case KeyHandlerGroup.History: return PSReadLineResources.HistoryGrouping; case KeyHandlerGroup.Completion: return PSReadLineResources.CompletionGrouping; case KeyHandlerGroup.Prediction: return PSReadLineResources.PredictionGrouping; case KeyHandlerGroup.Miscellaneous: return PSReadLineResources.MiscellaneousGrouping; case KeyHandlerGroup.Selection: return PSReadLineResources.SelectionGrouping; case KeyHandlerGroup.Search: return PSReadLineResources.SearchGrouping; case KeyHandlerGroup.Custom: return PSReadLineResources.CustomGrouping; default: return ""; } } } public partial class PSConsoleReadLine { class KeyHandler { // Each key handler will be passed 2 arguments. Most will ignore these arguments, // but having a consistent signature greatly simplifies dispatch. Defaults // should be included on all handlers that ignore their parameters so they // can be called from PowerShell without passing anything. // // The first argument is the key that caused the action to be called // (the second key when it's a 2 key chord). The default is null (it's nullable) // because PowerShell can't handle default(PSKeyInfo) as a default. // Most actions will ignore this argument. // // The second argument is an arbitrary object. It will usually be either a number // (e.g. as a repeat count) or a string. Most actions will ignore this argument. public Action Action; public string BriefDescription; public string LongDescription { get => _longDescription ?? (_longDescription = PSReadLineResources.ResourceManager.GetString(BriefDescription + "Description")); set => _longDescription = value; } private string _longDescription; public ScriptBlock ScriptBlock; public override string ToString() { return BriefDescription; } } static KeyHandler MakeKeyHandler(Action action, string briefDescription, string longDescription = null, ScriptBlock scriptBlock = null) { return new KeyHandler { Action = action, BriefDescription = briefDescription, LongDescription = longDescription, ScriptBlock = scriptBlock, }; } private Dictionary _dispatchTable; private Dictionary> _chordDispatchTable; /// /// Helper to set bindings based on EditMode /// void SetDefaultBindings(EditMode editMode) { switch (editMode) { case EditMode.Emacs: SetDefaultEmacsBindings(); break; case EditMode.Vi: SetDefaultViBindings(); break; case EditMode.Windows: SetDefaultWindowsBindings(); break; } } void SetDefaultWindowsBindings() { _dispatchTable = new Dictionary { { Keys.Enter, MakeKeyHandler(AcceptLine, "AcceptLine") }, { Keys.ShiftEnter, MakeKeyHandler(AddLine, "AddLine") }, { Keys.CtrlEnter, MakeKeyHandler(InsertLineAbove, "InsertLineAbove") }, { Keys.CtrlShiftEnter, MakeKeyHandler(InsertLineBelow, "InsertLineBelow") }, { Keys.Escape, MakeKeyHandler(RevertLine, "RevertLine") }, { Keys.LeftArrow, MakeKeyHandler(BackwardChar, "BackwardChar") }, { Keys.RightArrow, MakeKeyHandler(ForwardChar, "ForwardChar") }, { Keys.CtrlLeftArrow, MakeKeyHandler(BackwardWord, "BackwardWord") }, { Keys.CtrlRightArrow, MakeKeyHandler(NextWord, "NextWord") }, { Keys.ShiftLeftArrow, MakeKeyHandler(SelectBackwardChar, "SelectBackwardChar") }, { Keys.ShiftRightArrow, MakeKeyHandler(SelectForwardChar, "SelectForwardChar") }, { Keys.CtrlShiftLeftArrow, MakeKeyHandler(SelectBackwardWord, "SelectBackwardWord") }, { Keys.CtrlShiftRightArrow, MakeKeyHandler(SelectNextWord, "SelectNextWord") }, { Keys.UpArrow, MakeKeyHandler(PreviousHistory, "PreviousHistory") }, { Keys.DownArrow, MakeKeyHandler(NextHistory, "NextHistory") }, { Keys.Home, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") }, { Keys.End, MakeKeyHandler(EndOfLine, "EndOfLine") }, { Keys.ShiftHome, MakeKeyHandler(SelectBackwardsLine, "SelectBackwardsLine") }, { Keys.ShiftEnd, MakeKeyHandler(SelectLine, "SelectLine") }, { Keys.Delete, MakeKeyHandler(DeleteChar, "DeleteChar") }, { Keys.Backspace, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") }, { Keys.Tab, MakeKeyHandler(TabCompleteNext, "TabCompleteNext") }, { Keys.ShiftTab, MakeKeyHandler(TabCompletePrevious, "TabCompletePrevious") }, { Keys.CtrlA, MakeKeyHandler(SelectAll, "SelectAll") }, { Keys.CtrlC, MakeKeyHandler(CopyOrCancelLine, "CopyOrCancelLine") }, { Keys.CtrlShiftC, MakeKeyHandler(Copy, "Copy") }, { Keys.CtrlL, MakeKeyHandler(ClearScreen, "ClearScreen") }, { Keys.CtrlR, MakeKeyHandler(ReverseSearchHistory, "ReverseSearchHistory") }, { Keys.CtrlS, MakeKeyHandler(ForwardSearchHistory, "ForwardSearchHistory") }, { Keys.CtrlV, MakeKeyHandler(Paste, "Paste") }, { Keys.ShiftInsert, MakeKeyHandler(Paste, "Paste") }, { Keys.CtrlX, MakeKeyHandler(Cut, "Cut") }, { Keys.CtrlY, MakeKeyHandler(Redo, "Redo") }, { Keys.CtrlZ, MakeKeyHandler(Undo, "Undo") }, { Keys.CtrlBackspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") }, { Keys.CtrlHome, MakeKeyHandler(BackwardDeleteInput, "BackwardDeleteInput") }, { Keys.CtrlRBracket, MakeKeyHandler(GotoBrace, "GotoBrace") }, { Keys.CtrlAltQuestion, MakeKeyHandler(ShowKeyBindings, "ShowKeyBindings") }, { Keys.AltPeriod, MakeKeyHandler(YankLastArg, "YankLastArg") }, { Keys.Alt0, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt1, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt2, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt3, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt4, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt5, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt6, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt7, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt8, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt9, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.AltMinus, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.AltQuestion, MakeKeyHandler(WhatIsKey, "WhatIsKey") }, { Keys.AltA, MakeKeyHandler(SelectCommandArgument, "SelectCommandArgument") }, { Keys.AltH, MakeKeyHandler(ShowParameterHelp, "ShowParameterHelp") }, { Keys.F1, MakeKeyHandler(ShowCommandHelp, "ShowCommandHelp") }, { Keys.F2, MakeKeyHandler(SwitchPredictionView, "SwitchPredictionView") }, { Keys.F3, MakeKeyHandler(CharacterSearch, "CharacterSearch") }, { Keys.ShiftF3, MakeKeyHandler(CharacterSearchBackward, "CharacterSearchBackward") }, { Keys.F4, MakeKeyHandler(ShowFullPredictionTooltip, "ShowFullPredictionTooltip") }, { Keys.F8, MakeKeyHandler(HistorySearchBackward, "HistorySearchBackward") }, { Keys.ShiftF8, MakeKeyHandler(HistorySearchForward, "HistorySearchForward") }, // Added for xtermjs-based terminals that send different key combinations. { Keys.AltD, MakeKeyHandler(KillWord, "KillWord") }, { Keys.CtrlAt, MakeKeyHandler(MenuComplete, "MenuComplete") }, { Keys.CtrlW, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") }, }; // Some bindings are not available on certain platforms if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { _dispatchTable.Add(Keys.CtrlSpace, MakeKeyHandler(MenuComplete, "MenuComplete")); _dispatchTable.Add(Keys.AltF7, MakeKeyHandler(ClearHistory, "ClearHistory")); _dispatchTable.Add(Keys.CtrlDelete, MakeKeyHandler(KillWord, "KillWord")); _dispatchTable.Add(Keys.CtrlEnd, MakeKeyHandler(ForwardDeleteInput, "ForwardDeleteInput")); _dispatchTable.Add(Keys.CtrlH, MakeKeyHandler(BackwardDeleteChar,"BackwardDeleteChar")); // PageUp/PageDown and CtrlPageUp/CtrlPageDown bindings are supported on Windows only because they depend on the // API 'Console.SetWindowPosition', which throws 'PlatformNotSupportedException' on unix platforms. _dispatchTable.Add(Keys.PageUp, MakeKeyHandler(ScrollDisplayUp, "ScrollDisplayUp")); _dispatchTable.Add(Keys.PageDown, MakeKeyHandler(ScrollDisplayDown, "ScrollDisplayDown")); _dispatchTable.Add(Keys.CtrlPageUp, MakeKeyHandler(ScrollDisplayUpLine, "ScrollDisplayUpLine")); _dispatchTable.Add(Keys.CtrlPageDown, MakeKeyHandler(ScrollDisplayDownLine, "ScrollDisplayDownLine")); } _chordDispatchTable = new Dictionary>(); } void SetDefaultEmacsBindings() { _dispatchTable = new Dictionary { { Keys.Backspace, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") }, { Keys.Enter, MakeKeyHandler(AcceptLine, "AcceptLine") }, { Keys.ShiftEnter, MakeKeyHandler(AddLine, "AddLine") }, { Keys.LeftArrow, MakeKeyHandler(BackwardChar, "BackwardChar") }, { Keys.RightArrow, MakeKeyHandler(ForwardChar, "ForwardChar") }, { Keys.ShiftLeftArrow, MakeKeyHandler(SelectBackwardChar, "SelectBackwardChar") }, { Keys.ShiftRightArrow, MakeKeyHandler(SelectForwardChar, "SelectForwardChar") }, { Keys.UpArrow, MakeKeyHandler(PreviousHistory, "PreviousHistory") }, { Keys.DownArrow, MakeKeyHandler(NextHistory, "NextHistory") }, { Keys.AltLess, MakeKeyHandler(BeginningOfHistory, "BeginningOfHistory") }, { Keys.AltGreater, MakeKeyHandler(EndOfHistory, "EndOfHistory") }, { Keys.Home, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") }, { Keys.End, MakeKeyHandler(EndOfLine, "EndOfLine") }, { Keys.ShiftHome, MakeKeyHandler(SelectBackwardsLine, "SelectBackwardsLine") }, { Keys.ShiftEnd, MakeKeyHandler(SelectLine, "SelectLine") }, { Keys.Escape, MakeKeyHandler(Chord, "ChordFirstKey") }, { Keys.Delete, MakeKeyHandler(DeleteChar, "DeleteChar") }, { Keys.Tab, MakeKeyHandler(Complete, "Complete") }, { Keys.CtrlA, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") }, { Keys.CtrlB, MakeKeyHandler(BackwardChar, "BackwardChar") }, { Keys.CtrlC, MakeKeyHandler(CopyOrCancelLine, "CopyOrCancelLine") }, { Keys.CtrlD, MakeKeyHandler(DeleteCharOrExit, "DeleteCharOrExit") }, { Keys.CtrlE, MakeKeyHandler(EndOfLine, "EndOfLine") }, { Keys.CtrlF, MakeKeyHandler(ForwardChar, "ForwardChar") }, { Keys.CtrlG, MakeKeyHandler(Abort, "Abort") }, { Keys.CtrlL, MakeKeyHandler(ClearScreen, "ClearScreen") }, { Keys.CtrlK, MakeKeyHandler(KillLine, "KillLine") }, { Keys.CtrlM, MakeKeyHandler(ValidateAndAcceptLine, "ValidateAndAcceptLine") }, { Keys.CtrlN, MakeKeyHandler(NextHistory, "NextHistory") }, { Keys.CtrlO, MakeKeyHandler(AcceptAndGetNext, "AcceptAndGetNext") }, { Keys.CtrlP, MakeKeyHandler(PreviousHistory, "PreviousHistory") }, { Keys.CtrlR, MakeKeyHandler(ReverseSearchHistory, "ReverseSearchHistory") }, { Keys.CtrlS, MakeKeyHandler(ForwardSearchHistory, "ForwardSearchHistory") }, { Keys.CtrlT, MakeKeyHandler(SwapCharacters, "SwapCharacters") }, { Keys.CtrlU, MakeKeyHandler(BackwardKillInput, "BackwardKillInput") }, { Keys.CtrlX, MakeKeyHandler(Chord, "ChordFirstKey") }, { Keys.CtrlW, MakeKeyHandler(UnixWordRubout, "UnixWordRubout") }, { Keys.CtrlY, MakeKeyHandler(Yank, "Yank") }, { Keys.CtrlAt, MakeKeyHandler(SetMark, "SetMark") }, { Keys.CtrlBackspace, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") }, { Keys.CtrlUnderbar, MakeKeyHandler(Undo, "Undo") }, { Keys.CtrlRBracket, MakeKeyHandler(CharacterSearch, "CharacterSearch") }, { Keys.CtrlAltRBracket, MakeKeyHandler(CharacterSearchBackward, "CharacterSearchBackward") }, { Keys.Alt0, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt1, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt2, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt3, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt4, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt5, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt6, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt7, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt8, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.Alt9, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.AltMinus, MakeKeyHandler(DigitArgument, "DigitArgument") }, { Keys.AltB, MakeKeyHandler(BackwardWord, "BackwardWord") }, { Keys.AltShiftB, MakeKeyHandler(SelectBackwardWord, "SelectBackwardWord") }, { Keys.AltD, MakeKeyHandler(KillWord, "KillWord") }, { Keys.AltF, MakeKeyHandler(ForwardWord, "ForwardWord") }, { Keys.AltShiftF, MakeKeyHandler(SelectForwardWord, "SelectForwardWord") }, { Keys.AltR, MakeKeyHandler(RevertLine, "RevertLine") }, { Keys.AltY, MakeKeyHandler(YankPop, "YankPop") }, { Keys.AltBackspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") }, { Keys.AltEquals, MakeKeyHandler(PossibleCompletions, "PossibleCompletions") }, { Keys.CtrlAltQuestion, MakeKeyHandler(ShowKeyBindings, "ShowKeyBindings") }, { Keys.AltQuestion, MakeKeyHandler(WhatIsKey, "WhatIsKey") }, { Keys.AltPeriod, MakeKeyHandler(YankLastArg, "YankLastArg") }, { Keys.AltUnderbar, MakeKeyHandler(YankLastArg, "YankLastArg") }, { Keys.CtrlAltY, MakeKeyHandler(YankNthArg, "YankNthArg") }, { Keys.AltA, MakeKeyHandler(SelectCommandArgument, "SelectCommandArgument") }, { Keys.AltH, MakeKeyHandler(ShowParameterHelp, "ShowParameterHelp") }, { Keys.F1, MakeKeyHandler(ShowCommandHelp, "ShowCommandHelp") }, { Keys.F2, MakeKeyHandler(SwitchPredictionView, "SwitchPredictionView") }, { Keys.F4, MakeKeyHandler(ShowFullPredictionTooltip, "ShowFullPredictionTooltip") }, { Keys.AltU, MakeKeyHandler(UpcaseWord, "UpcaseWord") }, { Keys.AltL, MakeKeyHandler(DowncaseWord, "DowncaseWord") }, { Keys.AltC, MakeKeyHandler(CapitalizeWord, "CapitalizeWord") }, }; // Some bindings are not available on certain platforms if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { _dispatchTable.Add(Keys.CtrlH, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar")); _dispatchTable.Add(Keys.CtrlSpace, MakeKeyHandler(MenuComplete, "MenuComplete")); _dispatchTable.Add(Keys.CtrlEnd, MakeKeyHandler(ScrollDisplayToCursor, "ScrollDisplayToCursor")); _dispatchTable.Add(Keys.CtrlHome, MakeKeyHandler(ScrollDisplayTop, "ScrollDisplayTop")); // PageUp/PageDown and CtrlPageUp/CtrlPageDown bindings are supported on Windows only because they depend on the // API 'Console.SetWindowPosition', which throws 'PlatformNotSupportedException' on unix platforms. _dispatchTable.Add(Keys.PageUp, MakeKeyHandler(ScrollDisplayUp, "ScrollDisplayUp")); _dispatchTable.Add(Keys.PageDown, MakeKeyHandler(ScrollDisplayDown, "ScrollDisplayDown")); _dispatchTable.Add(Keys.CtrlPageUp, MakeKeyHandler(ScrollDisplayUpLine, "ScrollDisplayUpLine")); _dispatchTable.Add(Keys.CtrlPageDown, MakeKeyHandler(ScrollDisplayDownLine, "ScrollDisplayDownLine")); } else { _dispatchTable.Add(Keys.AltSpace, MakeKeyHandler(SetMark, "SetMark")); } _chordDispatchTable = new Dictionary> { // Escape, table (meta key) [Keys.Escape] = new Dictionary { { Keys.B, MakeKeyHandler(BackwardWord, "BackwardWord") }, { Keys.D, MakeKeyHandler(KillWord, "KillWord")}, { Keys.F, MakeKeyHandler(ForwardWord, "ForwardWord")}, { Keys.R, MakeKeyHandler(RevertLine, "RevertLine")}, { Keys.Y, MakeKeyHandler(YankPop, "YankPop")}, { Keys.U, MakeKeyHandler(UpcaseWord, "UpcaseWord") }, { Keys.L, MakeKeyHandler(DowncaseWord, "DowncaseWord") }, { Keys.C, MakeKeyHandler(CapitalizeWord, "CapitalizeWord") }, { Keys.CtrlY, MakeKeyHandler(YankNthArg, "YankNthArg")}, { Keys.Backspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord")}, { Keys.Period, MakeKeyHandler(YankLastArg, "YankLastArg")}, { Keys.Underbar, MakeKeyHandler(YankLastArg, "YankLastArg")}, }, // Ctrl+X, table [Keys.CtrlX] = new Dictionary { { Keys.Backspace, MakeKeyHandler(BackwardKillInput, "BackwardKillInput") }, { Keys.CtrlE, MakeKeyHandler(ViEditVisually, "ViEditVisually") }, { Keys.CtrlU, MakeKeyHandler(Undo, "Undo") }, { Keys.CtrlX, MakeKeyHandler(ExchangePointAndMark, "ExchangePointAndMark") }, } }; } /// /// Used to group the built in functions for help and Get-PSReadLineKeyHandler output. /// public static KeyHandlerGroup GetDisplayGrouping(string function) { switch (function) { case nameof(Abort): case nameof(AcceptAndGetNext): case nameof(AcceptLine): case nameof(AddLine): case nameof(BackwardDeleteChar): case nameof(BackwardDeleteInput): case nameof(BackwardDeleteLine): case nameof(BackwardDeleteWord): case nameof(BackwardKillInput): case nameof(BackwardKillLine): case nameof(BackwardKillWord): case nameof(CancelLine): case nameof(CapitalizeWord): case nameof(Copy): case nameof(CopyOrCancelLine): case nameof(Cut): case nameof(DeleteChar): case nameof(DeleteCharOrExit): case nameof(DeleteEndOfBuffer): case nameof(DeleteEndOfWord): case nameof(DeleteLine): case nameof(DeleteLineToFirstChar): case nameof(DeleteNextLines): case nameof(DeletePreviousLines): case nameof(DeleteRelativeLines): case nameof(DeleteToEnd): case nameof(DeleteWord): case nameof(DowncaseWord): case nameof(ForwardDeleteInput): case nameof(ForwardDeleteLine): case nameof(InsertLineAbove): case nameof(InsertLineBelow): case nameof(InvertCase): case nameof(KillLine): case nameof(KillRegion): case nameof(KillWord): case nameof(Paste): case nameof(PasteAfter): case nameof(PasteBefore): case nameof(PrependAndAccept): case nameof(Redo): case nameof(RepeatLastCommand): case nameof(RevertLine): case nameof(ShellBackwardKillWord): case nameof(ShellKillWord): case nameof(SwapCharacters): case nameof(Undo): case nameof(UndoAll): case nameof(UnixWordRubout): case nameof(UpcaseWord): case nameof(ValidateAndAcceptLine): case nameof(ViAcceptLine): case nameof(ViAcceptLineOrExit): case nameof(ViAppendLine): case nameof(ViBackwardDeleteGlob): case nameof(ViBackwardGlob): case nameof(ViDeleteBrace): case nameof(ViDeleteEndOfGlob): case nameof(ViDeleteGlob): case nameof(ViDeleteToBeforeChar): case nameof(ViDeleteToBeforeCharBackward): case nameof(ViDeleteToChar): case nameof(ViDeleteToCharBackward): case nameof(ViInsertAtBegining): case nameof(ViInsertAtEnd): case nameof(ViInsertLine): case nameof(ViInsertWithAppend): case nameof(ViInsertWithDelete): case nameof(ViJoinLines): case nameof(ViReplaceToBeforeChar): case nameof(ViReplaceToBeforeCharBackward): case nameof(ViReplaceToChar): case nameof(ViReplaceToCharBackward): case nameof(ViYankBeginningOfLine): case nameof(ViYankEndOfGlob): case nameof(ViYankEndOfWord): case nameof(ViYankLeft): case nameof(ViYankLine): case nameof(ViYankNextGlob): case nameof(ViYankNextWord): case nameof(ViYankPercent): case nameof(ViYankPreviousGlob): case nameof(ViYankPreviousWord): case nameof(ViYankRight): case nameof(ViYankToEndOfLine): case nameof(ViYankToFirstChar): case nameof(Yank): case nameof(YankLastArg): case nameof(YankNthArg): case nameof(YankPop): return KeyHandlerGroup.Basic; // The following are private so cannot be used with a custom binding. case nameof(BackwardReplaceChar): case nameof(ReplaceChar): case nameof(ReplaceCharInPlace): case nameof(ViBackwardReplaceGlob): case nameof(ViBackwardReplaceLine): case nameof(ViBackwardReplaceLineToFirstChar): case nameof(ViBackwardReplaceWord): case nameof(ViReplaceBrace): case nameof(ViReplaceEndOfGlob): case nameof(ViReplaceEndOfWord): case nameof(ViReplaceGlob): case nameof(ViReplaceLine): case nameof(ViReplaceToEnd): case nameof(ViReplaceUntilEsc): case nameof(ViReplaceWord): return KeyHandlerGroup.Basic; case nameof(BackwardChar): case nameof(BackwardWord): case nameof(BeginningOfLine): case nameof(EndOfLine): case nameof(ForwardChar): case nameof(ForwardWord): case nameof(GotoBrace): case nameof(GotoColumn): case nameof(GotoFirstNonBlankOfLine): case nameof(MoveToEndOfLine): case nameof(MoveToFirstLine): case nameof(MoveToLastLine): case nameof(NextLine): case nameof(NextWord): case nameof(NextWordEnd): case nameof(PreviousLine): case nameof(ShellBackwardWord): case nameof(ShellForwardWord): case nameof(ShellNextWord): case nameof(ViBackwardChar): case nameof(ViBackwardWord): case nameof(ViForwardChar): case nameof(ViEndOfGlob): case nameof(ViEndOfPreviousGlob): case nameof(ViGotoBrace): case nameof(ViNextGlob): case nameof(ViNextWord): return KeyHandlerGroup.CursorMovement; case nameof(BeginningOfHistory): case nameof(ClearHistory): case nameof(EndOfHistory): case nameof(ForwardSearchHistory): case nameof(HistorySearchBackward): case nameof(HistorySearchForward): case nameof(NextHistory): case nameof(PreviousHistory): case nameof(ReverseSearchHistory): case nameof(ViSearchHistoryBackward): return KeyHandlerGroup.History; case nameof(Complete): case nameof(MenuComplete): case nameof(PossibleCompletions): case nameof(TabCompleteNext): case nameof(TabCompletePrevious): case nameof(ViTabCompleteNext): case nameof(ViTabCompletePrevious): return KeyHandlerGroup.Completion; case nameof(AcceptSuggestion): case nameof(AcceptNextSuggestionWord): case nameof(NextSuggestion): case nameof(PreviousSuggestion): case nameof(SwitchPredictionView): case nameof(ShowFullPredictionTooltip): return KeyHandlerGroup.Prediction; case nameof(CaptureScreen): case nameof(ClearScreen): case nameof(DigitArgument): case nameof(InvokePrompt): case nameof(ScrollDisplayDown): case nameof(ScrollDisplayDownLine): case nameof(ScrollDisplayToCursor): case nameof(ScrollDisplayTop): case nameof(ScrollDisplayUp): case nameof(ScrollDisplayUpLine): case nameof(SelfInsert): case nameof(ShowKeyBindings): case nameof(ViCommandMode): case nameof(ViDigitArgumentInChord): case nameof(ViEditVisually): case nameof(ViExit): case nameof(ViInsertMode): case nameof(ViDGChord): case nameof(WhatIsKey): case nameof(ShowCommandHelp): case nameof(ShowParameterHelp): return KeyHandlerGroup.Miscellaneous; case nameof(CharacterSearch): case nameof(CharacterSearchBackward): case nameof(RepeatLastCharSearch): case nameof(RepeatLastCharSearchBackwards): case nameof(RepeatSearch): case nameof(RepeatSearchBackward): case nameof(SearchChar): case nameof(SearchCharBackward): case nameof(SearchCharBackwardWithBackoff): case nameof(SearchCharWithBackoff): case nameof(SearchForward): return KeyHandlerGroup.Search; case nameof(ExchangePointAndMark): case nameof(SetMark): case nameof(SelectAll): case nameof(SelectBackwardChar): case nameof(SelectBackwardsLine): case nameof(SelectBackwardWord): case nameof(SelectForwardChar): case nameof(SelectForwardWord): case nameof(SelectLine): case nameof(SelectNextWord): case nameof(SelectShellBackwardWord): case nameof(SelectShellForwardWord): case nameof(SelectShellNextWord): case nameof(SelectCommandArgument): return KeyHandlerGroup.Selection; default: return KeyHandlerGroup.Custom; } } /// /// Show all bound keys. /// public static void ShowKeyBindings(ConsoleKeyInfo? key = null, object arg = null) { var buffer = new StringBuilder(); var boundKeys = GetKeyHandlers(includeBound: true, includeUnbound: false); var console = _singleton._console; foreach (var group in boundKeys.GroupBy(k => k.Group).OrderBy(k => k.Key)) { var groupDescription = PowerShell.KeyHandler.GetGroupingDescription(group.Key); buffer.AppendFormat("\n{0}\n", groupDescription); buffer.Append('=', groupDescription.Length); buffer.AppendLine(); // Compute column widths var groupBindings = group.OrderBy(k => k.Function).ToArray(); var keyWidth = -1; var funcWidth = -1; foreach (var binding in groupBindings) { keyWidth = Math.Max(keyWidth, binding.Key.Length); funcWidth = Math.Max(funcWidth, binding.Function.Length); } var maxDescriptionLength = console.WindowWidth - keyWidth - funcWidth - 2; var fmtString = "{0,-" + keyWidth + "} {1,-" + funcWidth + "} {2}\n"; foreach (var boundKey in groupBindings) { var description = boundKey.Description; if (description.Length >= maxDescriptionLength) { description = description.Substring(0, maxDescriptionLength - 4) + "..."; } buffer.AppendFormat(CultureInfo.InvariantCulture, fmtString, boundKey.Key, boundKey.Function, description); } } // Don't overwrite any of the line - so move to first line after the end of our buffer. var point = _singleton.EndOfBufferPosition(); console.SetCursorPosition(point.X, point.Y); console.Write("\n"); console.WriteLine(buffer.ToString()); InvokePrompt(key: null, arg: _singleton._console.CursorTop); } /// /// Read a key and tell me what the key is bound to. /// public static void WhatIsKey(ConsoleKeyInfo? key = null, object arg = null) { _singleton._statusLinePrompt = "what-is-key: "; _singleton.Render(); var toLookup = ReadKey(); var buffer = new StringBuilder(); _singleton._dispatchTable.TryGetValue(toLookup, out var keyHandler); buffer.Append(toLookup.KeyStr); if (keyHandler != null) { if (keyHandler.BriefDescription == "ChordFirstKey") { if (_singleton._chordDispatchTable.TryGetValue(toLookup, out var secondKeyDispatchTable)) { toLookup = ReadKey(); secondKeyDispatchTable.TryGetValue(toLookup, out keyHandler); buffer.Append(","); buffer.Append(toLookup.KeyStr); } } } buffer.Append(": "); if (keyHandler != null) { buffer.Append(keyHandler.BriefDescription); if (!string.IsNullOrWhiteSpace(keyHandler.LongDescription)) { buffer.Append(" - "); buffer.Append(keyHandler.LongDescription); } } else if (toLookup.KeyChar != 0) { buffer.Append("SelfInsert"); buffer.Append(" - "); buffer.Append(PSReadLineResources.SelfInsertDescription); } else { buffer.Append(PSReadLineResources.KeyIsUnbound); } _singleton.ClearStatusMessage(render: false); var console = _singleton._console; // Don't overwrite any of the line - so move to first line after the end of our buffer. var point = _singleton.EndOfBufferPosition(); console.SetCursorPosition(point.X, point.Y); console.Write("\n"); console.WriteLine(buffer.ToString()); InvokePrompt(key: null, arg: console.CursorTop); } } }