教學課程:在 Windows 終端機啟用殼層整合

從終端機 1.15 預覽版起,Windows 終端機已開始實驗性地支援一些「殼層整合」功能。 這些功能可讓命令列更易於使用。 在先前的版本,我們會啟用殼層來告訴終端機目前的工作目錄是什麼。 現在,我們新增了更多序列的支援,允許殼層以語意方式將終端機輸出的部分描述為「提示」、「命令」或「輸出」。 殼層也可以告訴終端機命令是成功或失敗。

這是我們在終端機 1.18 版推出之部份殼層整合功能的指南。 我們計畫未來在這些功能上建置更多功能,因此我們想要取得一些其他關於各位如何使用這些功能的意見反應。

注意:需要注意的是,「標記」仍是實驗性功能,而且只會針對終端機的預覽組建啟用。 這些功能的設定在未來版本可能會變更。

這是如何運作的?

殼層整合的運作方式是讓殼層 (或任何命令列應用程式) 將特殊的「逸出序列」寫入終端機。 這些逸出序列不會列印到終端機,而是會提供終端機可用來深入了解應用程式內部狀況的中繼資料。 經由將這些序列貼入殼層的提示,您可以讓殼層持續提供只有殼層知道的終端機資訊。

針對下列序列:

  • OSC 是字串 "\x1b]" - 亦即逸出字元,後面接續的是 ]
  • ST 是「字串結束字元」,可以是 \x1b\ (ESC 字元,後面接續的是 \) 或 \x7 (BEL 字元)
  • 空白字元僅供說明之用。
  • <> 中的字串是應由一些其他值取代的參數。

從終端機 v1.18 起,相關的受支援殼層整合序列如下:

  • OSC 133 ; A ST ("FTCS_PROMPT") - 提示的開頭。
  • OSC 133 ; B ST ("FTCS_COMMAND_START") - 命令列的開頭 (讀取:提示的結尾)。
  • OSC 133 ; C ST ("FTCS_COMMAND_EXECUTED") - 命令輸出的開頭 / 命令列的結尾。
  • OSC 133 ; D ; <ExitCode> ST ("FTCS_COMMAND_FINISHED") - 命令的結尾。 ExitCode 如果提供ExitCode,終端機會將 0 視為「成功」,並將任何其他項目視為錯誤。 若省略,終端機僅會保留預設色彩的標記。

如何啟用殼層整合標記

支援這些功能需要仰賴殼層與終端機之間的合作。 您必須啟用終端機中的設定,以及修改殼層的提示,才能使用這些新功能。

若要在終端機中啟用這些功能,建議您將下列內容新增至您的設定:

"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" }, },
]

在殼層中啟用這些標記的方式會因殼層而異。 以下是 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\

注意:這裡找不到您最愛的殼層嗎? 如果您已經找到解答,歡迎為慣用的殼層貢獻解決方案!

殼層整合示範

在相同的工作目錄中開啟新的索引標籤

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