Psreadline: Support custom chords in vi modes

Created on 12 Sep 2018  路  2Comments  路  Source: PowerShell/PSReadLine

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

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

  • Set-PSReadLineKeyHandler -Key jk -Function ViCommandMode
  • ~~~~~~~~~~~~

    • CategoryInfo : NotSpecified: (:) [Set-PSReadlineKeyHandler], Ar

      gumentException

    • FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Se

      tPSReadlineKeyHandlerCommand

Issue-Enhancement

Most helpful comment

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.

All 2 comments

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.

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.

Was this page helpful?
0 / 5 - 0 ratings