Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ninmonkey/73e24a99a5d5b8eaedcf897c30fa4780 to your computer and use it in GitHub Desktop.
Save ninmonkey/73e24a99a5d5b8eaedcf897c30fa4780 to your computer and use it in GitHub Desktop.
Show ansi escapes for runes in Powershell 7
function Format-ControlChar {
<#
.synopsis
converts ANSI control chars into human-visible symbols.
.description
Because they are not ansi escapes ( control chars ), they have no special meaning
so they are save to pipe to your terminal or transport.
This is written in for Pwsh7 because it simplifes code
#>
[Alias('Fcc')]
param(
# Pipe strings to convert
[Parameter( ValueFromPipeline )]
[string] $Text
)
process {
# if it's an escape, add 0x2400 for the new codepoint
@( foreach( $rune in $Text.EnumerateRunes() ) {
$rune.Value -gt 0x20 ?
$rune :
[Text.Rune]::new( $rune.Value + 0x2400 )
}) | Join-String -sep ''
}
}

What is a "Codepoint" or "Rune" or "Char" ?

Tip

Have heard of "ascii numbers" or "alt codes" ? That's essentially what codepoints are.

It's one integer that converts to a specific character.

In DAX you may have added newlines with UniChar( 10 )

10 in decimal is the codepoint for a "newline": https://www.compart.com/en/unicode/U+000a

Extra resources

Note

All you really need to know is the basic concept of a codepoint

If you really want to dive deep into unicode and dotnet types, here's a good reference:

https://learn.microsoft.com/en-us/dotnet/standard/base-types/character-encoding-introduction

Usage

Pwsh7> Fcc "Hi world`n`n`n`tstuff`r`n"
    # out: Hi␠world␊␊␊␉stuff␍␊

Pwsh7> Fcc "Hi world`n`n`n`tstuff

    and more `r`n
end"
    # out: Hi␠world␊␊␊␉stuff␊␊␠␠␠␠and␠more␠␍␊␊end
    

Tip

You can visualize how 24-bit color in consoles is implemented

It replaces 0x1b with the plain text symbol.

'Hi world' 
    | Join-String -op $PSStyle.Foreground.FromRgb('#feaa99') 
    | Fcc

    # Out:  ␛[38;2;254;170;153mHi␠world
# WinPS users don't have PSStyle but the module 'pansies' will run on both 5 and 7
> "hi ${fg:#fe9911} world" | Fcc

    # out: hi␠␛[38;2;254;153;17m␠world

Method for Pwsh7

> [Text.Rune]::New( 0x1f412 )
# output: 🐒

# There's a `u` escape for codepoints inside a string
> "`u{1f412}".EnumerateRunes() | ft

> 'hi 🐒 world'.EnumerateRunes() | ft -AutoSize

A Safe method for both WinPS 5 and Pwsh 7+

Caution

To be safe, if you want a char from an int you need to use this function for WinPS <= 5

> $myChar = [char]::ConvertFromUtf32( 0x1f412 )
> $myChar
    # output: 🐒

> $myChar.Length
    # output: 2

> $myChar.GetType().FullName
    # output: System.String

Note that System.Char.ConvertFromUtf32 returns type string and not a char

Differences in 7

Note

WinPS 5 and Powershell 7 are two different branches. They install side-by side. 7 does not break 5.

  • powershell.exe means you're running 5
  • pwsh.exe means you're running 7

Tip

Cool things in 7

  • All strings have a new method .EnumerateRunes() which converts [String] into a list of [Text.Rune]
  • [Text.Rune] is a true representation of a unicode codepoint. In 5 you're using [char] which is only 2 bytes.
    • Therefore [char] cannot represent a huge chunk of utf8 codepoints
  • Join-String allows tons of calculated strings and properties
  • You can continue commands by prefixing a pipe opertor. Previously you had to add it to the end of the previous line
gci . 
   | Sort-Object LastWriteTime -Desc
   # You can even throw comments in to toggle chunks, without breaking the pipeline   
   # | Select -First 10 
   | ft -Auto

Warning

[char] is not one "character"

The problem is unicode has a million unique "characters". Up to 0x10ffff . The max value of Char is smaller than that:

> [int][char]::MaxValue
65535

# that's why it sometimes works but breaks on other characters
> [char]100
# out:
d

> [char]0x1f412
# error:
Cannot convert value "128018" to type "System.Char". Error: "Value was either too large or too small for a character."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment