Created
May 9, 2023 14:09
-
-
Save jhoneill/f327b7913735db4ab6f1adaaa7bcf67d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#requires -module psreadline | |
using namespace System.Collections | |
using namespace System.Collections.Generic | |
using namespace System.Management.Automation | |
using namespace System.Management.Automation.Language | |
#create a hash table of VT codes | |
# Reverse, underline and reset; the console colors as Name, NameBackground; Markdown theme colors if present, PsReadline theme colors, and out-stream colors | |
if (-not $host.UI.SupportsVirtualTerminal) {$Script:VTCodes = @{}} | |
else { | |
$esc = [char]0x1b | |
([System.ConsoleColor]).GetEnumNames() | | |
ForEach-Object -Begin {$Script:VTCodes = [ordered]@{"UnderLine"="$esc[4m";"Reverse"="$esc[7m";"Reset"="$esc[0m"}} -Process { | |
$Script:VTCodes[$_] = [Microsoft.PowerShell.VTColorUtils]::AsEscapeSequence($_) | |
$Script:VTCodes["$_`Background"] = [Microsoft.PowerShell.VTColorUtils]::AsEscapeSequence($_,$true) | |
} | |
try { | |
(Get-MarkdownOption).psobject.Properties | Where-Object -Property value -match "^\[\d" | | |
ForEach-Object -Process {$Script:VTCodes[$_.name] = $esc+ $_.value} | |
} | |
catch {Write-Verbose "Markdown not present, continuing"} | |
(Get-PSReadLineOption ).psobject.Properties | Where-Object -Property name -like "*color" | | |
ForEach-Object -Process {$Script:VTCodes[($_.name -Replace "color$","")] = [Microsoft.PowerShell.VTColorUtils]::AsEscapeSequence($_.value)} | |
$host.PrivateData.psobject.Properties | Where-Object -Property name -like "*color" | | |
ForEach-Object -Process {$Script:VTCodes[($_.name -Replace "(Foreground)?color$","")] = [Microsoft.PowerShell.VTColorUtils]::AsEscapeSequence($_.value,[boolean]($_.name -like "*BackgroundColor"))} | |
} | |
#completer class for VT codes - returns one of codes in the hash table above | |
class VTCodeCompleter : IArgumentCompleter { | |
[IEnumerable[CompletionResult]] CompleteArgument( | |
[string] $CommandName , | |
[string] $ParameterName, | |
[string] $WordToComplete, | |
[CommandAst] $CommandAst, | |
[IDictionary] $FakeBoundParameters | |
) | |
{ | |
$wildcard = ("*" + $wordToComplete + "*") | |
$completionResults = [List[CompletionResult]]::new() | |
$Script:VTCodes.keys.where({$_ -like $wildcard }) | | |
ForEach-Object {$completionResults.Add([CompletionResult]::new($_))} | |
return $completionResults | |
} | |
} | |
Function Add-VtFormat { | |
<# | |
.Synopsis | |
Adds VT formatting codes to strings, formatting either the whole string, or a matching part of it. | |
.Example | |
Add-VtFormat "arbitrary color" -vtcode 'DarkBlue', 'CyanBackground' | |
Sets the text to be Dark blue on a cyan background. | |
.Example | |
Add-vtformat "theme color" -VtCode 'Warning' | |
Sets the text to a the colour used for warning text. | |
.Example | |
Add-VtFormat "highlight this not that" -VtCode 'Reverse' -Select "this" | |
Highlights just word "this" | |
.Example | |
$s = select-string -path *.ps1 -SimpleMatch "\s*=" | |
Add-VtFormat $s.line 'Reverse' -Select $s.Pattern -EscapeFirst | |
$S matchinfo object and $S.pattern holds a string which should NOT be treated as a regular | |
expression - Select String was told to find the litteral text "\s*=". To ensure that text is | |
highlighted , and not look for "space, any number of times, followed by =" -EscapeFirst is needed | |
.Example | |
Add-VtFormat "highlight this not that" -VtCode 'Reverse' -select "^.{4}" | |
Add-VtFormat "highlight this not that" -VtCode 'Reverse' -select ".{3}$" | |
Add-VtFormat "highlight this not that" -VtCode 'Reverse' -select "(?<=^.{15}).*" | |
Add-VtFormat "highlight this not that" -VtCode 'Reverse' -select "(?<=^.{15}).{3}" | |
Add-VtFormat "highlight this not that" -VtCode 'Reverse' -select "(?<=^.{15}).*(?=.{5})" | |
Add-VtFormat "highlight this not that" -VtCode 'Reverse' -select ".*(?=.{5})" | |
Using regular expressions to select first 4 chars, last 3 , all text after the first 15, | |
3 chars after the first 15, from the first 15 to the the last 5, everything up to the last 5. | |
#> | |
param ( | |
#The Text to format | |
[Parameter(ValueFromPipeline=$true,Mandatory=$true)] | |
[string]$Text, | |
#One or more VT formatting code name(s) or escape string(s) to apply to the text | |
[ArgumentCompleter([VTCodeCompleter])] | |
[string[]]$VtCode, | |
#Applies the code to only a substring in -Text (by default the whole of text is format) | |
[string]$Select, | |
#If escapes any characters in -Select which have a special meaning in a regular expression | |
[switch]$EscapeFirst | |
) | |
process { | |
if ($DisableVTFormat -or -not $host.UI.SupportsVirtualTerminal) {$text} | |
else { | |
$codeString = "" | |
foreach ($code in $VTcode) { | |
if ($code -match "^\e\[\d.*m") { | |
$codeString += $code | |
} | |
else { | |
$codeString += $Script:VTCodes[$code] | |
} | |
} | |
if ($Select) { | |
if ($EscapeFirst) {$Select = [regex]::Escape($Select)} | |
$substition = $codeString + '$1' + $Script:VTCodes["Reset"] | |
$text -Replace "($Select)",$substition | |
} | |
else { | |
$codeString + $text + $Script:VTCodes["Reset"] | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment