lib/Status.ps1
|
function Write-Status { <# .SYNOPSIS Writes a colored status line to the Information stream using ANSI escapes. Falls back to plain text when $script:UseColor is $false (set in the entry-point script based on $Host.UI.SupportsVirtualTerminal). Standardised log levels (correspond to the bracket marker callers should put at the start of $Message): Info [INFO] informational; both work in progress and individual successful outcomes Warn [WARN] non-fatal anomaly Error [ERROR] unrecoverable failure Skip [SKIP] action deliberately not taken (config-driven no-op, missing prereq) Debug [DEBUG] low-signal troubleshooting output; always rendered (gray) so it's visible on failures without needing a re-run Ok (none) end-of-run / overall-success summary; green styling, no bracket marker. Per-step successes are Info, not Ok. Header (none) section divider, no bracket marker #> [CmdletBinding()] param( [Parameter(Mandatory)] [string] $Message, [ValidateSet('Info', 'Skip', 'Warn', 'Error', 'Header', 'Debug', 'Ok')] [string] $Level = 'Info' ) if (-not $script:UseColor) { Write-Information $Message return } $esc = [char]27 $reset = "$esc[0m" $color = switch ($Level) { 'Skip' { "$esc[90m" } # gray 'Warn' { "$esc[33m" } # yellow 'Error' { "$esc[31m" } # red 'Header' { "$esc[1;37m" } # bold white 'Debug' { "$esc[90m" } # gray 'Ok' { "$esc[32m" } # green - reserved for end-of-run summaries default { '' } # Info: default terminal color } Write-Information ('{0}{1}{2}' -f $color, $Message, $reset) } function Write-Header { <# .SYNOPSIS Writes a three-line boxed section banner via Write-Status -Level Header, shaped like: (blank) ╔════════════════════════════════════════════╗ ║ <Name> ║ ╚════════════════════════════════════════════╝ Box-drawing chars: U+2554/2557/255A/255D corners, U+2550 horizontal, U+2551 vertical. Width is the total visual width (default 60); the inside ($Width - 4) is padded with spaces so successive boxes line up regardless of name length. Names longer than that just spill past the right border - we keep the layout simple rather than wrapping or truncating. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string] $Name, [Parameter()] [int] $Width = 60 ) $h = [string]([char]0x2550) * ($Width - 2) $tl = [char]0x2554; $tr = [char]0x2557 $bl = [char]0x255A; $br = [char]0x255D $v = [char]0x2551 $top = "${tl}${h}${tr}" $middle = ('{0} {1} {2}' -f $v, $Name.PadRight([Math]::Max(0, $Width - 4)), $v) $bottom = "${bl}${h}${br}" Write-Status -Level Header -Message "`n$top`n$middle`n$bottom" } function Format-ToolOutput { <# .SYNOPSIS Pipeline-friendly output gate for external tools (winget, wsl, nvm, etc.). The surrounding [INSTALLING]/[MOVE]/[OK] status lines tell the user what's happening; the tool's own chatter is noise unless you're debugging. Default: silently consume the input. -Verbose ($VerbosePreference -ne 'SilentlyContinue'): stream each non-empty line indented two spaces under the parent status line. Lines matching any -SkipPattern regex are dropped even under -Verbose (useful for stripping legal boilerplate). Usage: wsl --install -d Debian --no-launch 2>&1 | Format-ToolOutput $LASTEXITCODE from the upstream external command remains visible to the caller after the pipeline returns. #> [CmdletBinding()] param( [Parameter(ValueFromPipeline)] $InputObject, [Parameter()] [string[]] $SkipPattern = @() ) begin { $verbose = $VerbosePreference -ne 'SilentlyContinue' } process { if (-not $verbose) { return } if ($null -eq $InputObject) { return } $s = [string]$InputObject if (-not $s) { return } foreach ($p in $SkipPattern) { if ($s -match $p) { return } } Write-Information " $s" } } |