Search code examples
powershellterminalcommand-promptwindows-terminal

Prompt extracting in Microsoft PowerShell


There is a function: $function:Global:Prompt, which sends the current prompt to the output console and pipe its ansi sequence. However, it does not work in some cases.

Example:

$function:Global:Prompt

=

Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
_OLD_VIRTUAL_PROMPT

In my case, it prints to the terminal:

(.venv)  ~/projects/test-project/untitled :: git(main)             3.9.13 00:11:51

However, it does not pipe "(.venv)" to the output.

$function:Global:Prompt.Invoke() > output.txt

returns

[36m[0m[36m ~/projects/test-project/untitled [0m[93m:: [94mgit([93mmain[94m)[0m            [38;2;254;209;66m 3.9.13[0m[92m 00:13:59 [0m
[92m➜ [0m

But I expected that at the beginning it will contain an ANSI sequence corresponding to the green text "(.venv)".

How can we handle direct writing to the console and support legacy prompts?

I tried to capture output of Console:

function MyCaptureOutput {
  param (
    [scriptblock]$ScriptBlock
  )

  $outputBuffer = New-Object System.Text.StringBuilder

  $stringWriter = New-Object System.IO.StringWriter -ArgumentList $outputBuffer

  $originalOutStream = [Console]::Out
  [Console]::SetOut($stringWriter)

  $ScriptBlock.Invoke()

  [Console]::SetOut($originalOutStream)

  return $outputBuffer.ToString()
}

MyCaptureOutput -ScriptBlock {
  $function:Global:Prompt.Invoke()
}

But it returns:

[36m[0m[36m ~/projects/test-project/untitled [0m[93m:: [94mgit([93mmain[94m)[0m            [38;2;254;209;66m 3.9.13[0m[92m 00:22:32 [0m
[92m➜ [0m
(.venv) 

Solution

  • I expected that at the beginning it will contain an ANSI sequence corresponding to the green text "(.venv)"

    • >, the redirection operator, acts only on the success output stream, whose (implied) number is 1.

    • By contrast, Write-Host (despite its name) writes to the information output stream (whose number is 6), and is therefore not captured by > by default.


    While you can use *>&1 to redirect all (other) streams (*) into the success output stream (1), any (hypothetical) ANSI escape sequences emitted by Write-Host are still lost in the process.

    In PowerShell (Core) 7, even (temporarily) setting the $PSStyle preference variable's .OutputRendering property to 'Ansi' doesn't help as of PowerShell 7.4.1.
    GitHub issue #20171 discusses this behavior in the context of Out-String and CLI output.