2

tl;博士

我想找到bash edit-and-execute-command小部件或zsh edit-command-line小部件的 Powershell 版本。

背景

短命令直接在命令行上执行,长而复杂的命令从脚本中执行。但是,在它们变得“长”之前,能够在命令行上测试中等长度的命令会有所帮助。为了帮助完成这项工作,在外部编辑器中编辑命令变得非常有帮助。AFAIK Powershell 并不像 egbashzshdo 那样本机支持这一点。

我目前的尝试

我是 Powershell 的新手,所以我一定会犯很多错误,但我已经提出了一个使用[Microsoft.Powershell.PSConsoleReadLine]该类功能的可行解决方案。我可以将当​​前命令行复制到文件中,编辑文件,然后将编辑后的版本重新注入命令行:

Set-PSReadLineKeyHandler -Chord "Alt+e" -ScriptBlock {
  $CurrentInput = $null

  # Copy current command-line input, save it to a file and clear it
  [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref] $CurrentInput, [ref] $null)
  Set-Content -Path "C:\Temp\ps_${PID}.txt" -Value "$CurrentInput"
  [Microsoft.PowerShell.PSConsoleReadLine]::KillRegion()

  # Edit the command with gvim
  Start-Job -Name EditCMD -ScriptBlock { gvim "C:\Temp\ps_${Using:PID}.txt" }
  Wait-Job  -Name EditCMD

  # Get command back from file the temporary file and insert it into the command-line
  $NewInput  = (Get-Content -Path "C:\Temp\ps_${PID}.txt") -join "`n"
  [Microsoft.PowerShell.PSConsoleReadLine]::Insert($NewInput)
}

问题

我目前的解决方案感觉笨重而且有点脆弱。还有其他解决方案吗?可以改进当前的解决方案吗?

环境

  • 操作系统 Windows 10.0.19043.0
  • Powershell 版本 5.1.19041.1320
  • PSReadLine 版本 2.0.0

我采用的解决方案

创建一个类似于mklement0显示的“烘焙”可执行文件。我更喜欢vim这个而不是`gvim,因为它直接在控制台中运行:

'@vim -f %*' > psvim.cmd
$env:EDITOR = "psvim"
Set-PSReadLineKeyHandler -Chord "Alt+e" -Function ViEditVisually
4

2 回答 2

3

这段代码有一些问题:

  • 临时路径是硬编码的,它应该使用$env:temp或更好[IO.Path]::GetTempPath()(为了跨平台兼容性)。
  • 编辑该行后,它不会替换整行,只会替换光标左侧的文本。正如mklement0所指出的,我们可以简单地替换现有缓冲区而不是擦除它,从而解决了问题。
  • 为编辑器使用正确的参数时,不需要创建作业来等待它。对于 VSCode,这是--wait( -w),对于 gvim,这是--nofork( -f),这会阻止这些进程与控制台进程分离,因此 PowerShell 代码会一直等到用户关闭编辑器。
  • 关闭编辑器后临时文件不会被删除。

这是我修复代码的尝试。我不使用gvim,所以我用 VSCode 测试了它code.exe。下面的代码也包含一个注释行gvim(由 OP 确认工作)。

Set-PSReadLineKeyHandler -Chord "Alt+e" -ScriptBlock {
    $CurrentInput = $null

    # Copy current console line
    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref] $CurrentInput, [ref] $null)

    # Save current console line to temp file
    $tempFilePath = Join-Path ([IO.Path]::GetTempPath()) "ps_$PID.ps1"
    Set-Content $tempFilePath -Value $CurrentInput -Encoding utf8

    # Edit the console line using VSCode
    code --new-window --wait $tempFilePath

    # Uncomment for using gvim editor instead
    # gvim -f $tempFilePath

    # The console doesn't like the CR character, so rejoin lines using LF only. 
    $editedInput = ((Get-Content -LiteralPath $tempFilePath) -join "`n").Trim()
    
    # Replace current console line with the content of the temp file
    [Microsoft.PowerShell.PSConsoleReadLine]::Replace(0, $currentInput.Length, $editedInput)

    Remove-Item $tempFilePath
}

更新:

GitHub Gist包含代码的更新版本。新功能包括保存/恢复光标位置、将光标位置传递给 VSCode 以及在控制台被阻止时显示消息。

笔记:

  • VSCode 的默认安装将 VSCode 二进制文件的目录添加到$env:PATH,这使我们能够编写只是code为了启动编辑器。
  • 虽然 UTF-8 是PowerShell CoreSet-Content等cmdlet 的默认编码,但对于Windows PowerShell,该参数是正确保存包含 Unicode 字符的命令所必需的。不需要指定编码,因为 Windows PowerShell 添加了一个 BOM 来检测并且 PowerShell Core 再次默认为 UTF-8。-Encoding utf8Get-ContentGet-Content
  • Alt+E在您打开控制台时始终可用,只需将此代码添加到您的$profile文件中。使小代码示例的快速测试和编辑变得轻而易举。
  • VSCode 设置 - 要获得最简化的体验,请启用“自动保存:onWindowChange”。允许您关闭编辑器并保存文件(更新控制台行),只需按一下即可Ctrl+W
于 2022-02-18T14:27:01.323 回答
3

tl;博士

  • PSReadLine带有您正在寻找的功能,即ViEditVisually函数,并且在类 Unix 平台上它甚至具有默认键绑定。

  • 要使该功能正常工作,您需要设置$env:VISUAL或设置$env:EDITOR您的编辑器可执行文件的名称/路径。

  • 从 PSReadLine v2.1 开始,如果您还需要为您的编辑器包括选项- 例如-ffor gvim- 您需要创建一个具有“已烘焙”选项的辅助可执行文件。

    • 由于创建帮助程序可执行文件很麻烦,因此您已尝试并在zett42 的有用答案中对其进行了改进,因此该功能的自定义仿真可能是目前更简单的解决方案。zett42 的答案还链接到一个要点,该要点通过保留光标位置来改进原始功能。

    • GitHub 问题 #3214建议添加对识别可执行文件及其在这些环境变量中的选项的支持。

详情如下。


  • PSReadLine模块附带这样一个特性,即ViEditVisually函数

  • 它的默认键绑定(如果有)取决于 PSReadLine 的编辑模式,您可以使用以下命令进行设置Set-PSReadLineOption -EditMode <mode>

    • Windows模式(Windows 上的默认模式):未绑定
    • Emacs模式(macOS 和 Linux 上的默认模式):Ctrl-xCtrl-e
    • Vi模式:v在命令模式下(按下Esc进入)
  • 用于Set-PSReadLineKeyHandler建立自定义键绑定,类似于问题中的方法;例如,绑定Alt-e

    • Set-PSReadLineKeyHandler -Chord Alt+e -Function ViEditVisually
  • 要使该功能正常工作,您必须通过以下任一环境变量按优先顺序定义要使用的编辑器可执行文件:$env:VISUAL$env:EDITOR;如果没有定义(有效的)编辑器,则在调用函数时发出警告哔声并且不采取任何措施。

    • 例如,要nano在 macOS 上使用编辑器:$env:VISUAL = 'nano'

    • 值必须引用可执行文件- 通过完整路径或更典型地仅通过名称,在这种情况下,它必须位于列出的目录中$env:PATH

      • 注意:.ps1脚本不能作为可执行文件,但Windows 上的批处理文件和类 Unix 平台上基于 shebang-line 的shell 脚本可以。
    • 从 PSReadLine 2.1 开始,支持包括可执行文件的选项- 例如--newindow --waitfor code(Visual Studio Code)

      • 因此,目前,如果您选择的编辑器需要 options,您需要创建一个包含这些选项的辅助可执行文件;见下面的例子。

      • GitHub issue #3214提议增加对允许将编辑器可执行文件加上选项指定为环境变量值的支持,这是 Git(识别相同变量)已经支持的东西;例如,您可以定义:
        $env:VISUAL = 'code --new-window --wait'


code带有(Visual Studio Code)的辅助程序可执行文件的示例配置:

  • 在此示例中,在用户的主目录中创建一个辅助可执行文件:

    • 在 Windows 上:

      '@code --new-window --wait %*' > "$HOME\codewait.cmd"
      
    • 在类 Unix 平台上:

      "#!/bin/sh`ncode --new-window --wait `"$@`"" > "$HOME/codewait"; chmod a+x "$HOME/codewait"
      
  • $env:VISUAL将指向辅助程序可执行文件的定义添加到您的$PROFILE文件中,并根据需要定义自定义键绑定:

$env:VISUAL = "$HOME/codewait"

# Custom key binding
Set-PSReadLineKeyHandler -Chord Alt+e -Function ViEditVisually
于 2022-02-18T23:49:57.870 回答