ターミナル 1.15 プレビュー以降、Windows ターミナルは一部の "シェル統合" 機能を実験的にサポートするようになりました。 これらの機能により、コマンドラインが使いやすくなります。 以前のリリースでは、シェルが現在の作業ディレクトリをターミナルに伝えることができました。 今回、シェルがターミナル出力の一部を "プロンプト"、"コマンド"、または "出力" として意味的に記述できるように、より多くのシーケンスをサポートするようになりました。 また、シェルは、コマンドが成功したか失敗したかをターミナルに伝えることもできます。
これは、ターミナル v1.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") - コマンドラインの開始 (READ: プロンプトの終了)。 -
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
}
Oh My 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
次のスクリプトは、source
または組み込みの .
bash
コマンドを使用してアクティブなシェルにソースを指定するか、${HOME}/.bash_profile
の末尾 (ログイン シェルの場合) または${HOME}/.bashrc
(非ログイン シェルの場合) に追加して、bash
以上のバージョン (bash-4.4
組み込み変数がPS0
) とで完全なシェル統合を有効にすることができます。
完全なシェル統合とは、発表されたすべてのターミナル機能が設計どおりに動作することを意味します。
注
PROMPT_COMMAND
、PS0
、PS1
、またはPS2
変数が既定以外の値に既に割り当てられている場合は、予期しない結果につながる可能性があることに注意してください。 前に示したように、 env --ignore-environment bash --noprofile --norc
を実行し、記述されたファイルをソーシングすることで、まず "clean" シェルを使用してスクリプトをテストすることをお勧めします。
# .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
、 PS1
、および PS2
) を必要なシーケンスと共にラップして、完全なシェル統合を可能にします。
さらに、 ${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 },
},
(詳細については、提案に関するドキュメントを参照してください)
その他のリソース
Windows Terminal