Rebind Escape в PSReadline для Vi-Mode

Я установил модуль PSReadline для PowerShell, чтобы получать привязки клавиш из Bash в PowerShell. Я включил Vi-Mode, и он работает хорошо.

Проблема в том, что в Vim я всегда использую j, k для выхода из режима вставки. Это означает: сначала я набираю j, а затем k очень быстро. Если я действительно хочу ввести j и k, тогда я просто жду времени ожидания после ввода j.

Как я могу сделать то же самое в Vi-Mode в PSReadline? Я уже попробовал: Set-PSReadlineKeyHandler -Chord 'j', 'k' ViCommandMode, но тогда я не мог набрать j или же k больше. Есть идеи?

0 ответов

Я удивлен, что этот вопрос не так популярен. Проблема с ответом Корбена заключается в том, что после нажатия 'j', если следующая нажатая клавиша является return или модификатором, например ctrl, вместо клавиши, которую вы ожидаете использовать, вставляется литерал.

Я переписал ответ, чтобы исправить эти две проблемы, а также превратил его в функцию, чтобы упростить повторное использование (например, при связывании двух разных букв, например jk).

Set-PSReadLineKeyHandler -vimode insert -Chord "k" -ScriptBlock { mapTwoLetterNormal 'k' 'j' }
Set-PSReadLineKeyHandler -vimode insert -Chord "j" -ScriptBlock { mapTwoLetterNormal 'j' 'k' }
function mapTwoLetterNormal($a, $b){
  mapTwoLetterFunc $a $b -func $function:setViCommandMode
}
function setViCommandMode{
    [Microsoft.PowerShell.PSConsoleReadLine]::ViCommandMode()
}

function mapTwoLetterFunc($a,$b,$func) {
  if ([Microsoft.PowerShell.PSConsoleReadLine]::InViInsertMode()) {
    $key = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    if ($key.Character -eq $b) {
        &$func
    } else {
      [Microsoft.Powershell.PSConsoleReadLine]::Insert("$a")
      # Representation of modifiers (like shift) when ReadKey uses IncludeKeyDown
      if ($key.Character -eq 0x00) {
        return
      } else {
        # Insert func above converts escape characters to their literals, e.g.
        # converts return to ^M. This doesn't.
        $wshell = New-Object -ComObject wscript.shell
        $wshell.SendKeys("{$($key.Character)}")
      }
    }
  }
}


# Bonus example
function replaceWithExit {
    [Microsoft.PowerShell.PSConsoleReadLine]::BackwardKillLine()
    [Microsoft.PowerShell.PSConsoleReadLine]::KillLine()
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert('exit')
}
Set-PSReadLineKeyHandler -Chord ";" -ScriptBlock { mapTwoLetterFunc ';' 'q' -func $function:replaceWithExit }

Для этого добавьте в свой $Profile следующее:

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)
    }
  }
}

Однако это может вызвать проблемы с вставкой j.

Другие вопросы по тегам