從終端機 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讀取 $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\
Bash
您可以使用或內建bash命令將source.下列指令碼來源至作用中 Shell,或將其新增至 (對於登入 Shell) 或 ${HOME}/.bashrc (對於非登入 Shell) 的${HOME}/.bash_profile結尾,以啟用與更大或等於bash-4.4版本的完整 Shell 整合 bash (內建變數最初實作的位置PS0)。
完整的 shell 集成意味著每個宣布的終端功能都按設計工作。
備註
應該指出的是,如果已經將 、 PS0或 PS1PS2變數指派給任何非預設值,可能會導致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 提示變數 (PS0 和 PS1PS2) 與必要的序列包裝在一起,以啟用完整的 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設定為也顯示您最近的命令。
您可以使用下列動作來開啟此選單:
{
"command": { "action": "showSuggestions", "source": "recentCommands", "useCommandline": true },
},
(如需詳細資訊,請參閱 建議檔案 )