PowerShell / PSReadLine

A bash inspired readline implementation for PowerShell
BSD 2-Clause "Simplified" License
3.74k stars 295 forks source link

Support custom chords in vi modes #759

Closed andrewzigerelli closed 1 year ago

andrewzigerelli commented 6 years ago

Could you support mapping to multiple keys? It's a common to remap the exit mode functionality (ESC for vi) to \<jj> or \<jk> for vi.

Environment data

PS version: 5.1.17134.228 PSReadline version: 1.2 os: 10.0.17134.1 (WinBuild.160101.0800) PS file version: 10.0.17134.1 (WinBuild.160101.0800)

Steps to reproduce or exception report

~ $ Set-PSReadLineKeyHandler -Key jk -Function ViCommandMode Set-PSReadLineKeyHandler : Unrecognized key 'jk'. Please use a character literal or a well-known key name from the System.ConsoleKey enumeration. At line:1 char:1

lzybkr commented 6 years ago

Multiple keys are specified with a comma, so you would use:

Set-PSReadLineKeyHandler -Key j,k -Function ViCommandMode

That said, this still doesn't seem to work correctly, it seems to switch to command mode after typing j. Possibly related - there is no timeout code that would be needed to support this scenario where you type j to insert, or even j and a short delay before k to insert jk.

corben2 commented 5 years ago

Here's a way to achieve this (or at least something close).

Set-PSReadLineKeyHandler -Chord 'j' -ScriptBlock {
  if ([Microsoft.PowerShell.PSConsoleReadLine]::InViInsertMode()) {
    $key = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    if ($key.Character -eq 'k') {
      [Microsoft.PowerShell.PSConsoleReadLine]::ViCommandMode()
    }
    else {
      [Microsoft.Powershell.PSConsoleReadLine]::Insert('j')
      [Microsoft.Powershell.PSConsoleReadLine]::Insert($key.Character)
    }
  }
}

Put that into your $PROFILE. When in insert mode, if a j is pressed, it'll not insert anything until the next key is pressed. If that key is a 'k', it'll switch to ViCommandMode. If it's not, it'll insert the j and whatever the next key is.