共用方式為


Shell 整合

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

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

注意:從終端機 1.21 起,標記現在是穩定的功能。 在 1.21 之前,僅針對終端機的預覽組建啟用標記。 如果您使用 1.21 之前的終端機版本,則 showMarksOnScrollbar 此設定名為 experimental.showMarksOnScrollbar,且 autoMarkPrompts 已命名為 experimental.autoMarkPrompts

這是如何運作的?

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

針對下列序列:

  • 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":
    {
        // Enable marks on the scrollbar
        "showMarksOnScrollbar": true,

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

        // Add support for a right-click context menu
        // You can also just bind the `showContextMenu` action
        "experimental.rightClickContextMenu": true,
    },
}
"actions":
[
    // Scroll between prompts
    { "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)
    { "command": { "action": "selectOutput", "direction": "prev" }, },
    { "command": { "action": "selectOutput", "direction": "next" }, },

    { "command": { "action": "selectCommand", "direction": "prev" }, },
    { "command": { "action": "selectCommand", "direction": "next" }, },
]

在殼層中啟用這些標記的方式會因殼層而異。 以下是 CMD、PowerShell 和 Zsh 的教學課程。

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
}

哦, 我的 Posh 設定

使用 oh-my-posh? 您會想要稍微修改上述內容,以隱藏原始的提示,然後將它新增回殼層整合逸出序列的中間。

# initialize oh-my-posh at the top of your profile.ps1
oh-my-posh init pwsh --config "$env:POSH_THEMES_PATH\gruvbox.omp.json" | Invoke-Expression
# then stash away the prompt() that oh-my-posh sets
$Global:__OriginalPrompt = $function:Prompt

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 {
  $gle = $(__Terminal-Get-LastExitCode);
  $LastHistoryEntry = $(Get-History -Count 1)
  if ($Global:__LastHistoryId -ne -1) {
    if ($LastHistoryEntry.Id -eq $Global:__LastHistoryId) {
      $out += "`e]133;D`a"
    } else {
      $out += "`e]133;D;$gle`a"
    }
  }
  $loc = $($executionContext.SessionState.Path.CurrentLocation);
  $out += "`e]133;A$([char]07)";
  $out += "`e]9;9;`"$loc`"$([char]07)";
  
  $out += $Global:__OriginalPrompt.Invoke(); # <-- This line adds the original prompt back

  $out += "`e]133;B$([char]07)";
  $Global:__LastHistoryId = $LastHistoryEntry.Id
  return $out
}

命令提示字元

命令提示字元會從環境變數取得 PROMPT 其提示。 CMD.exe讀取 $eESC 字元。 可惜的是,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\

Bash

您可以使用或內建bash命令將source.下列指令碼來源至作用中 Shell,或將其新增至 (對於登入 Shell) 或 ${HOME}/.bashrc (對於非登入 Shell) 的${HOME}/.bash_profile結尾,以啟用與更大或等於bash-4.4版本的完整 Shell 整合 bash (內建變數最初實作的位置PS0)。 完整的 shell 集成意味著每個宣布的終端功能都按設計工作。

備註

應該指出的是,如果已經將 、 PS0PS1PS2變數指派給任何非預設值,可能會導致PROMPT_COMMAND不可預測的結果。 最好先使用「乾淨」的 shell 測試腳本,方法是執行 env --ignore-environment bash --noprofile --norc 和取得先前所指示的所描述的檔案。

# .bash_profile | .bashrc

function __set_ps1() {
    local PS1_TMP="${__PS1_BASE}"
    if [ ! -z "${__IS_WT}" ]; then
        local __FTCS_CMD_FINISHED='\e]133;D;'"${1}"'\e\\'
        PS1_TMP="\[${__FTCS_CMD_FINISHED}\]${__PS1_BASE}"
    fi
    printf '%s' "${PS1_TMP}"
}

function __prompt_command() {
    # Must be first in the list otherwise the exit status will be overwritten.
    local PS1_EXIT_STATUS=${?}
    PS1="$(__set_ps1 ${PS1_EXIT_STATUS})"
}

# ---------------------------------------------------------------------------
# PROMPT (PS0..PS2).

# The given variable might be linked to a function detecting whether `bash`
# actually runs under `Microsoft Terminal` otherwise unexpected garbage might
# be displayed on the user screen.
__IS_WT='true'

printf -v __BASH_V '%d' ${BASH_VERSINFO[*]:0:2}

if [ ${__BASH_V} -ge 44 ]; then
    __PS0_BASE=''
fi

# The following assignments reflect the default values.
__PS1_BASE='\s-\v\$ '
__PS2_BASE='> '

if [ ! -z "${__IS_WT}" ]; then
    __FTCS_PROMPT='\e]133;A\e\\'
    __FTCS_CMD_START='\e]133;B\e\\'
    if [ ${__BASH_V} -ge 44 ]; then
        __FTCS_CMD_EXECUTED='\e]133;C\e\\'
        __PS0_BASE="\[${__FTCS_CMD_EXECUTED}\]"
    fi
    __PS1_BASE="\[${__FTCS_PROMPT}\]${__PS1_BASE}\[${__FTCS_CMD_START}\]"
    # Required, otherwise the `PS2` prefix will split and corrupt a long
    # command.
    __PS2_BASE=''
fi

PROMPT_COMMAND=__prompt_command

if [ ${__BASH_V} -ge 44 ]; then
    PS0="${__PS0_BASE}"
fi
# `PS1` is set with the `__prompt_command` function call.
PS2="${__PS2_BASE}"

這會將所有各種 bash 提示變數 (PS0PS1PS2) 與必要的序列包裝在一起,以啟用完整的 shell 整合。

此外, ${HOME}/.inputrc 可能還需要調整以刪除「編輯模式通知」和「修改線條」標誌:

# .inputrc

set mark-modified-lines Off
set show-mode-in-prompt Off

如果一切都正確完成,它應該是什麼樣子:

$ env --ignore-environment bash --noprofile --norc
bash-5.2$ . /tmp/msft-terminal-bash.sh
bash-5.2$ echo "|${PS0}|"
|\[\e]133;C\e\\\]|
bash-5.2$ echo "|${PS1}|"
|\[\e]133;D;0\e\\\]\[\e]133;A\e\\\]\s-\v\$ \[\e]133;B\e\\\]|
bash-5.2$ echo "|${PS2}|"
||

注意:這裡找不到您最愛的殼層嗎? 如果您弄清楚,請放心 地為慣用的殼層提供解決方案!

殼層整合功能

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

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

顯示捲軸中每個命令的標記

顯示捲軸中每個命令的標記

在命令間自動跳躍

這會使用 scrollToMark 上述定義的動作。

在命令間自動跳躍

選取命令的整個輸出

在此gif中 selectOutput ,我們使用系結至的動作來 ctrl+g 選取命令的整個輸出。 選取命令的整個輸出

下列會 experimental.rightClickContextMenu 使用 設定,在終端機中啟用以滑鼠右鍵按下操作功能表。 啟用該和殼層整合之後,您可以以滑鼠右鍵按下命令,以選取整個命令或其輸出。

使用滑鼠右鍵操作功能選取命令

最近的命令建議

啟用殼層整合后,可以將建議UI設定為也顯示您最近的命令。

顯示其中最近命令的建議UI

您可以使用下列動作來開啟此選單:

{
    "command": { "action": "showSuggestions", "source": "recentCommands", "useCommandline": true },
},

(如需詳細資訊,請參閱 建議檔案

其他資源