教程:在 Windows 终端中启用 shell 集成

从终端 1.15 预览版开始,Windows 终端已开始试验性地支持一些“shell 集成”功能。 这些功能使命令行更易于使用。 在早期版本中,我们启用了 shell 来告知终端当前工作目录是什么。 现在,我们添加了对更多序列的支持,允许 shell 以语义方式将终端输出的各个部分描述为“提示”、“命令”或“输出”。 shell 还可以告知终端某个命令是成功还是失败。

这是从终端 v1.18 开始推出的一些 shell 集成功能的指南。 我们计划在将来基于这些功能构建更多功能,因此希望获得一些有关用户如何使用它们的其他反馈。

注意:值得注意的是,“标记”仍处于试验阶段,仅对终端的预览版本启用。 这些功能的设置可能会在将来的版本中更改。

WSL 的工作原理是怎样的?

shell 集成的工作原理是让 shell(或任何命令行应用程序)向终端写入特殊的“转义序列”。 这些转义序列不会输出到终端,而是提供一些元数据供终端用来详细了解应用程序中发生的情况。 通过将这些序列粘贴到 shell 的提示符中,你可以让 shell 不断向终端提供只有 shell 知道的信息。

对于以下序列来说:

  • OSC 是字符串 "\x1b]" - 一个转义字符,后跟 ]
  • ST 是“字符串终止符”,可以是 \x1b\(ESC 字符,后跟 \),也可以是 \x7(BEL 字符)
  • 空格只是说明性的。
  • <> 中的字符串是应由其他值替换的参数。

从终端 v1.18 开始,相关的受支持的 shell 集成序列为:

  • OSC 133 ; A ST(“FTCS_PROMPT”)- 提示开始。
  • OSC 133 ; B ST(“FTCS_COMMAND_START”)- 命令行开始(READ:提示结束)。
  • OSC 133 ; C ST(“FTCS_COMMAND_EXECUTED”)- 命令输出开始/命令行结束。
  • OSC 133 ; D ; <ExitCode> ST(“FTCS_COMMAND_FINISHED”)- 命令结束。 ExitCode 如果提供了 ExitCode,则终端会将 0 视为“成功”,将其他任何情况视为错误。 如果省略此项,则终端就会让标记保留默认颜色。

如何启用 shell 集成标记

支持这些功能需要 shell 和终端之间的协作。 需要在终端中启用设置才能使用这些新功能,还需要修改 shell 的提示符。

若要在终端中启用这些功能,需要将以下内容添加到设置中:

"profiles":
{
    "defaults":
    {
        // Marks in general
        "experimental.showMarksOnScrollbar": true,

        // Needed for both pwsh and CMD shell integration
        "experimental.autoMarkPrompts": true,

        // Add support for a right-click context menu
        // You can also just bind the `showContextMenu` action
        "experimental.rightClickContextMenu": true,
    },
}
"actions":
[
    { "keys": "ctrl+up",   "command": { "action": "scrollToMark", "direction": "previous" }, },
    { "keys": "ctrl+down", "command": { "action": "scrollToMark", "direction": "next" }, },

    // Add the ability to select a whole command (or its output)
    { "keys": "ctrl+shift+w", "command": { "action": "selectOutput", "direction": "prev" }, },
    { "keys": "ctrl+shift+s", "command": { "action": "selectOutput", "direction": "next" }, },

    { "keys": "ctrl+alt+shift+w", "command": { "action": "selectCommand", "direction": "prev" }, },
    { "keys": "ctrl+alt+shift+s", "command": { "action": "selectCommand", "direction": "next" }, },
]

在 shell 中启用这些标记的方式因 shell 而异。 下面是 CMD 和 PowerShell 的教程。

PowerShell (pwsh.exe)

如果你之前从未更改过 PowerShell 提示符,则应先查看 about_Prompts

我们需要编辑你的 prompt,以确保将有关 CWD 的信息告知终端,并使用适当的标记来标记提示。 PowerShell 还允许我们在 133;D 序列中包含上一个命令的错误代码,这将使终端能够自动根据命令是成功还是失败为标记着色。

将以下内容添加到 PowerShell 配置文件

$Global:__LastHistoryId = -1

function Global:__Terminal-Get-LastExitCode {
  if ($? -eq $True) {
    return 0
  }
  $LastHistoryEntry = $(Get-History -Count 1)
  $IsPowerShellError = $Error[0].InvocationInfo.HistoryId -eq $LastHistoryEntry.Id
  if ($IsPowerShellError) {
    return -1
  }
  return $LastExitCode
}

function prompt {

  # First, emit a mark for the _end_ of the previous command.

  $gle = $(__Terminal-Get-LastExitCode);
  $LastHistoryEntry = $(Get-History -Count 1)
  # Skip finishing the command if the first command has not yet started
  if ($Global:__LastHistoryId -ne -1) {
    if ($LastHistoryEntry.Id -eq $Global:__LastHistoryId) {
      # Don't provide a command line or exit code if there was no history entry (eg. ctrl+c, enter on no command)
      $out += "`e]133;D`a"
    } else {
      $out += "`e]133;D;$gle`a"
    }
  }


  $loc = $($executionContext.SessionState.Path.CurrentLocation);

  # Prompt started
  $out += "`e]133;A$([char]07)";

  # CWD
  $out += "`e]9;9;`"$loc`"$([char]07)";

  # (your prompt here)
  $out += "PWSH $loc$('>' * ($nestedPromptLevel + 1)) ";

  # Prompt ended, Command started
  $out += "`e]133;B$([char]07)";

  $Global:__LastHistoryId = $LastHistoryEntry.Id

  return $out
}

命令提示符

命令提示符从 PROMPT 环境变量获取提示。 CMD.exe 将 $e 读取为 ESC 字符。 遗憾的是,CMD.exe 没有办法在提示中获取上一个命令的返回代码,因此我们无法在 CMD 提示中提供成功/错误信息。

可通过运行以下命令更改当前 CMD.exe 实例的提示:

PROMPT $e]133;D$e\$e]133;A$e\$e]9;9;$P$e\$P$G$e]133;B$e\

也可从命令行为所有未来会话设置变量:

setx PROMPT $e]133;D$e\$e]133;A$e\$e]9;9;$P$e\$P$G$e]133;B$e\

这些示例假定当前 PROMPT 只是 $P$G。 你可以改为选择使用如下所示内容来包装当前提示:

PROMPT $e]133;D$e\$e]133;A$e\$e]9;9;$P$e\%PROMPT%$e]133;B$e\

注意:没有在这里看到你喜欢的 shell? 如果你已清楚,可随意,为你喜欢的 shell 提供一个解决方案!

shell 集成演示

在同一工作目录中打开新选项卡

Open new tabs in the same working directory

在滚动条中显示每个命令的标记

Show marks for each command in the scrollbar

在命令之间自动跳转

Automatically jump between commands

选择命令的整个输出

Select the entire output of a command

Select the command using the right-click context menu