# Tested in 3 environments
PS version: 5.1.18362.628
PSReadline version: 2.0.1
os: 10.0.18362.1 (WinBuild.160101.0800)
PS file version: 10.0.18362.1 (WinBuild.160101.0800)
HostName: ConsoleHost (Windows Terminal)
BufferWidth: 229
BufferHeight: 55
PS version: 7.0.1
PSReadline version: 2.0.0
os: 10.0.18362.1 (WinBuild.160101.0800)
PS file version: 7.0.1.0
HostName: ConsoleHost (Windows Terminal)
BufferWidth: 229
BufferHeight: 55
PS version: 7.0.0
PSReadline version: 2.0.0
os: Linux 4.4.0-18362-Microsoft #476-Microsoft Fri Nov 01 16:53:00 PST 2019 x86_64 x86_64 x86_64 GNU/Linux
PS file version: 7.0.0.0
HostName: ConsoleHost
BufferWidth: 229
BufferHeight: 55
None
Write a prompt
function that uses Write-Host
to construct the prompt. Place the prompt function in your PowerShell profile or in the -Command
option script block when launching PowerShell. Doing so will cause PSReadLine's syntax error prompt notification color to not trigger.
# C:\users\<username>\Documents\WindowsPowerShell\profile.ps1
# Prompt function that uses Write-Host to construct prompt
function prompt {
Write-Host 'myprompt' -NoNewLine
'> ' # Need to also return string so PowerShell doesn't auto add "PS>"
}
PS C:\> powershell.exe -NoLogo
PS C:\> function prompt { Write-Host 'myprompt' -NoNewLine; '> ' }
myprompt> } # syntax error prompt works
```powershell
PS C:> powershell.exe -NoExit -Command { function prompt { Write-Host 'myprompt' -NoNewLine; '> ' } }
myprompt> } # last char of prompt does not change color with syntax error
````
Add the following to your profile - I think it should fix it:
Set-PSReadLineOption -PromptText '> '
Before v2, PSReadLine relied on screen scraping to implement the error prompt coloring.
With the move to a more portable PSReadLine, screen scraping was no longer an option.
If you have a "pure" prompt, PSReadLine can infer what text needs to change to properly change the color, but if your prompt is not pure, e.g. calls Write-Host
, then you need to help PSReadLine out with this configuration option.
Note that if your prompt is extra fancy (like mine):
You can also specify the error coloring precisely by passing 2 strings instead of one - the first being the normal text, the second being the error text, so mine looks like:
$esc = [char]0x1b
$pc = [char]0xe0b0
$fg = "0"
$nbg = "8;2;95;158;160"
$ebg = "1"
Set-PSReadLineOption -PromptText (
"$esc[4${nbg};3${fg}mPS$esc[4${fg};3${nbg}m$pc",
"$esc[4${ebg};3${fg}mPS$esc[4${fg};3${ebg}m$pc"
)
Note how I use the background color instead of the foreground color.
@lzybkr Thanks for that tip, that generally solves my problem!
However I'm running into another related issue to the error prompt coloring.
If I add any of the "Smart" key handlers from the SamplePSReadLineProfile.ps1, when the prompt reverts from error back to "normal" the cursor becomes a ?
instead.
Here's a repro using the SmartBackspace key handler.
# C:\users\<username>\Documents\WindowsPowerShell\profile.ps1
Set-PSReadLineKeyHandler -Key Backspace `
-BriefDescription SmartBackspace `
-LongDescription "Delete previous character or matching quotes/parens/braces" `
-ScriptBlock {
param($key, $arg)
$line = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
if ($cursor -gt 0)
{
$toMatch = $null
if ($cursor -lt $line.Length)
{
switch ($line[$cursor])
{
<#case#> '"' { $toMatch = '"'; break }
<#case#> "'" { $toMatch = "'"; break }
<#case#> ')' { $toMatch = '('; break }
<#case#> ']' { $toMatch = '['; break }
<#case#> '}' { $toMatch = '{'; break }
}
}
if ($toMatch -ne $null -and $line[$cursor-1] -eq $toMatch)
{
[Microsoft.PowerShell.PSConsoleReadLine]::Delete($cursor - 1, 2)
}
else
{
[Microsoft.PowerShell.PSConsoleReadLine]::BackwardDeleteChar($key, $arg)
}
}
}
function prompt {
Write-Host "test$([char]0x276F)" -NoNewLine
' '
}
Set-PSReadLineOption -PromptText "$([char]0x276f) "
test❯ {enter}
test? if{backspace} # turns prompt into "?"
@DecoyJoe - yeah, I see the same thing with the ?
but hadn't investigated. It looks like you need to set the output encoding to UTF8:
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
I thought PSReadLine was doing that for you, but maybe that changed. @daxian-dbw?
I thought PSReadLine was doing that for you, but maybe that changed. @daxian-dbw?
No, how UTF8
is set is not changed in PSRL.
This is because PSRL set the output encoding to the initial encoding before evaluating a script block key binding.
[PSConsoleReadLine]::Delete
or [PSConsoleReadLine]::BackwardDeleteChar
will trigger the rendering, which will run in the initial console encoding, and hence you see the question mark.
I feel resetting console encoding is not really necessary for invoking a keybinding scriptblock, given that those script blocks usually calls back to PSReadLine static methods that triggers rendering.
The output encoding needs to be UTF8 when PSReadLine calls Console.Write
: https://github.com/PowerShell/PSReadLine/blob/65d332e277c88cd7f7050786956afae9770555d4/PSReadLine/Render.cs#L441-L453
I feel resetting console encoding is not really necessary for invoking a keybinding scriptblock, given that those script blocks usually calls back to PSReadLine static methods that triggers rendering.
@lzybkr what's your thoughts on this?
Calling external commands is definitely a scenario and while rendering may be likely, it's not guaranteed. Imagine a minimalist prompt that doesn't show the current directory, but adding a key binding to something like https://github.com/ajeetdsouza/zoxide to change directories.
while rendering may be likely, it's not guaranteed.
That makes sense.
If we want PSReadLine reliably calls Console.Write/WriteLine
in UTF8
console encoding, then I guess the VirtualTerminal
and LegacyWin32Console
has to set and reset console encoding in the Write
and WriteLine
implementation.
Most helpful comment
Add the following to your profile - I think it should fix it:
Before v2, PSReadLine relied on screen scraping to implement the error prompt coloring.
With the move to a more portable PSReadLine, screen scraping was no longer an option.
If you have a "pure" prompt, PSReadLine can infer what text needs to change to properly change the color, but if your prompt is not pure, e.g. calls
Write-Host
, then you need to help PSReadLine out with this configuration option.Note that if your prompt is extra fancy (like mine):
You can also specify the error coloring precisely by passing 2 strings instead of one - the first being the normal text, the second being the error text, so mine looks like:
Note how I use the background color instead of the foreground color.