diff --git a/PSReadLine/BasicEditing.cs b/PSReadLine/BasicEditing.cs index a59bdf4e..a07434c2 100644 --- a/PSReadLine/BasicEditing.cs +++ b/PSReadLine/BasicEditing.cs @@ -246,6 +246,72 @@ public static void DeleteCharOrExit(ConsoleKeyInfo? key = null, object arg = nul _singleton.DeleteCharImpl(1, orExit: true); } + /// + /// A helper function to change the case of the current word. + /// + private static void UpdateWordCase(bool toUpper, ConsoleKeyInfo? key = null, object arg = null) + { + if (_singleton._current >= _singleton._buffer.Length) + { + Ding(); + return; + } + + int endOfWord = _singleton.FindForwardWordPoint(_singleton.Options.WordDelimiters); + int wordlen = endOfWord - _singleton._current; + + string word = _singleton._buffer.ToString(_singleton._current, wordlen); + word = toUpper ? word.ToUpper() : word.ToLower(); + + Replace(_singleton._current, wordlen, word); + + _singleton.MoveCursor(endOfWord); + _singleton.Render(); + } + + /// + /// Upcase the current word and move to the next one. + /// + public static void UpcaseWord(ConsoleKeyInfo? key = null, object arg = null) + { + UpdateWordCase(true, key, arg); + } + + /// + /// Downcase the current word and move to the next one. + /// + public static void DowncaseWord(ConsoleKeyInfo? key = null, object arg = null) + { + UpdateWordCase(false, key, arg); + } + + /// + /// Capitalize the current word and move to the next one. + /// + public static void CapitalizeWord(ConsoleKeyInfo? key = null, object arg = null) + { + if (_singleton._current >= _singleton._buffer.Length) + { + Ding(); + return; + } + + int endOfWord = _singleton.FindForwardWordPoint(_singleton.Options.WordDelimiters); + int wordlen = endOfWord - _singleton._current; + + char[] word = _singleton._buffer.ToString(_singleton._current, wordlen).ToLower().ToCharArray(); + int idxFirstLetter = Array.FindIndex(word, x => char.IsLetter(x)); + + if (idxFirstLetter > 0) + { + word[idxFirstLetter] = Char.ToUpper(word[idxFirstLetter]); + Replace(_singleton._current, wordlen, new string(word)); + } + + _singleton.MoveCursor(endOfWord); + _singleton.Render(); + } + private bool AcceptLineImpl(bool validate) { using var _ = _prediction.DisableScoped(); diff --git a/PSReadLine/KeyBindings.cs b/PSReadLine/KeyBindings.cs index 9315cd56..08474b54 100644 --- a/PSReadLine/KeyBindings.cs +++ b/PSReadLine/KeyBindings.cs @@ -339,6 +339,9 @@ void SetDefaultEmacsBindings() { Keys.AltH, MakeKeyHandler(ShowParameterHelp, "ShowParameterHelp") }, { Keys.F1, MakeKeyHandler(ShowCommandHelp, "ShowCommandHelp") }, { Keys.F2, MakeKeyHandler(SwitchPredictionView, "SwitchPredictionView") }, + { Keys.AltU, MakeKeyHandler(UpcaseWord, "UpcaseWord") }, + { Keys.AltL, MakeKeyHandler(DowncaseWord, "DowncaseWord") }, + { Keys.AltC, MakeKeyHandler(CapitalizeWord, "CapitalizeWord") }, }; // Some bindings are not available on certain platforms @@ -399,14 +402,15 @@ public static KeyHandlerGroup GetDisplayGrouping(string function) case nameof(AcceptAndGetNext): case nameof(AcceptLine): case nameof(AddLine): - case nameof(BackwardDeleteInput): 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): @@ -414,13 +418,14 @@ public static KeyHandlerGroup GetDisplayGrouping(string function) case nameof(DeleteCharOrExit): case nameof(DeleteEndOfBuffer): case nameof(DeleteEndOfWord): - case nameof(DeleteRelativeLines): 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): @@ -442,6 +447,7 @@ public static KeyHandlerGroup GetDisplayGrouping(string function) case nameof(Undo): case nameof(UndoAll): case nameof(UnixWordRubout): + case nameof(UpcaseWord): case nameof(ValidateAndAcceptLine): case nameof(ViAcceptLine): case nameof(ViAcceptLineOrExit):