Public/ColorNames.ps1

function Register-ColorName {
    <#
    .SYNOPSIS
    Adds a color name to the color table, for every command of the module.
 
    .DESCRIPTION
    Register-ColorName names a color, so -Color, -BackGroundColor, -UnderlineColor, the
    gradients, markup tags and -Highlight styles take the name as they take the built-in names.
    The name keeps the color in every color mode: the 256-color and 16-color codes and the console
    color nearest it.
 
    A name holds letters, digits, '-' and '_', starting with a letter. It cannot be None, on, or a
    style name markup reads, such as bold. A name in use, built-in or registered, is replaced only
    with -Force; Unregister-ColorName brings a replaced built-in name back.
 
    The names last for the session. Export-ColorProfile saves them with the style profiles, and
    Import-ColorProfile registers them again.
 
    .PARAMETER Name
    The name for the color.
 
    .PARAMETER Color
    The color: a hex code ('#FF8000', '#F80'), 'rgb(255, 128, 0)', 'hsl(30, 100%, 50%)', an RGB
    array @(255, 128, 0), or a name already in the color table.
 
    .PARAMETER Force
    Replaces a name that is in use.
 
    .EXAMPLE
    Register-ColorName -Name Brand -Color '#FF6B35'
    Write-ColorEX -Text 'Acme' -Color Brand -Bold
 
    Names a brand color and writes with it.
 
    .EXAMPLE
    Register-ColorName Orange 'hsl(30, 100%, 50%)' -Force
 
    Replaces the built-in Orange for the session.
 
    .INPUTS
    None
 
    .OUTPUTS
    None
 
    .NOTES
    Author: Mark Newton
    License: MIT
    Requires: PowerShell 5.1 or later
 
    .LINK
    https://github.com/MarkusMcNugen/PSWriteColorEX
 
    .LINK
    Unregister-ColorName
 
    .LINK
    Show-ColorTable
    #>

    [CmdletBinding()]
    [Alias('Register-ColourName')]
    param(
        [Parameter(Mandatory, Position = 0)]
        [string] $Name,

        [Parameter(Mandatory, Position = 1)]
        [object] $Color,

        [switch] $Force
    )

    if ($Name -notmatch '^[A-Za-z][A-Za-z0-9_-]*$' -or $Name -eq 'None' -or $Name -eq 'on' -or
        $script:MarkupStyleNames.ContainsKey($Name.ToLowerInvariant())) {
        $PSCmdlet.WriteError([System.Management.Automation.ErrorRecord]::new(
            [System.ArgumentException]::new("'$Name' cannot be a color name. A name holds letters, digits, '-' and '_', starts with a letter, and is not None, on or a style name."),
            'InvalidColorName', [System.Management.Automation.ErrorCategory]::InvalidArgument, $Name))
        return
    }

    $table = Get-ColorTableWithRGB
    if ($table.ContainsKey($Name) -and -not $Force) {
        $PSCmdlet.WriteError([System.Management.Automation.ErrorRecord]::new(
            [System.ArgumentException]::new("The color name '$Name' is in use. Use -Force to replace it."),
            'ColorNameInUse', [System.Management.Automation.ErrorCategory]::ResourceExists, $Name))
        return
    }

    $rgb = Get-ColorRegisterRgb -Value $Color -Table $table
    if ($null -eq $rgb) {
        $shown = if ($Color -is [array]) { "@($($Color -join ', '))" } else { "$Color" }
        $PSCmdlet.WriteError([System.Management.Automation.ErrorRecord]::new(
            [System.ArgumentException]::new("'$shown' is not a color. A color is a hex code, rgb(), hsl(), an RGB array of three numbers 0-255, or a name in the color table."),
            'InvalidColor', [System.Management.Automation.ErrorCategory]::InvalidArgument, $Color))
        return
    }

    $ansi4 = Convert-RGBToANSI4 -RGB $rgb
    $script:CustomColors[$Name] = @((ConvertANSI4ToNativeColor -Code $ansi4), $ansi4, ($ansi4 + 10), (Convert-RGBToANSI8 -RGB $rgb), $rgb)
    $script:CachedColorTable = $null
}

function Unregister-ColorName {
    <#
    .SYNOPSIS
    Removes color names Register-ColorName added.
 
    .DESCRIPTION
    A built-in name that Register-ColorName replaced takes its built-in color again. A name that
    was not registered gives an error.
 
    .PARAMETER Name
    The names to remove.
 
    .EXAMPLE
    Unregister-ColorName -Name Brand
 
    .INPUTS
    System.String[]
    Names piped in are removed.
 
    .OUTPUTS
    None
 
    .NOTES
    Author: Mark Newton
    License: MIT
    Requires: PowerShell 5.1 or later
 
    .LINK
    https://github.com/MarkusMcNugen/PSWriteColorEX
 
    .LINK
    Register-ColorName
    #>

    [CmdletBinding()]
    [Alias('Unregister-ColourName')]
    param(
        [Parameter(Mandatory, Position = 0, ValueFromPipeline = $true)]
        [string[]] $Name
    )

    process {
        foreach ($item in $Name) {
            if (-not $script:CustomColors.Contains($item)) {
                $PSCmdlet.WriteError([System.Management.Automation.ErrorRecord]::new(
                    [System.ArgumentException]::new("No color name '$item' was registered."),
                    'ColorNameNotRegistered', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $item))
                continue
            }
            $script:CustomColors.Remove($item)
            $script:CachedColorTable = $null
        }
    }
}

function Show-ColorTable {
    <#
    .SYNOPSIS
    Writes the color names with a sample of each in every color mode, or a view of the text
    styles, the 256 colors or the style profiles.
 
    .DESCRIPTION
    Show-ColorTable writes one line for each name in the color table, registered names among
    them: the name, a sample of the color in TrueColor, in 256 colors, in 16 colors and as a
    console color, then its hex code, its 256-color number and its console color. The names go by
    family, each family's Dark, normal and Light variants together.
 
    A terminal without a mode shows the nearest color it has in that mode's column.
 
    -Styles, -Palette and -Profiles write a view instead of the names:
 
    - -Styles: each text style, with a sample in it, the Write-ColorEX parameter that gives it and
      the markup tags that give it.
    - -Palette: the 256-color chart, each number written on its own color in black or white,
      whichever has the higher contrast: the terminal's 16 colors, the 6x6x6 color cube as six
      blocks of 6x6, and the 24 grays. On the 16 colors, which the terminal's scheme sets, the
      numbers 0-6 and 8 are white and the others black.
    - -Profiles: each style profile, with a sample in its colors and styles, then its settings in
      words, the default style marked. Layout settings such as AutoPad are listed, not applied. A
      color Write-ColorEX does not take, such as 5.5, gives Write-ColorEX's error in place of the
      sample.
 
    .PARAMETER Name
    The names to show, or with -Profiles the profiles. Wildcards are allowed.
 
    Default: every name
 
    .PARAMETER Background
    Shows each sample as a background behind spaces rather than as blocks of text color.
 
    .PARAMETER Styles
    Writes the text styles instead of the color names.
 
    .PARAMETER Palette
    Writes the 256-color chart instead of the color names.
 
    .PARAMETER Profiles
    Writes the style profiles instead of the color names.
 
    .EXAMPLE
    Show-ColorTable
 
    .EXAMPLE
    Show-ColorTable *Blue*, *Cyan* -Background
 
    Shows the blue and cyan families as backgrounds.
 
    .EXAMPLE
    Show-ColorTable -Styles
 
    .EXAMPLE
    Show-ColorTable -Palette
 
    .EXAMPLE
    Import-ColorProfile -Theme Nord
    Show-ColorTable -Profiles
 
    Shows the profiles as the Nord theme set them.
 
    .INPUTS
    None
 
    .OUTPUTS
    None
    Show-ColorTable writes to the host.
 
    .NOTES
    Author: Mark Newton
    License: MIT
    Requires: PowerShell 5.1 or later
 
    .LINK
    https://github.com/MarkusMcNugen/PSWriteColorEX
 
    .LINK
    Get-ColorTableWithRGB
 
    .LINK
    Register-ColorName
    #>

    [CmdletBinding(DefaultParameterSetName = 'Names')]
    [Alias('Show-ColourTable')]
    param(
        [Parameter(Position = 0, ParameterSetName = 'Names')]
        [Parameter(Position = 0, ParameterSetName = 'Profiles')]
        [SupportsWildcards()]
        [string[]] $Name = '*',

        [Parameter(ParameterSetName = 'Names')]
        [switch] $Background,

        [Parameter(Mandatory, ParameterSetName = 'Styles')]
        [switch] $Styles,

        [Parameter(Mandatory, ParameterSetName = 'Palette')]
        [switch] $Palette,

        [Parameter(Mandatory, ParameterSetName = 'Profiles')]
        [switch] $Profiles
    )

    if ($Styles) {
        # Each style, the Write-ColorEX parameters that give it, and the parameter as written
        $rows = @(
            , @('Bold', @{ Bold = $true }, '-Bold')
            , @('Faint', @{ Faint = $true }, '-Faint')
            , @('Italic', @{ Italic = $true }, '-Italic')
            , @('Underline', @{ Underline = $true }, '-Underline')
            , @('DoubleUnderline', @{ DoubleUnderline = $true }, '-DoubleUnderline')
            , @('Curly', @{ UnderlineStyle = 'Curly' }, '-UnderlineStyle Curly')
            , @('Dotted', @{ UnderlineStyle = 'Dotted' }, '-UnderlineStyle Dotted')
            , @('Dashed', @{ UnderlineStyle = 'Dashed' }, '-UnderlineStyle Dashed')
            , @('Blink', @{ Blink = $true }, '-Blink')
            , @('Reverse', @{ Reverse = $true }, '-Reverse')
            , @('CrossedOut', @{ CrossedOut = $true }, '-CrossedOut')
            , @('Overline', @{ Overline = $true }, '-Overline')
        )
        $markupColumn = 17 + 13 + 24
        Write-ColorEX -Text ('Style'.PadRight(17) + 'Sample'.PadRight(13) + 'Parameter'.PadRight(24) + 'Markup') -Bold
        foreach ($row in $rows) {
            $styleName = $row[0]
            $sample = $row[1]
            # The markup tags for the style: its own name, then the others in ordinal order
            $own = $styleName.ToLowerInvariant()
            $others = [string[]]@($script:MarkupStyleNames.Keys | Where-Object { $script:MarkupStyleNames[$_] -eq $styleName -and $_ -ne $own })
            [Array]::Sort($others, [System.StringComparer]::Ordinal)
            # The tags wrap onto lines of their own under the markup column to stay within 80 columns
            $tagLines = [System.Collections.Generic.List[string]]::new()
            $tagLine = ''
            foreach ($tag in @($own) + $others) {
                $word = "[$tag]"
                if ($tagLine.Length -gt 0 -and $markupColumn + $tagLine.Length + 1 + $word.Length -gt 80) {
                    $tagLines.Add($tagLine)
                    $tagLine = $word
                } elseif ($tagLine.Length -gt 0) {
                    $tagLine += " $word"
                } else {
                    $tagLine = $word
                }
            }
            $tagLines.Add($tagLine)
            Write-ColorEX -Text $styleName.PadRight(17) -NoNewLine
            Write-ColorEX -Text 'Sample text' @sample -NoNewLine
            Write-ColorEX -Text (' ' + $row[2].PadRight(24) + $tagLines[0])
            for ($i = 1; $i -lt $tagLines.Count; $i++) {
                Write-ColorEX -Text ((' ' * $markupColumn) + $tagLines[$i])
            }
        }
        return
    }

    if ($Palette) {
        # The rows of the chart, each a list of codes and gaps, a part's last row followed by a
        # blank line: the 16 colors, the cube's two bands of three 6x6 blocks, the 24 grays
        $rows = [System.Collections.Generic.List[object]]::new()
        $rows.Add(@{ Cells = @(0..7); Blank = $false })
        $rows.Add(@{ Cells = @(8..15); Blank = $true })
        foreach ($band in 0, 1) {
            for ($r = 0; $r -lt 6; $r++) {
                $cells = [System.Collections.Generic.List[object]]::new()
                for ($block = 0; $block -lt 3; $block++) {
                    if ($block -gt 0) {
                        $cells.Add(' ')
                    }
                    $start = 16 + ($band * 3 + $block) * 36 + $r * 6
                    for ($c = 0; $c -lt 6; $c++) {
                        $cells.Add($start + $c)
                    }
                }
                $rows.Add(@{ Cells = $cells.ToArray(); Blank = ($r -eq 5) })
            }
        }
        $rows.Add(@{ Cells = @(232..243); Blank = $false })
        $rows.Add(@{ Cells = @(244..255); Blank = $false })
        foreach ($row in $rows) {
            $cellTexts = [System.Collections.Generic.List[string]]::new()
            $cellColors = [System.Collections.Generic.List[object]]::new()
            $cellBackgrounds = [System.Collections.Generic.List[object]]::new()
            foreach ($cell in $row.Cells) {
                if ($cell -is [string]) {
                    $cellTexts.Add($cell)
                    $cellColors.Add($null)
                    $cellBackgrounds.Add($null)
                    continue
                }
                $cellTexts.Add(('{0,3} ' -f $cell))
                $cellColors.Add((Get-PaletteTextColor -Code $cell))
                $cellBackgrounds.Add([int]$cell)
            }
            $lines = 0
            if ($row.Blank) {
                $lines = 1
            }
            Write-ColorEX -Text $cellTexts.ToArray() -Color $cellColors.ToArray() -BackGroundColor $cellBackgrounds.ToArray() -ANSI8 -Silent -LinesAfter $lines
        }
        return
    }

    if ($Profiles) {
        # The profiles named, in the order of their names in upper case, ordinal
        $profileNames = [string[]]@([PSColorStyle]::Profiles.Keys | Where-Object {
            $key = $_
            @($Name | Where-Object { $key -like $_ }).Count -gt 0
        })
        if ($profileNames.Count -eq 0) {
            return
        }
        $keys = [string[]]@(foreach ($profileName in $profileNames) { $profileName.ToUpperInvariant() })
        [Array]::Sort($keys, $profileNames, [System.StringComparer]::Ordinal)
        $width = 7
        foreach ($profileName in $profileNames) {
            $width = [Math]::Max($width, $profileName.Length)
        }
        Write-ColorEX -Text ('Profile'.PadRight($width) + ' ' + 'Sample'.PadRight(13) + 'Settings') -Bold
        foreach ($profileName in $profileNames) {
            $style = [PSColorStyle]::Profiles[$profileName]
            # The sample takes the profile's colors and styles, not its layout
            $sample = $style.ToWriteColorParams()
            foreach ($key in 'StartTab', 'StartSpaces', 'LinesBefore', 'LinesAfter', 'ShowTime', 'NoNewLine', 'HorizontalCenter', 'AutoPad', 'PadLeft', 'PadChar', 'PadCenter', 'Truncate', 'Wrap') {
                $sample.Remove($key)
            }
            Write-ColorEX -Text ($profileName.PadRight($width) + ' ') -NoNewLine
            # A color Write-ColorEX does not take gives its error in place of the sample, written
            # as one that does not stop the view, and the other profiles follow
            try {
                Write-ColorEX -Text 'Sample text' @sample -Silent -NoNewLine
            } catch {
                $PSCmdlet.WriteError($_)
            }
            Write-ColorEX -Text (' ' + (Get-ColorStyleSummary -Style $style))
        }
        return
    }

    $table = Get-ColorTableWithRGB
    $names = @(Get-ColorNameOrder -Names @($table.Keys | Where-Object {
        $key = $_
        @($Name | Where-Object { $key -like $_ }).Count -gt 0
    }))
    if ($names.Count -eq 0) {
        return
    }

    $width = 4
    foreach ($item in $names) {
        $width = [Math]::Max($width, $item.Length)
    }
    $sample = if ($Background) { ' ' } else { [string][char]0x2588 * 6 }

    Write-ColorEX -Text ('Name'.PadRight($width) + ' TrueColor 256 16 Console Hex ANSI8 Console color') -Bold
    foreach ($item in $names) {
        $entry = $table[$item]
        $rgb = $entry[4]
        $hex = '#{0:X2}{1:X2}{2:X2}' -f $rgb[0], $rgb[1], $rgb[2]
        Write-ColorEX -Text ($item.PadRight($width) + ' ') -NoNewLine
        if ($Background) {
            Write-ColorEX -Text $sample -BackGroundColor $hex -TrueColor -Silent -NoNewLine
            Write-ColorEX -Text ' ' -NoNewLine
            Write-ColorEX -Text $sample -BackGroundColor $entry[3] -ANSI8 -Silent -NoNewLine
            Write-ColorEX -Text ' ' -NoNewLine
            Write-ColorEX -Text $sample -BackGroundColor $item -ANSI4 -Silent -NoNewLine
            Write-ColorEX -Text ' ' -NoNewLine
            Write-ColorEX -Text $sample -BackGroundColor $entry[0] -NoNewLine
        } else {
            Write-ColorEX -Text $sample -Color $hex -TrueColor -Silent -NoNewLine
            Write-ColorEX -Text ' ' -NoNewLine
            Write-ColorEX -Text $sample -Color $entry[3] -ANSI8 -Silent -NoNewLine
            Write-ColorEX -Text ' ' -NoNewLine
            Write-ColorEX -Text $sample -Color $item -ANSI4 -Silent -NoNewLine
            Write-ColorEX -Text ' ' -NoNewLine
            Write-ColorEX -Text $sample -Color $entry[0] -NoNewLine
        }
        Write-ColorEX -Text (' ' + $hex + ' ' + "$($entry[3])".PadLeft(5) + ' ' + $entry[0])
    }
}