Public/Update-TerminalColor.ps1
|
function Update-TerminalColor { <# .SYNOPSIS Applies the colour matching the current directory. .DESCRIPTION Called automatically every time the prompt is drawn while Enable-TerminalColors is active. Does nothing if the directory has not changed since the last call, so that the per-prompt cost stays negligible. .PARAMETER Path Directory to evaluate. Defaults to the current directory. .PARAMETER Force Reapplies the colour even when nothing has changed. .PARAMETER PassThru Returns the object describing the resolved colour. .EXAMPLE Update-TerminalColor -Force Reapplies the colour, for instance after editing .terminalcolors.json. #> [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Position = 0)] [string] $Path, [switch] $Force, [switch] $PassThru ) $options = Get-TcOptions if ($Path) { try { $target = (Resolve-Path -LiteralPath $Path -ErrorAction Stop).ProviderPath } catch { $target = $Path } } else { $target = Get-TcCurrentPath } if (-not $target) { return } $pathChanged = ($target -ne $script:TcLastPath) # Directory unchanged: read nothing. The colour is only re-emitted when the # user asked for AlwaysReapply (useful if a program resets the terminal # background); otherwise return immediately. if (-not $pathChanged -and -not $Force) { if ($options.AlwaysReapply) { if ($script:TcLastInfo) { Set-TcAppearance -Info $script:TcLastInfo -Path $target -Options $options } else { Reset-TcAppearance -Options $options } } if ($PassThru) { return $script:TcLastInfo } return } if ($Force) { Clear-TcResolveCache } $info = Resolve-TcColor -Path $target -AutoGitColors ([bool]$options.AutoGitColors) $key = 'none' if ($info) { $key = '{0}|{1}' -f $info.Color, $info.Name } if ($key -ne $script:TcLastKey -or $Force) { if ($info) { Set-TcAppearance -Info $info -Path $target -Options $options } else { Reset-TcAppearance -Options $options } $script:TcLastKey = $key } $script:TcLastPath = $target $script:TcLastInfo = $info if ($PassThru) { return $info } } function Get-TcEffectiveBackground { <# .SYNOPSIS Background colour to send to the terminal for a given project. .DESCRIPTION In pure-colour mode this is the project colour as-is: the opaque backdrop keeps the pane readable, and any dilution would be counter-productive - including one a project asked for through its [tint] key. Otherwise the colour is blended into the reference background using the requested tint, the project's taking priority over the session's. .PARAMETER BaseBackground Reference background for the blend. Derived from the Windows Terminal settings when not supplied. Pure-colour mode never reads it, which avoids a settings.json read. #> [CmdletBinding()] param( [pscustomobject] $Info, [hashtable] $Options, [hashtable] $BaseBackground ) if ($Options.PureColor) { return $Info.Rgb } $tint = $Options.Tint if ($null -ne $Info.Tint) { $tint = [double]$Info.Tint } if ($null -eq $BaseBackground) { $BaseBackground = Get-TcBaseBackground } return (Get-TcBlendedColor -Base $BaseBackground -Color $Info.Rgb -Amount $tint) } function Set-TcAppearance { [CmdletBinding()] param( [pscustomobject] $Info, [string] $Path, [hashtable] $Options ) # Icon: the one from the configuration, otherwise the nearest coloured square. $icon = [string]$Info.Icon if ([string]::IsNullOrEmpty($icon) -and $Options.Icons) { $icon = Get-TcColorEmoji -Rgb $Info.Rgb } $effective = $Info.PSObject.Copy() $effective.Icon = $icon if (Test-TcVtSupported) { Set-TcTerminalBackground -Rgb (Get-TcEffectiveBackground -Info $Info -Options $Options) } if ($Options.SetTitle) { if ($null -eq $script:TcOriginalTitle) { $script:TcOriginalTitle = Get-TcWindowTitle } Set-TcWindowTitle -Title (Format-TcTitle -Format $Options.TitleFormat -Info $effective -Path $Path) } # The window border itself comes from the theme (window.frame), not from here. # This DWM call is a fallback for hosts that ignore the theme, plus the system # title bar when -CaptionColor is on. The border belongs to the window, so a # tab that is not the visible one must not repaint it, otherwise the tabs of a # freshly opened window fight over it. if ($Options.WindowBorder -and (Test-TcActiveTab) -ne $false) { if (Set-TcWindowBorderColor -Rgb $Info.Rgb -IncludeCaption:([bool]$Options.CaptionColor)) { $script:TcBorderApplied = $true } } } function Reset-TcAppearance { [CmdletBinding()] param( [hashtable] $Options, # Set for an explicit Reset-TerminalColor / Disable-TerminalColors: the # user asked for it, so restore the border whatever this session did. [switch] $Force ) if (Test-TcVtSupported) { Reset-TcTerminalBackground -Explicit:([bool]$Options.ExplicitReset) } if ($Options.SetTitle -and $script:TcOriginalTitle) { Set-TcWindowTitle -Title $script:TcOriginalTitle } # Two guards, because erasing another tab's colour is the worst outcome here. # A tab only resets the border if it is the visible one AND it is the one that # coloured it in the first place - a tab that never coloured anything has # nothing to restore, and would only be clobbering a sibling. if ($Options.WindowBorder -and ($Force -or $script:TcBorderApplied) -and (Test-TcActiveTab) -ne $false) { [void](Reset-TcWindowBorderColor -IncludeCaption:([bool]$Options.CaptionColor)) $script:TcBorderApplied = $false } } function Reset-TerminalColor { <# .SYNOPSIS Restores the terminal's default appearance (background, title, border). .PARAMETER Explicit Rewrites the background colour derived from the Windows Terminal settings instead of using the OSC 111 reset sequence. Useful if your version of Windows Terminal does not honour OSC 111. .EXAMPLE Reset-TerminalColor #> [CmdletBinding()] param([switch] $Explicit) $options = (Get-TcOptions).Clone() if ($Explicit) { $options.ExplicitReset = $true } Reset-TcAppearance -Options $options -Force $script:TcLastKey = 'none' $script:TcLastPath = $null } |