Public/Set-FolderColor.ps1
|
function Set-FolderColor { <# .SYNOPSIS Associates a colour with a folder by writing a .terminalcolors.json file into it. .DESCRIPTION The colour applies to the folder and, by default, to all of its subfolders. The file is deliberately readable and source-controllable: commit it so the whole team shares the same project colour. .PARAMETER Color Colour as a hex code (#215732), a known colour name (Teal, SteelBlue...) or [auto] to derive a stable colour from the project name. .PARAMETER Path Folder to colour. Defaults to the current folder. .PARAMETER Name Label shown in the tab. Defaults to the folder name. .PARAMETER Icon Symbol shown before the label. Defaults to a coloured square derived from the colour. .PARAMETER Tint Tint strength specific to this project, from 0 to 1. Overrides the global setting. .PARAMETER Branches Git branch -> colour map. Wildcards are accepted. Example: @{ 'main' = '#215732'; 'release/*' = '#B71C1C' } .PARAMETER NoSubfolders Limits the colour to the given folder only. .PARAMETER Force Overwrites an existing configuration file. .EXAMPLE Set-FolderColor '#215732' .EXAMPLE Set-FolderColor auto -Path C:\Repos\pastel .EXAMPLE Set-FolderColor Teal -Name 'Superviseur' -Branches @{ 'main' = 'Teal'; 'hotfix/*' = 'OrangeRed' } #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] [OutputType([pscustomobject])] param( [Parameter(Mandatory, Position = 0)] [string] $Color, [Parameter(Position = 1)] [string] $Path = '.', [string] $Name, [string] $Icon, [ValidateRange(0.0, 1.0)] [double] $Tint = -1, [hashtable] $Branches, [switch] $NoSubfolders, [switch] $Force, [switch] $PassThru ) try { $directory = (Resolve-Path -LiteralPath $Path -ErrorAction Stop).ProviderPath } catch { throw "TerminalColors: folder not found [$Path]." } if (-not [System.IO.Directory]::Exists($directory)) { throw "TerminalColors: [$directory] is not a folder." } if ($Color -ne 'auto' -and -not (ConvertFrom-TcColor -Value $Color)) { throw "TerminalColors: unrecognised colour [$Color]. Use a hex code (#RRGGBB), a known colour name, or [auto]." } if ($Branches) { foreach ($key in $Branches.Keys) { $value = [string]$Branches[$key] if ($value -ne 'auto' -and -not (ConvertFrom-TcColor -Value $value)) { throw "TerminalColors: unrecognised colour [$value] for branch [$key]." } } } $target = Join-Path $directory '.terminalcolors.json' if ([System.IO.File]::Exists($target) -and -not $Force) { throw "TerminalColors: [$target] already exists. Use -Force to overwrite it." } $config = [ordered]@{ color = $Color } if ($Name) { $config.name = $Name } else { $config.name = Split-Path $directory -Leaf } if ($Icon) { $config.icon = $Icon } if ($Tint -ge 0) { $config.tint = $Tint } if ($Branches) { $ordered = [ordered]@{} foreach ($key in ($Branches.Keys | Sort-Object)) { $ordered[$key] = [string]$Branches[$key] } $config.branches = $ordered } if ($NoSubfolders) { $config.applyToSubfolders = $false } $json = ([pscustomobject]$config | ConvertTo-Json -Depth 10) if ($PSCmdlet.ShouldProcess($target, 'Write the colour configuration')) { # UTF-8 without BOM: readable by every tool, clean diff in Git. $encoding = New-Object System.Text.UTF8Encoding($false) [System.IO.File]::WriteAllText($target, $json + [Environment]::NewLine, $encoding) Clear-TcResolveCache $script:TcLastPath = $null $script:TcLastKey = $null $current = Get-TcCurrentPath if ($current -and ($current -eq $directory -or $current.StartsWith($directory + [System.IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase))) { Update-TerminalColor -Force } } if ($PassThru) { return Get-TerminalColor -Path $directory } } function Remove-FolderColor { <# .SYNOPSIS Removes a folder's .terminalcolors.json file. .PARAMETER Path Folder concerned. Defaults to the current folder. .EXAMPLE Remove-FolderColor #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] param( [Parameter(Position = 0)] [string] $Path = '.' ) try { $directory = (Resolve-Path -LiteralPath $Path -ErrorAction Stop).ProviderPath } catch { throw "TerminalColors: folder not found [$Path]." } $removed = $false foreach ($name in @('.terminalcolors.json', 'terminalcolors.json', '.terminalcolors')) { $candidate = Join-Path $directory $name if ([System.IO.File]::Exists($candidate)) { if ($PSCmdlet.ShouldProcess($candidate, 'Remove')) { Remove-Item -LiteralPath $candidate -Force $removed = $true } } } if (-not $removed) { Write-Warning "TerminalColors: no colour configuration in [$directory]." return } Clear-TerminalColorCache Update-TerminalColor -Force } |