Skip to content

Instantly share code, notes, and snippets.

@trackd
Last active July 10, 2024 17:11
Show Gist options
  • Save trackd/0f237de4829f1120a55564f8e8436a1d to your computer and use it in GitHub Desktop.
Save trackd/0f237de4829f1120a55564f8e8436a1d to your computer and use it in GitHub Desktop.
function Set-DemoPrompt {
<#
.SYNOPSIS
Creates a simple prompt with WT highlighting using a temporary module.
minor trickery with setting an alias for prompt so we can easily restore old prompt on module removal.
.NOTES
it adds terminal prompt markings for WT Preview.
see links below for more info
.LINK
https://learn.microsoft.com/en-us/windows/terminal/tutorials/shell-integration#powershell-pwshexe/
prompt markings
https://gist.github.com/mdgrs-mei/1599cb07ef5bc67125ebffba9c8f1e37
progress indicator
https://gist.github.com/mdgrs-mei/244496f094abc367d46a64d6c7f7dd7e
.notes
runs on powershell 5.1 and pwsh 7+
#>
if (Get-Module -Name DemoPrompt) {
Remove-Module DemoPrompt -Force
}
New-Module -Name DemoPrompt -ScriptBlock {
$script:LastCMD = $null
$script:LastHistoryId = -1
function Get-LastExitCode {
if ($? -eq $True) {
return 0
}
if ($error.count -gt 0) {
$LastHistoryEntry = Get-History -Count 1
$IsPowerShellError = $Error[0].InvocationInfo.HistoryId -eq $LastHistoryEntry.Id
}
if ($IsPowerShellError) {
return 1
}
return $LastExitCode
}
function New-PromptBlock {
[cmdletbinding()]
param(
[string[]]$Block,
[object]$Color,
[Switch]$Start,
[Switch]$End,
[int]$Padding = 1,
[String]$Separator = [char]57520,
[String]$StartIcon = [char]57526
)
$e = [char]27
$reset = "$e[0m"
$whitefg = "$e[38;2;255;255;255m"
$minispace = [char]0x2009
$redfg = "$e[31;1m"
$sb = [System.Text.StringBuilder]::new()
if ($Start) {
[void]$sb.append($color.Foreground).
Append($StartIcon).
Append($color.background)
}
else {
[void]$sb.append($color.background).
append($Separator)
}
[void]$sb.append($whitefg)
foreach ($entry in $Block) {
[void]$sb.append($entry)
if ($Padding -gt 0) {
[void]$sb.append(($minispace.ToString() * $Padding))
}
}
[void]$sb.append($reset).
Append($color.Foreground)
if (-Not $End) {
return $sb.ToString()
}
if ($lastCMD -ne 0) {
[void]$sb.append($redfg)
}
[void]$sb.append($Separator)
[void]$sb.append($reset)
return $sb.ToString()
}
function RGBtoColor ($R, $G, $B) {
return [PSCustomObject]@{
Foreground = "$([char]27)[38;2;{0};{1};{2}m" -f $R, $G, $B
Background = "$([char]27)[48;2;{0};{1};{2}m" -f $R, $G, $B
}
}
Set-PSReadLineKeyHandler -Key Enter -BriefDescription 'MarkEndofcommandforWT' -ScriptBlock {
try {
$e = [char]27
$startProgressIndicator = "$e]9;4;3;50$e\"
$EndOfCommand = "$e]133;C`a"
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
# progress indicator
Write-Host $startProgressIndicator -NoNewline
# command end, i think this needs to be after cause it marks start of output.
Write-Host $EndOfCommand -NoNewline
}
finally {}
}
function Invoke-DemoPrompt {
[cmdletbinding()]
param()
$script:LastCMD = Get-LastExitCode
$LastHistoryEntry = Get-History -Count 1
$e = [char]27
if ($script:LastHistoryId -ne -1) {
if ($LastHistoryEntry.Id -eq $script:LastHistoryId) {
$zero = "$e]133;D`a"
# no command input, so reset $LastCMD
$script:LastCMD = 0
}
else {
$zero = "$e]133;D;$LastCMD`a"
}
}
$script:LastHistoryId = $LastHistoryEntry.Id
$cwdir = $executionContext.SessionState.Path.CurrentLocation.Path
$ht = @{
errorIcon = [char]9888
HistoryIcon = [Char]::ConvertFromUtf32(984589)
pwshIcon = [char]59011
start = "$e]133;A`a"
cwd = "$e]9;9;`"{0}`"`a" -f $cwdir
endofprompt = "$e]133;B`a"
startProgressIndicator = "$e]9;4;3;50$e\"
stopProgressIndicator = "$e]9;4;0;50$e\"
}
if ($PSEdition -eq 'Core') {
$versionstring = $PSVersionTable.PSVersion
}
else {
$versionstring = $PSVersionTable.PSVersion.ToString(2)
}
$block1 = New-PromptBlock -Block $ht.pwshIcon, $versionstring -Color (RGBtoColor 58 58 58) -Start
$block2 = New-PromptBlock -Block $ht.HistoryIcon, $MyInvocation.HistoryId, $ht.errorIcon, $global:error.count -Color (RGBtoColor 88 88 88)
$block3 = New-PromptBlock -Block ($cwdir | Split-Path -Leaf) -Color (RGBtoColor 118 118 118) -End
return $zero + $ht.stopProgressIndicator + $ht.start + $ht.cwd + $block1 + $block2 + $block3 + $ht.endofprompt
}
$OnRemove = {
Remove-Item "alias:\prompt" -Force
Set-PSReadLineKeyHandler -Chord 'Enter' -Function AcceptLine
}
$ExecutionContext.SessionState.Module.OnRemove += $OnRemove
$registerEngineEventSplat = @{
SourceIdentifier = ([System.Management.Automation.PsEngineEvent]::Exiting)
Action = $OnRemove
}
Set-Alias -Name prompt -Value Invoke-DemoPrompt -Force -Option AllScope -Scope Global
Register-EngineEvent @registerEngineEventSplat
Export-ModuleMember -Alias prompt -Function Invoke-DemoPrompt
} | Import-Module -Global
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment