commands.ps1
<# .SYNOPSIS Breaks a long word into two parts: the portion that fits within the allowed width and the leftover characters. .DESCRIPTION This function processes a list of ASCII characters (`figChars`) and determines how much of the word can fit within the specified width (`opts.width`). It returns the portion that fits (`outputFigText`) and any leftover characters (`chars`). .PARAMETER figChars An array of single ASCII characters in the form `{fig, overlap}`. Represents the word to be broken. .PARAMETER len The number of rows to process. .PARAMETER opts A hashtable containing options, including: - `width`: The maximum allowed width for the word. .EXAMPLE $figChars = @( @{ fig = "H"; overlap = 1 }, @{ fig = "e"; overlap = 1 }, @{ fig = "l"; overlap = 1 }, @{ fig = "l"; overlap = 1 }, @{ fig = "o"; overlap = 1 } ) $opts = @{ width = 10 } $result = Break-Word -figChars $figChars -len 2 -opts $opts This example breaks the word "Hello" into a portion that fits within the width of 10 and any leftover characters. .NOTES This function assumes the existence of helper functions `Join-FigArray` and `Get-FigLinesWidth` for processing the ASCII characters and calculating their widths. #> function Break-Word { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [array]$figChars, # List of single ASCII characters in form {fig, overlap} [int]$len, # Number of rows [hashtable]$opts # Options object ) $result = @{} for ($i = $figChars.Count; --$i -ge 0; ) { # Join the figChars up to the current index $w = Join-FigArray -array $figChars[0..($i)] -len $len -opts $opts # Check if the width of the joined array is within the allowed width if ((Get-FigLinesWidth -textLines $w) -le $opts.width) { $result["outputFigText"] = $w # If there are leftover characters, add them to the result if ($i -lt $figChars.Count) { $result["chars"] = $figChars[$i..($figChars.Count)] } else { $result["chars"] = @() } break } } return $result } <# .SYNOPSIS Determines if two lines of text can be vertically smushed based on the specified smushing rules. .DESCRIPTION This function evaluates whether two lines of text (`txt1` and `txt2`) can be vertically smushed together according to the vertical smushing rules defined in the `opts.fittingRules` parameter. It iterates through each character in the lines and applies the appropriate smushing rules to determine if the lines can be combined. The function returns whether the smushing is valid, invalid, or has ended. .PARAMETER txt1 The first line of text to evaluate for vertical smushing. .PARAMETER txt2 The second line of text to evaluate for vertical smushing. .PARAMETER opts A hashtable containing the smushing options, including: - `fittingRules.vLayout`: Specifies the vertical layout type (e.g., Full, Fitted, UniversalSmushing). - `fittingRules.vRule1` to `vRule4`: Boolean flags indicating which smushing rules to apply. .EXAMPLE $txt1 = "Hello" $txt2 = "World" $opts = @{ fittingRules = @{ vLayout = [LayoutType]::UniversalSmushing vRule1 = $true vRule2 = $false vRule3 = $true vRule4 = $false } } $result = Can-VerticalSmush -txt1 $txt1 -txt2 $txt2 -opts $opts This example checks if the lines "Hello" and "World" can be vertically smushed using the specified smushing rules. .NOTES This function relies on helper functions (`vRule1-Smush`, `vRule2-Smush`, `vRule3-Smush`, `vRule4-Smush`, and `vRule5-Smush`) to evaluate individual smushing rules for character pairs. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Can-VerticalSmush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$txt1, # A line of text [string]$txt2, # A line of text [hashtable]$opts # FIGlet options array ) # Check if the vertical layout is FULL_WIDTH if ($opts.fittingRules.vLayout -eq [LayoutType]::Full) { return "invalid" } # Determine the minimum length of the two lines $len = [math]::Min($txt1.Length, $txt2.Length) if ($len -eq 0) { return "invalid" } $endSmush = $false $validSmush = $false # Iterate through each character in the lines for ($ii = 0; $ii -lt $len; $ii++) { $ch1 = $txt1[$ii] $ch2 = $txt2[$ii] # Check if both characters are not spaces if ($ch1 -ne " " -and $ch2 -ne " ") { if ($opts.fittingRules.vLayout -eq [LayoutType]::Fitted) { return "invalid" } elseif ($opts.fittingRules.vLayout -eq [LayoutType]::UniversalSmushing) { return "end" } else { # Apply smushing rules if (vRule5-Smush -ch1 $ch1 -ch2 $ch2) { $endSmush = $endSmush -or $false continue } $validSmush = $false if ($opts.fittingRules.vRule1) { $validSmush = vRule1-Smush -ch1 $ch1 -ch2 $ch2 } if (-not $validSmush -and $opts.fittingRules.vRule2) { $validSmush = vRule2-Smush -ch1 $ch1 -ch2 $ch2 } if (-not $validSmush -and $opts.fittingRules.vRule3) { $validSmush = vRule3-Smush -ch1 $ch1 -ch2 $ch2 } if (-not $validSmush -and $opts.fittingRules.vRule4) { $validSmush = vRule4-Smush -ch1 $ch1 -ch2 $ch2 } $endSmush = $true if (-not $validSmush) { return "invalid" } } } } # Return the result based on whether smushing has ended if ($endSmush) { return "end" } else { return "valid" } } <# .SYNOPSIS Generates FIGlet text lines from input text using specified FIGlet characters and options. .DESCRIPTION This function processes input text and converts it into FIGlet text lines using the provided FIGlet character definitions (`figChars`) and options (`opts`). It handles whitespace, character smushing, and layout rules to produce the final FIGlet text output. .PARAMETER txt The input text to be converted into FIGlet text lines. .PARAMETER figChars A hashtable containing the FIGlet character definitions. Each character maps to its FIGlet representation. .PARAMETER opts A hashtable containing options for generating FIGlet text, including: - `height`: The height of the FIGlet characters. - `width`: The maximum width of the output text. - `whitespaceBreak`: A flag indicating whether to break lines at whitespace. - `printDirection`: The direction in which the text is printed (e.g., left-to-right or right-to-left). - `fittingRules.hLayout`: Specifies the horizontal layout type (e.g., Full, Fitted, ControlledSmushing). .EXAMPLE $txt = "Hello, World!" $figChars = @{ 72 = @("H", "H") 101 = @("e", "e") 108 = @("l", "l") 111 = @("o", "o") 44 = @(",", ",") 32 = @(" ", " ") 87 = @("W", "W") 114 = @("r", "r") 100 = @("d", "d") 33 = @("!", "!") } $opts = @{ height = 8 width = 80 whitespaceBreak = $true printDirection = 0 fittingRules = @{ hLayout = [LayoutType]::ControlledSmushing } } $result = Generate-FigTextLines -txt $txt -figChars $figChars -opts $opts This example generates FIGlet text lines for the input "Hello, World!" using the specified FIGlet characters and options. .NOTES This function assumes the existence of helper functions such as `New-FigChar` for creating FIGlet characters and `Join-FigArray` for combining FIGlet text lines. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Generate-FigTextLines { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','')] param ( [string]$txt, # Input text [hashtable]$figChars, # FIGlet characters [hashtable]$opts # Options object ) $overlap = 0 $height = $opts.height $outputFigLines = @() $figWords = @() $outputFigText = New-FigChar -len $height $nextFigChars = $null if ($opts.width -gt 0 -and $opts.whitespaceBreak) { $nextFigChars = @{ chars = @() overlap = $overlap } } if ($opts.printDirection -eq 1) { $txt = ($txt.ToCharArray() | ForEach-Object { $_ })[-1..-($txt.Length)] -join "" } $len = $txt.Length for ($charIndex = 0; $charIndex -lt $len; $charIndex++) { $char = $txt.Substring($charIndex, 1) $isSpace = $char -match "\s" $figChar = $figChars[[int][char]$char] $textFigLine = $null if ($figChar) { if ($opts.fittingRules.hLayout -ne [LayoutType]::Full) { $overlap = 10000 for ($row = 0; $row -lt $opts.height; $row++) { $overlap = [math]::Min( $overlap, (Get-HorizontalSmushLength -txt1 $outputFigText[$row] -txt2 $figChar[$row] -opts $opts) ) } $overlap = if ($overlap -eq 10000) { 0 } else { $overlap } } if ($opts.width -gt 0) { if ($opts.whitespaceBreak) { $textFigWord = Join-FigArray -array ($nextFigChars.chars + @(@{ fig = $figChar; overlap = $overlap })) -len $height -opts $opts $textFigLine = Join-FigArray -array ($figWords + @(@{ fig = $textFigWord; overlap = $nextFigChars.overlap })) -len $height -opts $opts $maxWidth = Get-FigLinesWidth -textLines $textFigLine } else { $textFigLine = Horizontal-Smush -textBlock1 $outputFigText -textBlock2 $figChar -overlap $overlap -opts $opts $maxWidth = Get-FigLinesWidth -textLines $textFigLine } if ($maxWidth -ge $opts.width -and $charIndex -gt 0) { if ($opts.whitespaceBreak) { $outputFigText = Join-FigArray -array $figWords[0..($figWords.Count - 2)] -len $height -opts $opts if ($figWords.Count -gt 1) { $outputFigLines += $outputFigText $outputFigText = New-FigChar -len $height } $figWords = @() } else { $outputFigLines += $outputFigText $outputFigText = New-FigChar -len $height } } } if ($opts.width -gt 0 -and $opts.whitespaceBreak) { if (-not $isSpace -or $charIndex -eq $len - 1) { $nextFigChars.chars += @{ fig = $figChar; overlap = $overlap } } if ($isSpace -or $charIndex -eq $len - 1) { $tmpBreak = $null while ($true) { $textFigLine = Join-FigArray -array $nextFigChars.chars -len $height -opts $opts $maxWidth = Get-FigLinesWidth -textLines $textFigLine if ($maxWidth -ge $opts.width) { $tmpBreak = Break-Word -figChars $nextFigChars.chars -len $height -opts $opts $nextFigChars = @{ chars = $tmpBreak.chars } $outputFigLines += $tmpBreak.outputFigText } else { break } } if ($maxWidth -gt 0) { if ($tmpBreak) { $figWords += @{ fig = $textFigLine; overlap = 1 } } else { $figWords += @{ fig = $textFigLine; overlap = $nextFigChars.overlap } } } if ($isSpace) { $figWords += @{ fig = $figChar; overlap = $overlap } $outputFigText = New-FigChar -len $height } if ($charIndex -eq $len - 1) { $outputFigText = Join-FigArray -array $figWords -len $height -opts $opts } $nextFigChars = @{ chars = @() overlap = $overlap } continue } } $outputFigText = Horizontal-Smush -textBlock1 $outputFigText -textBlock2 $figChar -overlap $overlap -opts $opts } } if (Get-FigLinesWidth -textLines $outputFigText -gt 0) { $outputFigLines += $outputFigText } if (-not $opts.showHardBlanks) { $outputFigLines = $outputFigLines | ForEach-Object { $_ | ForEach-Object { $_ -replace [regex]::Escape($opts.hardBlank), " " } } } return $outputFigLines } <# .SYNOPSIS Generates ASCII art text using a specified FIGlet font and options. .DESCRIPTION This function converts input text into ASCII art using the specified FIGlet font and rendering options. It processes each line of the input text, generates FIGlet lines for each, and combines them vertically to produce the final ASCII art output. .PARAMETER fontName The name of the FIGlet font to use for generating the ASCII art. .PARAMETER options A hashtable containing options to override the default font settings, including: - `width`: The maximum width of the output text. - `fittingRules`: Rules for horizontal and vertical smushing. - `printDirection`: The direction in which the text is printed (e.g., left-to-right or right-to-left). .PARAMETER txt The input text to be converted into ASCII art. .EXAMPLE $fontName = "Standard" $options = @{ width = 80 fittingRules = @{ hLayout = [LayoutType]::ControlledSmushing vLayout = [LayoutType]::UniversalSmushing } printDirection = 0 } $txt = "Hello, World!" $asciiArt = Generate-Text -fontName $fontName -options $options -txt $txt This example generates ASCII art for the text "Hello, World!" using the "Standard" FIGlet font and the specified options. .NOTES This function assumes the existence of helper functions such as `Generate-FigTextLines` for generating FIGlet lines and `Smush-VerticalFigLines` for combining FIGlet lines vertically. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Generate-Text { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$fontName, # Font to use [hashtable]$options, # Options to override the defaults [string]$txt # The text to make into ASCII Art ) # Replace line endings with "\n" $txt = $txt -replace "`r`n", "`n" -replace "`r", "`n" # Split the text into lines $lines = $txt -split "`n" $figLines = @() # Generate FIGlet lines for each line of text foreach ($line in $lines) { $figLines += Generate-FigTextLines -txt $line -figChars $Script:FigFonts[$fontName] -opts $options } # Combine the FIGlet lines vertically $output = $figLines[0] for ($ii = 1; $ii -lt $figLines.Count; $ii++) { $lines = $figLines[$ii] $output = Smush-VerticalFigLines -output $output -lines $lines -opts $options } # Return the final output as a single string return $output -join "`n" } <# .SYNOPSIS Retrieves the border symbols for a specified border type. .DESCRIPTION This function returns a hashtable containing the symbols used for constructing borders based on the specified border type. The hashtable includes symbols for the corners, spacers, and edges of the border. .PARAMETER BorderType The type of border to retrieve symbols for. Valid values are defined in the `BorderType` enum and include: - `Asterisk` - `Hash` - `Plus` - `Box` - `TwoLinesFrame` .EXAMPLE $borderSymbols = Get-BorderSymbol -BorderType "Box" This example retrieves the border symbols for the "Box" border type. .EXAMPLE $borderSymbols = Get-BorderSymbol -BorderType "Asterisk" This example retrieves the border symbols for the "Asterisk" border type. .NOTES This function uses a switch statement to map the specified border type to its corresponding symbols. The returned hashtable includes the following keys: - `TopLeft`, `TopRight`, `BottomLeft`, `BottomRight`: Symbols for the corners. - `TopSpacer`, `BottomSpacer`: Symbols for the horizontal edges. - `LeftSpacer`, `RightSpacer`: Symbols for the vertical edges. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Get-BorderSymbol { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter(Mandatory = $true)] [BorderType] # Use the enum for validation $BorderType ) switch ($BorderType) { 'Asterisk' { return @{ TopLeft = "*"; TopRight = "*"; BottomLeft = "*"; BottomRight = "*"; TopSpacer = "*"; BottomSpacer = "*"; LeftSpacer = "*"; RightSpacer = "*" } } 'Hash' { return @{ TopLeft = "#"; TopRight = "#"; BottomLeft = "#"; BottomRight = "#"; TopSpacer = "#"; BottomSpacer = "#"; LeftSpacer = "#"; RightSpacer = "#" } } 'Plus' { return @{ TopLeft = "+"; TopRight = "+"; BottomLeft = "+"; BottomRight = "+"; TopSpacer = "+"; BottomSpacer = "+"; LeftSpacer = "+"; RightSpacer = "+" } } 'Box' { return @{ TopLeft = "┌"; TopRight = "┐"; BottomLeft = "└"; BottomRight = "┘"; TopSpacer = "─"; BottomSpacer = "─"; LeftSpacer = "│"; RightSpacer = "│" } } 'TwoLinesFrame' { return @{ TopLeft = "/"; TopRight = "\"; BottomLeft = "\"; BottomRight = "/"; TopSpacer = "="; BottomSpacer = "="; LeftSpacer = "||"; RightSpacer = "||" } } 'DoubleBox' { return @{ TopLeft = "╔"; TopRight = "╗"; BottomLeft = "╚"; BottomRight = "╝"; TopSpacer = "═"; BottomSpacer = "═"; LeftSpacer = "║"; RightSpacer = "║" } } 'DoubleCorners' { return @{ TopLeft = "╔"; TopRight = "╗"; BottomLeft = "╚"; BottomRight = "╝"; TopSpacer = "─"; BottomSpacer = "─"; LeftSpacer = "│"; RightSpacer = "│" } } 'BubbleBorder' { return @{ TopLeft = "(_)"; TopRight = "(_)"; BottomLeft = "(_)"; BottomRight = "(_)"; TopSpacer = "(_)"; BottomSpacer = "(_)"; LeftSpacer = "(_)"; RightSpacer = "(_)" } } 'BoxBorder' { return @{ TopLeft = "|_|"; TopRight = "|_|"; BottomLeft = "|_|"; BottomRight = "|_|"; TopSpacer = "|_|"; BottomSpacer = "|_|"; LeftSpacer = "|_|"; RightSpacer = "|_|" } } 'Dots' { return @{ TopLeft = "."; TopRight = "."; BottomLeft = ":"; BottomRight = ":"; TopSpacer = "."; BottomSpacer = "."; LeftSpacer = ":"; RightSpacer = ":" } } 'DoubleDots' { return @{ TopLeft = "::"; TopRight = "::"; BottomLeft = "::"; BottomRight = "::"; TopSpacer = ":"; BottomSpacer = ":"; LeftSpacer = "::"; RightSpacer = "::" } } 'None' { return @{ TopLeft = ""; TopRight = ""; BottomLeft = ""; BottomRight = ""; TopSpacer = ""; BottomSpacer = ""; LeftSpacer = ""; RightSpacer = "" } } } } <# .SYNOPSIS Calculates the maximum line width of the provided ASCII art text. .DESCRIPTION This function takes an array of text lines as input and determines the maximum width (number of characters) among all the lines. It is useful for measuring the width of ASCII art or text blocks. .PARAMETER textLines An array of strings representing the lines of text to measure. .EXAMPLE $textLines = @( "Hello, World!", "This is a test.", "PowerShell" ) $maxWidth = Get-FigLinesWidth -textLines $textLines This example calculates the maximum line width from the provided text lines. .NOTES This function uses the `Measure-Object` cmdlet to determine the maximum length of the lines. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Get-FigLinesWidth { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string[]]$textLines # Array of lines for text ) return ($textLines | ForEach-Object { $_.Length } | Measure-Object -Maximum).Maximum } <# .SYNOPSIS Retrieves metadata about a specified FIGlet font. .DESCRIPTION This function retrieves metadata for a given FIGlet font, including its options and header comment. It loads the font using the `Load-Font` function and extracts the header comment from the global `$Script:FigFonts` hashtable. .PARAMETER fontName The name of the FIGlet font to retrieve metadata for. .PARAMETER next An optional callback function to handle the result or error. If provided, the callback will be invoked with the font options and header comment. .EXAMPLE $fontName = "Standard" $metadata = Get-FontMetadata -fontName $fontName This example retrieves the metadata for the "Standard" FIGlet font. .NOTES This function assumes the existence of a `Load-Font` function to load the font options and a global `$Script:FigFonts` hashtable containing font metadata. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Get-FontMetadata { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','')] param ( [string]$fontName, # Name of the font [ScriptBlock]$next = $null # Optional callback function ) # Ensure fontName is a string $fontName = [string]"$fontName" # Load the font $fontOpts = Load-Font -fontName "$fontName" $headerComment = $Script:FigFonts["$fontName"].comment # Return the Task object return @($fontOpts, $headerComment) } <# .SYNOPSIS Retrieves the horizontal fitting rules for a specified layout type. .DESCRIPTION This function returns a hashtable containing the horizontal fitting rules based on the specified layout type. It supports multiple layout types, such as Default, Full, Fitted, and ControlledSmushing. The function maps the layout type to its corresponding fitting rules, including horizontal layout (`hLayout`) and individual smushing rules (`hRule1` to `hRule6`). .PARAMETER layout The layout type for which the horizontal fitting rules are retrieved. Valid values include: - `[LayoutType]::Default` - `[LayoutType]::Full` - `[LayoutType]::Fitted` - `[LayoutType]::ControlledSmushing` .PARAMETER options A hashtable containing the fitting rules for the Default layout. This parameter is used when the layout type is `[LayoutType]::Default`. .EXAMPLE $layout = [LayoutType]::Default $options = @{ fittingRules = @{ hLayout = [LayoutType]::Default hRule1 = $true hRule2 = $false hRule3 = $true hRule4 = $false hRule5 = $true hRule6 = $false } } $rules = Get-HorizontalFittingRules -layout $layout -options $options This example retrieves the horizontal fitting rules for the Default layout type using the specified options. .NOTES This function assumes the existence of a `[LayoutType]` enum or equivalent structure to define valid layout types. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Get-HorizontalFittingRules { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','')] param ( [string]$layout, # Layout type (e.g., [LayoutType]::Default, [LayoutType]::Full, etc.) [hashtable]$options # Options object containing fitting rules ) $props = @("hLayout", "hRule1", "hRule2", "hRule3", "hRule4", "hRule5", "hRule6") $params = @{} if ($layout -eq [LayoutType]::Default) { foreach ($prop in $props) { $params[$prop] = $options.fittingRules[$prop] } } elseif ($layout -eq [LayoutType]::Full) { $params = @{ hLayout = [LayoutType]::Full hRule1 = $false hRule2 = $false hRule3 = $false hRule4 = $false hRule5 = $false hRule6 = $false } } elseif ($layout -eq [LayoutType]::Fitted) { $params = @{ hLayout = [LayoutType]::Fitted hRule1 = $false hRule2 = $false hRule3 = $false hRule4 = $false hRule5 = $false hRule6 = $false } } elseif ($layout -eq [LayoutType]::ControlledSmushing) { $params = @{ hLayout = [LayoutType]::ControlledSmushing hRule1 = $true hRule2 = $true hRule3 = $true hRule4 = $true hRule5 = $true hRule6 = $true } } elseif ($layout -eq [LayoutType]::UniversalSmushing) { $params = @{ hLayout = [LayoutType]::UniversalSmushing hRule1 = $false hRule2 = $false hRule3 = $false hRule4 = $false hRule5 = $false hRule6 = $false } } else { return $null } return $params } <# .SYNOPSIS Calculates the horizontal smushing distance between two text strings based on the specified smushing rules. .DESCRIPTION This function determines the maximum horizontal smushing distance between two text strings (`txt1` and `txt2`) according to the smushing rules defined in the `opts.fittingRules` parameter. It evaluates character overlaps and applies specific smushing rules, such as Full, Fitted, and UniversalSmushing, to calculate the distance. .PARAMETER txt1 The first text string to evaluate for horizontal smushing. .PARAMETER txt2 The second text string to evaluate for horizontal smushing. .PARAMETER opts A hashtable containing smushing options, including: - `fittingRules.hLayout`: Specifies the horizontal layout type (e.g., Full, Fitted, UniversalSmushing). - `hardBlank`: The character used to represent hard blanks in FIGlet fonts. .EXAMPLE $txt1 = "Hello" $txt2 = "World" $opts = @{ fittingRules = @{ hLayout = [LayoutType]::UniversalSmushing } hardBlank = "@" } $smushLength = Get-HorizontalSmushLength -txt1 $txt1 -txt2 $txt2 -opts $opts This example calculates the horizontal smushing distance between the strings "Hello" and "World" using the UniversalSmushing layout type. .NOTES This function assumes the existence of a `[LayoutType]` enum or equivalent structure to define valid layout types. It also relies on the `hardBlank` option to handle special cases for smushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Get-HorizontalSmushLength { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$txt1, # First text string [string]$txt2, # Second text string [hashtable]$opts # Options for smushing ) if ($opts.fittingRules.hLayout -eq [LayoutType]::Full) { return 0 } $len1 = $txt1.Length $len2 = $txt2.Length $maxDist = $len1 $curDist = 1 $breakAfter = $false $validSmush = $false if ($len1 -eq 0) { return 0 } $stopWhile = $false while ($curDist -le $maxDist -and (-not $stopWhile)) { $seg1StartPos = $len1 - $curDist $seg1 = $txt1.Substring($seg1StartPos, $curDist) $seg2 = $txt2.Substring(0, [math]::Min($curDist, $len2)) for ($ii = 0; $ii -lt [math]::Min($curDist, $len2) -and (-not $stopWhile); $ii++) { $ch1 = $seg1.Substring($ii, 1) $ch2 = $seg2.Substring($ii, 1) if ($ch1 -ne " " -and $ch2 -ne " ") { if ($opts.fittingRules.hLayout -eq [LayoutType]::Fitted) { $curDist -= 1 $stopWhile = $true break } elseif ($opts.fittingRules.hLayout -eq [LayoutType]::UniversalSmushing) { if ($ch1 -eq $opts.hardBlank -or $ch2 -eq $opts.hardBlank) { $curDist -= 1 # universal smushing does not smush hardblanks } $stopWhile = $true break } else { $breakAfter = $true # we know we need to break, but we need to check if our smushing rules will allow us to smush the overlapped characters $validSmush = $false # the below checks will let us know if we can smush these characters if ($opts.fittingRules.hRule1) { $validSmush = hRule1-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } if (-not $validSmush -and $opts.fittingRules.hRule2) { $validSmush = hRule2-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } if (-not $validSmush -and $opts.fittingRules.hRule3) { $validSmush = hRule3-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } if (-not $validSmush -and $opts.fittingRules.hRule4) { $validSmush = hRule4-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } if (-not $validSmush -and $opts.fittingRules.hRule5) { $validSmush = hRule5-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } if (-not $validSmush -and $opts.fittingRules.hRule6) { $validSmush = hRule6-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } if (-not $validSmush) { $curDist -= 1 $stopWhile = $true break } } } } if($stopWhile) { break } if ($breakAfter) { break } $curDist++ } return [math]::Min($maxDist, $curDist) } <# .SYNOPSIS Retrieves smushing rules for horizontal and vertical layouts based on the specified layout values. .DESCRIPTION This function calculates the smushing rules for both horizontal and vertical layouts based on the provided `oldLayout` and `newLayout` values. It processes a predefined set of codes to determine the layout type (e.g., Fitted, UniversalSmushing) and individual smushing rules (e.g., `hRule1`, `vRule5`). The resulting rules are returned as a hashtable. .PARAMETER oldLayout The legacy layout value used to determine smushing rules if `newLayout` is not provided. .PARAMETER newLayout The updated layout value used to determine smushing rules. If provided, it takes precedence over `oldLayout`. .EXAMPLE $oldLayout = 2048 $newLayout = 8192 $rules = Get-SmushingRules -oldLayout $oldLayout -newLayout $newLayout This example retrieves smushing rules based on the provided `oldLayout` and `newLayout` values. .EXAMPLE $oldLayout = 128 $rules = Get-SmushingRules -oldLayout $oldLayout This example retrieves smushing rules using only the `oldLayout` value. .NOTES The function uses a predefined set of codes to map layout values to smushing rules. The resulting hashtable includes keys such as `hLayout`, `vLayout`, `hRule1`, `vRule5`, and others. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Get-SmushingRules { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','')] param ( [int]$oldLayout, [int]$newLayout ) # Initialize rules $rules = @{} # Define codes array $codes = @( @{ Value = 16384; Key = "vLayout"; Default = [LayoutType]::UniversalSmushing }, @{ Value = 8192; Key = "vLayout"; Default = [LayoutType]::Fitted }, @{ Value = 4096; Key = "vRule5"; Default = $true }, @{ Value = 2048; Key = "vRule4"; Default = $true }, @{ Value = 1024; Key = "vRule3"; Default = $true }, @{ Value = 512; Key = "vRule2"; Default = $true }, @{ Value = 256; Key = "vRule1"; Default = $true }, @{ Value = 128; Key = "hLayout"; Default = [LayoutType]::UniversalSmushing }, @{ Value = 64; Key = "hLayout"; Default = [LayoutType]::Fitted }, @{ Value = 32; Key = "hRule6"; Default = $true }, @{ Value = 16; Key = "hRule5"; Default = $true }, @{ Value = 8; Key = "hRule4"; Default = $true }, @{ Value = 4; Key = "hRule3"; Default = $true }, @{ Value = 2; Key = "hRule2"; Default = $true }, @{ Value = 1; Key = "hRule1"; Default = $true } ) # Determine the layout value $val = if ($null -ne $newLayout) { $newLayout } else { $oldLayout } # Process codes foreach ($code in $codes) { if ($val -ge $code.Value) { $val -= $code.Value if (-not $rules.ContainsKey($code.Key)) { $rules[$code.Key] = $code.Default } } elseif ($code.Key -notin @("vLayout", "hLayout")) { $rules[$code.Key] = $false } } # Handle undefined horizontal layout if (-not $rules.ContainsKey("hLayout")) { if ($oldLayout -eq 0) { $rules["hLayout"] = [LayoutType]::Fitted } elseif ($oldLayout -eq -1) { $rules["hLayout"] = [LayoutType]::Full } else { if ( $rules["hRule1"] -or $rules["hRule2"] -or $rules["hRule3"] -or $rules["hRule4"] -or $rules["hRule5"] -or $rules["hRule6"] ) { $rules["hLayout"] = [LayoutType]::ControlledSmushing } else { $rules["hLayout"] = [LayoutType]::UniversalSmushing } } } elseif ($rules["hLayout"] -eq [LayoutType]::UniversalSmushing) { if ( $rules["hRule1"] -or $rules["hRule2"] -or $rules["hRule3"] -or $rules["hRule4"] -or $rules["hRule5"] -or $rules["hRule6"] ) { $rules["hLayout"] = [LayoutType]::ControlledSmushing } } # Handle undefined vertical layout if (-not $rules.ContainsKey("vLayout")) { if ( $rules["vRule1"] -or $rules["vRule2"] -or $rules["vRule3"] -or $rules["vRule4"] -or $rules["vRule5"] ) { $rules["vLayout"] = [LayoutType]::ControlledSmushing } else { $rules["vLayout"] = [LayoutType]::Full } } elseif ($rules["vLayout"] -eq [LayoutType]::UniversalSmushing) { if ( $rules["vRule1"] -or $rules["vRule2"] -or $rules["vRule3"] -or $rules["vRule4"] -or $rules["vRule5"] ) { $rules["vLayout"] = [LayoutType]::ControlledSmushing } } return $rules } <# .SYNOPSIS Retrieves vertical fitting rules for a specified layout type. .DESCRIPTION This function returns a hashtable containing the vertical fitting rules based on the specified layout type. It supports multiple layout types, such as Default, Full, Fitted, and ControlledSmushing. The function maps the layout type to its corresponding fitting rules, including vertical layout (`vLayout`) and individual smushing rules (`vRule1` to `vRule5`). .PARAMETER layout The layout type for which the vertical fitting rules are retrieved. Valid values include: - `[LayoutType]::Default` - `[LayoutType]::Full` - `[LayoutType]::Fitted` - `[LayoutType]::ControlledSmushing` .PARAMETER options A hashtable containing the fitting rules for the Default layout. This parameter is used when the layout type is `[LayoutType]::Default`. .EXAMPLE $layout = [LayoutType]::Default $options = @{ fittingRules = @{ vLayout = [LayoutType]::Default vRule1 = $true vRule2 = $false vRule3 = $true vRule4 = $false vRule5 = $true } } $rules = Get-VerticalFittingRules -layout $layout -options $options This example retrieves the vertical fitting rules for the Default layout type using the specified options. .NOTES This function assumes the existence of a `[LayoutType]` enum or equivalent structure to define valid layout types. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Get-VerticalFittingRules { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','')] param ( [string]$layout, # Layout type (e.g., [LayoutType]::Default, [LayoutType]::Full, etc.) [hashtable]$options # Options object containing fitting rules ) $props = @("vLayout", "vRule1", "vRule2", "vRule3", "vRule4", "vRule5") $params = @{} if ($layout -eq [LayoutType]::Default) { foreach ($prop in $props) { $params[$prop] = $options.fittingRules[$prop] } } elseif ($layout -eq [LayoutType]::Full) { $params = @{ vLayout = [LayoutType]::Full vRule1 = $false vRule2 = $false vRule3 = $false vRule4 = $false vRule5 = $false } } elseif ($layout -eq [LayoutType]::Fitted) { $params = @{ vLayout = [LayoutType]::Fitted vRule1 = $false vRule2 = $false vRule3 = $false vRule4 = $false vRule5 = $false } } elseif ($layout -eq [LayoutType]::ControlledSmushing) { $params = @{ vLayout = [LayoutType]::ControlledSmushing vRule1 = $true vRule2 = $true vRule3 = $true vRule4 = $true vRule5 = $true } } elseif ($layout -eq [LayoutType]::UniversalSmushing) { $params = @{ vLayout = [LayoutType]::UniversalSmushing vRule1 = $false vRule2 = $false vRule3 = $false vRule4 = $false vRule5 = $false } } else { return $null } return $params } <# .SYNOPSIS Calculates the maximum vertical smushing distance between two sets of text lines. .DESCRIPTION This function determines the maximum number of overlapping lines (`curDist`) that can be vertically smushed between two sets of text lines (`lines1` and `lines2`) based on the smushing rules defined in the `opts` parameter. It evaluates each pair of overlapping lines using the `Can-VerticalSmush` function and adjusts the distance based on the results ("valid", "invalid", or "end"). .PARAMETER lines1 An array of strings representing the first set of text lines. .PARAMETER lines2 An array of strings representing the second set of text lines. .PARAMETER opts A hashtable containing smushing options, including: - `fittingRules.vLayout`: Specifies the vertical layout type (e.g., Full, Fitted, UniversalSmushing). - Additional smushing rules for evaluating line overlaps. .EXAMPLE $lines1 = @( "Hello", "World" ) $lines2 = @( "Foo", "Bar" ) $opts = @{ fittingRules = @{ vLayout = [LayoutType]::UniversalSmushing } } $maxDist = Get-VerticalSmushDist -lines1 $lines1 -lines2 $lines2 -opts $opts This example calculates the maximum vertical smushing distance between the two sets of text lines. .NOTES This function relies on the `Can-VerticalSmush` helper function to evaluate individual line overlaps. The result is determined based on the smushing rules and the overlap validity. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Get-VerticalSmushDist { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string[]] $lines1, [string[]] $lines2, [hashtable] $opts ) $maxDist = $lines1.Count $len1 = $lines1.Count $len2 = $lines2.Count $curDist = 1 while ($curDist -le $maxDist) { $startIndex = [math]::Max(0, $len1 - $curDist) $subLines1 = $lines1[$startIndex..($len1 - 1)] $subLines2 = $lines2[0..([math]::Min($len2, $curDist) - 1)] $slen = $subLines2.Count $result = "" for ($ii = 0; $ii -lt $slen; $ii++) { $ret = Can-VerticalSmush -txt1 $subLines1[$ii] -txt2 $subLines2[$ii] -opts $opts if ($ret -eq "end") { $result = $ret break } elseif ($ret -eq "invalid") { $result = $ret break } else { $result = "valid" } } if ($result -eq "invalid") { $curDist-- break } if ($result -eq "end") { break } if ($result -eq "valid") { $curDist++ } } return [math]::Min($maxDist, $curDist) } <# .SYNOPSIS Combines two horizontal text blocks with optional overlapping smushing. .DESCRIPTION The Horizontal-Smush function takes two horizontal text blocks (`textBlock1` and `textBlock2`) and combines them into a single text block. If an overlap is specified, the function applies horizontal smushing rules to the overlapping characters. The smushing behavior is determined by the options provided in the `opts` parameter, including the horizontal layout type (`hLayout`) and specific smushing rules (`hRule1` to `hRule6`). The function processes each line of the text blocks, calculates the overlapping segments, and applies the appropriate smushing rules to generate the combined output. .PARAMETER textBlock1 An array of strings representing the first horizontal text block. .PARAMETER textBlock2 An array of strings representing the second horizontal text block. .PARAMETER overlap The number of overlapping characters to smush. If set to 0, no smushing is applied, and the text blocks are concatenated. .PARAMETER opts A hashtable containing options for horizontal smushing, including: - `fittingRules.hLayout`: Specifies the horizontal layout type (e.g., Fitted, UniversalSmushing, ControlledSmushing). - `fittingRules.hRule1` to `hRule6`: Boolean flags indicating which smushing rules to apply. - `hardBlank`: The character used to represent hard blanks in FIGlet fonts. - `height`: The number of rows in the text blocks. .EXAMPLE $textBlock1 = @( "Hello", "World" ) $textBlock2 = @( "Foo", "Bar" ) $opts = @{ fittingRules = @{ hLayout = [LayoutType]::ControlledSmushing hRule1 = $true hRule2 = $false hRule3 = $true hRule4 = $false hRule5 = $true hRule6 = $false } hardBlank = "@" height = 2 } $result = Horizontal-Smush -textBlock1 $textBlock1 -textBlock2 $textBlock2 -overlap 3 -opts $opts This example combines two horizontal text blocks with 3 characters of overlap using ControlledSmushing rules. .NOTES This function relies on the following helper functions: - `Uni-Smush`: Applies universal smushing rules to overlapping characters. - `hRule1-Smush` to `hRule6-Smush`: Applies specific controlled smushing rules to overlapping characters. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Horizontal-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string[]]$textBlock1, # First text block [string[]]$textBlock2, # Second text block [int]$overlap, # Overlap length [hashtable]$opts # Options containing fitting rules and hardBlank ) $outputFig = @() $height = $opts.height for ($ii = 0; $ii -lt $height; $ii++) { $txt1 = $textBlock1[$ii] $txt2 = $textBlock2[$ii] $len1 = $txt1.Length $len2 = $txt2.Length $overlapStart = $len1 - $overlap $piece1 = $txt1.Substring(0, [math]::Max(0, $overlapStart)) $piece2 = "" # Determine overlap piece $seg1StartPos = [math]::Max(0, $len1 - $overlap) $seg1 = $txt1.Substring($seg1StartPos, [math]::Min($overlap, $len1 - $seg1StartPos)) $seg2 = $txt2.Substring(0, [math]::Min($overlap, $len2)) for ($jj = 0; $jj -lt $overlap; $jj++) { $ch1 = if ($jj -lt $len1) { $seg1[$jj] } else { " " } $ch2 = if ($jj -lt $len2) { $seg2[$jj] } else { " " } if ($ch1 -ne " " -and $ch2 -ne " ") { if ($opts.fittingRules.hLayout -eq [LayoutType]::Fitted) { $piece2 += Uni-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } elseif ($opts.fittingRules.hLayout -eq [LayoutType]::UniversalSmushing) { $piece2 += Uni-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } else { # Controlled Smushing $nextCh = "" if (-not $nextCh -and $opts.fittingRules.hRule1) { $nextCh = hRule1-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } if (-not $nextCh -and $opts.fittingRules.hRule2) { $nextCh = hRule2-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } if (-not $nextCh -and $opts.fittingRules.hRule3) { $nextCh = hRule3-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } if (-not $nextCh -and $opts.fittingRules.hRule4) { $nextCh = hRule4-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } if (-not $nextCh -and $opts.fittingRules.hRule5) { $nextCh = hRule5-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } if (-not $nextCh -and $opts.fittingRules.hRule6) { $nextCh = hRule6-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } $nextCh = if ($nextCh) { $nextCh } else { Uni-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } $piece2 += $nextCh } } else { $piece2 += Uni-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $opts.hardBlank } } if ($overlap -ge $len2) { $piece3 = "" } else { $piece3 = $txt2.Substring($overlap, [math]::Max(0, $len2 - $overlap)) } $outputFig += $piece1 + $piece2 + $piece3 } return $outputFig } <# .SYNOPSIS Applies Rule 1: Equal Character Smushing. .DESCRIPTION This function smushes two characters into a single character if they are the same and not a hardblank. Rule 1, known as "Equal Character Smushing," ensures that identical characters are combined into one, except when the characters are hardblanks. .PARAMETER ch1 The first character to evaluate for smushing. .PARAMETER ch2 The second character to evaluate for smushing. .PARAMETER hardBlank The character used to represent hardblanks in FIGlet fonts. Hardblanks are excluded from smushing. .EXAMPLE $ch1 = "H" $ch2 = "H" $hardBlank = "@" $result = hRule1-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $hardBlank This example smushes the characters "H" and "H" into a single "H" since they are identical and not a hardblank. .EXAMPLE $ch1 = "@" $ch2 = "@" $hardBlank = "@" $result = hRule1-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $hardBlank This example does not smush the characters "@" and "@" because they are hardblanks. .NOTES This function implements Rule 1 of the FIGlet smushing rules: Equal Character Smushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function hRule1-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$ch1, [string]$ch2, [string]$hardBlank ) if ($ch1 -eq $ch2 -and $ch1 -ne $hardBlank) { return $ch1 } return $false } <# .SYNOPSIS Applies Rule 2: Underscore Smushing. .DESCRIPTION This function smushes an underscore (`_`) with specific characters (`|`, `/`, `\`, `[`, `]`, `{`, `}`, `(`, `)`, `<`, `>`) according to Rule 2 of the FIGlet smushing rules. If one of the characters is an underscore and the other is in the allowed set, the underscore is replaced by the other character. .PARAMETER ch1 The first character to evaluate for smushing. .PARAMETER ch2 The second character to evaluate for smushing. .EXAMPLE $ch1 = "_" $ch2 = "|" $result = hRule2-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the underscore (`_`) with the pipe (`|`) and returns `|`. .EXAMPLE $ch1 = "/" $ch2 = "_" $result = hRule2-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the underscore (`_`) with the forward slash (`/`) and returns `/`. .EXAMPLE $ch1 = "_" $ch2 = "A" $result = hRule2-Smush -ch1 $ch1 -ch2 $ch2 This example does not smush the underscore (`_`) with the character `A` and returns `$false`. .NOTES This function implements Rule 2 of the FIGlet smushing rules: Underscore Smushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function hRule2-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$ch1, [string]$ch2 ) $rule2Str = "|/\[]{}()<>" if ($ch1 -eq "_") { if ($rule2Str.Contains($ch2)) { return $ch2 } } elseif ($ch2 -eq "_") { if ($rule2Str.Contains($ch1)) { return $ch1 } } return $false } <# .SYNOPSIS Applies Rule 3: Hierarchy Smushing. .DESCRIPTION This function smushes two characters based on their hierarchy class according to Rule 3 of the FIGlet smushing rules. A hierarchy of six classes is defined: "|", "/\", "[]", "{}", "()", and "<>". When two smushing characters belong to different classes, the character from the latter class in the hierarchy is used. .PARAMETER ch1 The first character to evaluate for smushing. .PARAMETER ch2 The second character to evaluate for smushing. .EXAMPLE $ch1 = "|" $ch2 = ">" $result = hRule3-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the characters "|" and ">" and returns ">". .EXAMPLE $ch1 = "(" $ch2 = "[" $result = hRule3-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the characters "(" and "[" and returns "[". .EXAMPLE $ch1 = "|" $ch2 = "|" $result = hRule3-Smush -ch1 $ch1 -ch2 $ch2 This example does not smush the characters "|" and "|" because they belong to the same class and returns `$false`. .NOTES This function implements Rule 3 of the FIGlet smushing rules: Hierarchy Smushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function hRule3-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$ch1, [string]$ch2 ) # Define the hierarchy classes explicitly $rule3Classes = @("|", "/", "\", "[", "]", "{", "}", "(", ")", "<", ">") # Get the indices of the characters in the hierarchy $r3_pos1 = $rule3Classes.IndexOf($ch1) $r3_pos2 = $rule3Classes.IndexOf($ch2) # Ensure both characters are in the hierarchy if ($r3_pos1 -ne -1 -and $r3_pos2 -ne -1) { # Check if characters are from different classes if ($r3_pos1 -ne $r3_pos2) { # Return the character from the latter class return $rule3Classes[[math]::Max($r3_pos1, $r3_pos2)] } } return $false } <# .SYNOPSIS Applies Rule 4: Opposite Pair Smushing. .DESCRIPTION This function smushes opposing pairs of brackets (`[]` or `][`), braces (`{}` or `}{`), and parentheses (`()` or `)(`) into a vertical bar (`|`). It checks if the two characters belong to the predefined set of opposing pairs and replaces them with a vertical bar if they meet the criteria. .PARAMETER ch1 The first character to evaluate for smushing. .PARAMETER ch2 The second character to evaluate for smushing. .EXAMPLE $ch1 = "[" $ch2 = "]" $result = hRule4-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the characters `[` and `]` into a vertical bar (`|`). .EXAMPLE $ch1 = "(" $ch2 = ")" $result = hRule4-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the characters `(` and `)` into a vertical bar (`|`). .EXAMPLE $ch1 = "[" $ch2 = "}" $result = hRule4-Smush -ch1 $ch1 -ch2 $ch2 This example does not smush the characters `[` and `}` and returns `$false`. .NOTES This function implements Rule 4 of the FIGlet smushing rules: Opposite Pair Smushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function hRule4-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$ch1, [string]$ch2 ) $rule4Str = "[] {} ()" $r4_pos1 = $rule4Str.IndexOf($ch1) $r4_pos2 = $rule4Str.IndexOf($ch2) if ($r4_pos1 -ne -1 -and $r4_pos2 -ne -1) { if ([math]::Abs($r4_pos1 - $r4_pos2) -le 1) { return "|" } } return $false } <# .SYNOPSIS Applies Rule 5: Big X Smushing. .DESCRIPTION This function smushes specific character pairs into predefined replacements according to Rule 5 of the FIGlet smushing rules. It replaces: - `"/\"` with `"|"`, - `"\\"` with `"Y"`, - `"><"` with `"X"`. If the character pair does not match any of these patterns, the function returns `$false`. .PARAMETER ch1 The first character to evaluate for smushing. .PARAMETER ch2 The second character to evaluate for smushing. .EXAMPLE $ch1 = "/" $ch2 = "\" $result = hRule5-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the characters `"/\"` into `"|"`. .EXAMPLE $ch1 = ">" $ch2 = "<" $result = hRule5-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the characters `"><"` into `"X"`. .EXAMPLE $ch1 = "/" $ch2 = ">" $result = hRule5-Smush -ch1 $ch1 -ch2 $ch2 This example does not smush the characters `"/"` and `">"` and returns `$false`. .NOTES This function implements Rule 5 of the FIGlet smushing rules: Big X Smushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function hRule5-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$ch1, [string]$ch2 ) $rule5Str = "/\ \/ ><" $rule5Hash = @{ 0 = "|" 3 = "Y" 6 = "X" } if($rule5Str.IndexOf($ch1+$ch2) -ge 0) { return $rule5Hash[$rule5Str.IndexOf($ch1+$ch2)] } return $false } <# .SYNOPSIS Applies Rule 6: Hardblank Smushing. .DESCRIPTION This function smushes two hardblanks together into a single hardblank according to Rule 6 of the FIGlet smushing rules. If both characters are hardblanks, they are replaced with a single hardblank. If either character is not a hardblank, the function returns `$false`. .PARAMETER ch1 The first character to evaluate for smushing. .PARAMETER ch2 The second character to evaluate for smushing. .PARAMETER hardBlank The character used to represent hardblanks in FIGlet fonts. .EXAMPLE $ch1 = "@" $ch2 = "@" $hardBlank = "@" $result = hRule6-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $hardBlank This example smushes two hardblanks (`@` and `@`) into a single hardblank (`@`). .EXAMPLE $ch1 = "@" $ch2 = "H" $hardBlank = "@" $result = hRule6-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $hardBlank This example does not smush the characters `@` and `H` because `H` is not a hardblank, and it returns `$false`. .NOTES This function implements Rule 6 of the FIGlet smushing rules: Hardblank Smushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function hRule6-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$ch1, [string]$ch2, [string]$hardBlank ) if ($ch1 -eq $hardBlank -and $ch2 -eq $hardBlank) { return $hardBlank } return $false } <# .SYNOPSIS Measures the execution time of a command or function by marking its start and end points. .DESCRIPTION The Invoke-TimeSignal function is used to measure the time spent executing a specific command or function. It works by marking the start and end points of the execution and calculating the time difference between them. The function uses a global hashtable `$Script:TimeSignals` to store the start time for each command or function. When the `-Start` parameter is used, the function records the current time for the specified command or function. If the command is already being tracked, the start time is updated. When the `-End` parameter is used, the function calculates the elapsed time since the start and logs the result. If the command was not started, a message is logged. .PARAMETER Start Marks the start of the time measurement for the current command or function. .PARAMETER End Marks the end of the time measurement for the current command or function and calculates the elapsed time. .EXAMPLE Invoke-TimeSignal -Start This example marks the start of the time measurement for the current command or function. .EXAMPLE Invoke-TimeSignal -End This example marks the end of the time measurement for the current command or function and logs the elapsed time. .NOTES This function uses the PSFramework module for logging and message handling. Ensure the PSFramework module is installed and imported before using this function. The function relies on a global hashtable `$Script:TimeSignals` to track the start times of commands or functions. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Invoke-TimeSignal { [CmdletBinding(DefaultParameterSetName = 'Start')] param ( [Parameter(Mandatory = $true, ParameterSetName = 'Start', Position = 1 )] [switch] $Start, [Parameter(Mandatory = $True, ParameterSetName = 'End', Position = 2 )] [switch] $End ) $Time = (Get-Date) $Command = (Get-PSCallStack)[1].Command if ($Start) { if ($Script:TimeSignals.ContainsKey($Command)) { Write-PSFMessage -Level Verbose -Message "The command '$Command' was already taking part in time measurement. The entry has been update with current date and time." $Script:TimeSignals[$Command] = $Time } else { $Script:TimeSignals.Add($Command, $Time) } } else { if ($Script:TimeSignals.ContainsKey($Command)) { $TimeSpan = New-TimeSpan -End $Time -Start (($Script:TimeSignals)[$Command]) Write-PSFMessage -Level Verbose -Message "Total time spent inside the function was $TimeSpan" -Target $TimeSpan -FunctionName $Command -Tag "TimeSignal" $null = $Script:TimeSignals.Remove($Command) } else { Write-PSFMessage -Level Verbose -Message "The command '$Command' was never started to take part in time measurement." } } } <# .SYNOPSIS Joins an array of ASCII words or single characters into a single FIGlet line. .DESCRIPTION This function combines an array of ASCII words or single characters into a single FIGlet line. It processes each element in the array and smushes it horizontally with the accumulated result using the specified smushing rules and options. .PARAMETER array An array of ASCII words or single characters. Each element is a hashtable with the following keys: - `fig`: The FIGlet representation of the word or character. - `overlap`: The number of overlapping characters to smush. .PARAMETER len The height of the FIGlet characters (number of rows). .PARAMETER opts A hashtable containing options for smushing, including: - `fittingRules.hLayout`: Specifies the horizontal layout type (e.g., Full, Fitted, ControlledSmushing). - Additional smushing rules for evaluating overlaps. .EXAMPLE $array = @( @{ fig = @("H", "H"); overlap = 1 }, @{ fig = @("e", "e"); overlap = 1 }, @{ fig = @("l", "l"); overlap = 1 }, @{ fig = @("l", "l"); overlap = 1 }, @{ fig = @("o", "o"); overlap = 1 } ) $len = 2 $opts = @{ fittingRules = @{ hLayout = [LayoutType]::ControlledSmushing } } $result = Join-FigArray -array $array -len $len -opts $opts This example joins the characters "H", "e", "l", "l", and "o" into a single FIGlet line. .NOTES This function relies on the `Horizontal-Smush` helper function to smush characters horizontally and the `New-FigChar` function to initialize the accumulator. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Join-FigArray { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [array]$array, # Array of ASCII words or single characters: {fig: array, overlap: number} [int]$len, # Height of the characters (number of rows) [hashtable]$opts # Options object ) $acc = New-FigChar -len $len foreach ($data in $array) { $acc = Horizontal-Smush -textBlock1 $acc -textBlock2 $data.fig -overlap $data.overlap -opts $opts } return $acc } <# .SYNOPSIS Loads a FIGlet font from the specified font path and parses its data. .DESCRIPTION This function loads a FIGlet font file by its name from the configured font path. If the font is already loaded in the global `$Script:FigFonts` hashtable, it retrieves the cached font data. Otherwise, it reads the font file, parses its content, and stores the parsed font options in the global hashtable for future use. .PARAMETER fontName The name of the FIGlet font to load. The font file should have a `.flf` extension and reside in the directory specified by `$Script:FigDefaults.fontPath`. .EXAMPLE $fontName = "Standard" $fontOptions = Load-Font -fontName $fontName This example loads the "Standard" FIGlet font and returns its parsed options. .NOTES This function relies on the `Parse-Font` helper function to parse the font data and extract its options. If the font file cannot be found or an error occurs during loading, the function logs an error message and stops execution. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Load-Font { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$fontName # Name of the font to load ) # Construct the font URL $fontPath = $Script:FigDefaults.fontPath $fontUrl = Join-Path $fontPath "$fontName.flf" # Check if the font already exists in the global $Script:FigFonts hashtable if ($Script:FigFonts["$fontName"]) { return $Script:FigFonts["$fontName"] } # Fetch the font data try { $response = (Get-Content -Path $fontUrl -Raw) if ($response) { # Parse the font and store it in $Script:FigFonts $FontData = $response $fontOptions = Parse-Font -fontName $fontName -fontData $FontData $Script:FigFonts[$fontName] = $fontOptions return $fontOptions } else { throw } } catch { Write-PSFMessage -Level Error -Message "Something went wrong during request to ADO: $($_.ErrorDetails)" -Exception $PSItem.Exception Stop-PSFFunction -Message "Stopping because of errors" throw $($PSItem.Exception) } } <# .SYNOPSIS Creates a new empty ASCII placeholder with the specified number of rows. .DESCRIPTION This function generates an array of empty strings, where the number of elements in the array corresponds to the specified number of rows. It is typically used as a placeholder for FIGlet characters or ASCII art that will be populated later. .PARAMETER len The number of rows to include in the placeholder. Each row is represented as an empty string. .EXAMPLE $placeholder = New-FigChar -len 5 This example creates a placeholder with 5 rows, each represented as an empty string. .NOTES This function is useful for initializing FIGlet character arrays or ASCII art structures. Author: Oleksandr Nikolaiev (@onikolaiev) #> function New-FigChar { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions','')] [OutputType([string[]])] param ( [int]$len # Number of rows ) $outputFigText = @() for ($row = 0; $row -lt $len; $row++) { $outputFigText += "" } return $outputFigText } <# .SYNOPSIS Pads each line in an array of strings with a specified number of spaces. .DESCRIPTION This function takes an array of strings (`lines`) and appends a specified number of spaces (`numSpaces`) to the end of each line. It returns a new array containing the padded lines. .PARAMETER lines An array of strings representing the lines to be padded. .PARAMETER numSpaces The number of spaces to append to the end of each line. .EXAMPLE $lines = @("Line1", "Line2", "Line3") $numSpaces = 4 $paddedLines = Pad-Lines -lines $lines -numSpaces $numSpaces This example pads each line in the array with 4 spaces and returns the padded lines. .NOTES This function creates a new array to store the padded lines and does not modify the original input array. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Pad-Lines { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','')] param ( [string[]]$lines, # Array of lines to pad [int]$numSpaces # Number of spaces to pad ) # Create the padding string $padding = " " * $numSpaces # Create a new array with padded lines $paddedLines = @() foreach ($line in $lines) { $paddedLines += $line + $padding } return $paddedLines } <# .SYNOPSIS Parses data from a FIGlet font file and stores it in the global FIGlet fonts hashtable. .DESCRIPTION This function processes the raw data of a FIGlet font file, normalizes its line endings, and extracts metadata such as height, baseline, layout, and smushing rules. The parsed font data is stored in the global `$Script:FigFonts` hashtable under the specified font name. It also validates the header data to ensure the font file is correctly formatted. .PARAMETER FontName The name of the FIGlet font being parsed. This is used as the key in the `$Script:FigFonts` hashtable. .PARAMETER FontData The raw data of the FIGlet font file as a string. This data is parsed to extract font metadata and options. .EXAMPLE $FontName = "Standard" $FontData = Get-Content -Path "C:\Fonts\Standard.flf" -Raw Parse-Font -FontName $FontName -FontData $FontData This example parses the "Standard" FIGlet font file and stores its metadata and options in the global `$Script:FigFonts` hashtable. .NOTES This function relies on the `Get-SmushingRules` helper function to calculate smushing rules based on the font's layout values. It validates the header data to ensure the font file is properly formatted. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Parse-Font { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$FontName, # Name of the font [string]$FontData # Data from the FIGlet font file ) # Normalize line endings $FontData = "$FontData" -replace "`r`n", "`n" -replace "`r", "`n" $Script:FigFonts[$FontName] = @{} $lines = $FontData -split "`n" $headerData = ($lines[0] -split " ") $lines = $lines[1..($lines.Count - 1)] $figFont = $Script:FigFonts[$FontName] $opts = @{} # Parse header data $opts.hardBlank = $headerData[0].Substring(5, 1) $opts.height = [int]$headerData[1] $opts.baseline = [int]$headerData[2] $opts.maxLength = [int]$headerData[3] $opts.oldLayout = if([int]$headerData[4] -eq 0) { -1 } else { [int]$headerData[4] } $opts.numCommentLines = [int]$headerData[5] $opts.printDirection = if ($headerData.Count -ge 7) { [int]$headerData[6] } else { 0 } $opts.fullLayout = if ($headerData.Count -ge 8) { [int]$headerData[7] } else { $null } $opts.codeTagCount = if ($headerData.Count -ge 9) { [int]$headerData[8] } else { $null } $opts.fittingRules = Get-SmushingRules -oldLayout $opts.oldLayout -fullLayout $opts.fullLayout $figFont.options = $opts # Error check if ( $opts.hardBlank.Length -ne 1 -or -not $opts.height -or -not $opts.baseline -or -not $opts.maxLength -or -not $opts.oldLayout -or -not $opts.numCommentLines ) { throw "FIGlet header contains invalid values." } # Define required character codes $charNums = @(32..126) + @(196, 214, 220, 228, 246, 252, 223) # Error check - validate that there are enough lines in the file if ($lines.Count -lt ($opts.numCommentLines + $opts.height * $charNums.Count)) { throw "FIGlet file is missing data." } # Parse the font data $figFont.comment = ($lines[0..($opts.numCommentLines - 1)] -join "`n") $lines = $lines[$opts.numCommentLines..($lines.Count - 1)] $figFont.numChars = 0 while ($lines.Count -gt 0 -and $figFont.numChars -lt $charNums.Count) { $cNum = $charNums[$figFont.numChars] $figFont[$cNum] = $lines[0..($opts.height - 1)] $lines = $lines[$opts.height..($lines.Count - 1)] # Remove end sub-chars for ($ii = 0; $ii -lt $opts.height; $ii++) { if (-not $figFont[$cNum][$ii]) { $figFont[$cNum][$ii] = "" } else { $endChar = [regex]::Escape($figFont[$cNum][$ii].Substring($figFont[$cNum][$ii].Length - 1, 1)) $figFont[$cNum][$ii] = $figFont[$cNum][$ii] -replace "$endChar+$", "" } } $figFont.numChars++ } # Parse additional characters $parseError = $false while ($lines.Count -gt 0) { $cNum = ($lines[0] -split " ")[0] $lines = $lines[1..($lines.Count - 1)] if ($cNum -match "^0[xX][0-9a-fA-F]+$") { $cNum = [int]::Parse($cNum.Substring(2), [System.Globalization.NumberStyles]::HexNumber) } elseif ($cNum -match "^0[0-7]+$") { $cNum = [int]::Parse($cNum, [System.Globalization.NumberStyles]::None) } elseif ($cNum -match "^[0-9]+$") { $cNum = [int]$cNum } elseif ($cNum -match "^-0[xX][0-9a-fA-F]+$") { $cNum = -[int]::Parse($cNum.Substring(3), [System.Globalization.NumberStyles]::HexNumber) } else { if ($cNum -eq "") { break } Write-PSFMessage -Level Host -Message "Invalid data: $cNum" -ForegroundColor Red $parseError = $true break } $figFont[$cNum] = $lines[0..($opts.height - 1)] $lines = $lines[$opts.height..($lines.Count - 1)] # Remove end sub-chars for ($ii = 0; $ii -lt $opts.height; $ii++) { if (-not $figFont[$cNum][$ii]) { $figFont[$cNum][$ii] = "" } else { $endChar = [regex]::Escape($figFont[$cNum][$ii].Substring($figFont[$cNum][$ii].Length - 1, 1)) $figFont[$cNum][$ii] = $figFont[$cNum][$ii] -replace "$endChar+$", "" } } $figFont.numChars++ } # Error check if ($parseError) { throw "Error parsing data." } return $figFont } <# .SYNOPSIS Merges assigned options with the default font options for a FIGlet font. .DESCRIPTION This function takes the default font options (`fontOpts`) and merges them with the user-specified options (`options`). It overrides the default horizontal and vertical fitting rules if specified, and updates additional font properties such as `printDirection`, `showHardBlanks`, `width`, and `whitespaceBreak`. .PARAMETER fontOpts A hashtable containing the default font options, including fitting rules and other font properties. .PARAMETER options A hashtable containing user-specified options to override the default font options. These may include: - `horizontalLayout`: Specifies the horizontal layout type. - `verticalLayout`: Specifies the vertical layout type. - `printDirection`: The direction in which the text is printed. - `showHardBlanks`: A flag indicating whether to display hard blanks. - `width`: The maximum width of the text. - `whitespaceBreak`: A flag indicating whether to break lines at whitespace. .EXAMPLE $fontOpts = @{ fittingRules = @{ hLayout = "default" vLayout = "default" } printDirection = 0 showHardBlanks = $true width = 80 whitespaceBreak = $true } $options = @{ horizontalLayout = "fitted" verticalLayout = "controlled smushing" printDirection = 1 showHardBlanks = $false width = 100 } $mergedOpts = Rework-FontOpts -fontOpts $fontOpts -options $options This example merges the user-specified options with the default font options and returns the updated options. .NOTES This function relies on the `Get-HorizontalFittingRules` and `Get-VerticalFittingRules` helper functions to calculate the fitting rules for the specified layouts. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Rework-FontOpts { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','')] param ( [hashtable]$fontOpts, # Default font options [hashtable]$options # Assigned options to merge with the defaults ) # Make a copy of the font options $myOpts = $fontOpts.PSObject.Copy() # If the user specifies a horizontal layout, override the default font options if ($options.horizontalLayout) { $params = Get-HorizontalFittingRules -layout $options.horizontalLayout -options $fontOpts foreach ($prop in $params.Keys) { $myOpts.fittingRules[$prop] = $params[$prop] } } # If the user specifies a vertical layout, override the default font options if ($options.verticalLayout) { $params = Get-VerticalFittingRules -layout $options.verticalLayout -options $fontOpts foreach ($prop in $params.Keys) { $myOpts.fittingRules[$prop] = $params[$prop] } } # Set printDirection, showHardBlanks, width, and whitespaceBreak $myOpts.printDirection = if ($options.printDirection) { $options.printDirection } else { $fontOpts.printDirection } $myOpts.showHardBlanks = $options.showHardBlanks -or $false $myOpts.width = if ($options.width) { $options.width } else { -1 } $myOpts.whitespaceBreak = $options.whitespaceBreak -or $false return $myOpts } <# .SYNOPSIS Sets or overrides the default FIGlet font options. .DESCRIPTION This function initializes the global `$Script:FigDefaults` hashtable with default FIGlet font options if it is not already defined. It then merges the user-specified options (`$opts`) into the defaults, overriding any existing properties. The updated defaults are returned as a copy to prevent unintended modifications to the global hashtable. .PARAMETER opts A hashtable containing user-specified properties to override the default FIGlet font options. Supported properties include: - `font`: The name of the default FIGlet font. - `fontPath`: The path to the directory containing FIGlet font files. .EXAMPLE $opts = @{ font = "Big" fontPath = "./custom_fonts" } $updatedDefaults = Set-Defaults -opts $opts This example sets the default font to "Big" and updates the font path to "./custom_fonts". .EXAMPLE $updatedDefaults = Set-Defaults -opts @{} This example returns the current default FIGlet font options without making any changes. .NOTES This function ensures that the global `$Script:FigDefaults` hashtable is always initialized before applying any overrides. It returns a copy of the updated defaults to prevent unintended modifications. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Set-Defaults { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions','')] param ( [hashtable]$opts # Hashtable containing properties to override ) # Ensure $figDefaults is defined globally if (-not $Script:FigDefaults) { $Script:FigDefaults = @{ font = "Standard" fontPath = "$Script:ModuleRoot\internal\misc\Fonts" } } # Override defaults if $opts is a hashtable and not null if ($opts -is [hashtable] -and $opts -ne $null) { foreach ($prop in $opts.Keys) { $Script:FigDefaults[$prop] = $opts[$prop] } } # Return a copy of the updated $figDefaults return $Script:FigDefaults.PSObject.Copy() } <# .SYNOPSIS Combines two sets of FIGlet text lines vertically with optional overlapping smushing. .DESCRIPTION The Smush-VerticalFigLines function takes two sets of FIGlet text lines (`output` and `lines`) and combines them vertically. If the lengths of the lines in the two sets differ, the shorter set is padded with spaces to match the length of the longer set. The function calculates the vertical smush distance using the provided smushing options and applies vertical smushing rules to the overlapping lines. The resulting text is returned as a single array of combined lines. .PARAMETER output An array of strings representing the first set of FIGlet text lines. .PARAMETER lines An array of strings representing the second set of FIGlet text lines. .PARAMETER options A hashtable containing options for vertical smushing, including: - `fittingRules.vLayout`: Specifies the vertical layout type (e.g., Full, Fitted, ControlledSmushing). - Additional smushing rules for evaluating overlaps. .EXAMPLE $output = @( "Hello", "World" ) $lines = @( "Foo", "Bar" ) $options = @{ fittingRules = @{ vLayout = [LayoutType]::ControlledSmushing } } $result = Smush-VerticalFigLines -output $output -lines $lines -options $options This example combines two sets of FIGlet text lines using ControlledSmushing rules. .NOTES This function relies on the following helper functions: - `Pad-Lines`: Pads the shorter set of lines with spaces to match the length of the longer set. - `Get-VerticalSmushDist`: Calculates the vertical smush distance between the two sets of lines. - `Vertical-Smush`: Performs the actual vertical smushing of the two sets of lines. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Smush-VerticalFigLines { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','')] param ( [string[]]$output, # First set of lines [string[]]$lines, # Second set of lines [hashtable]$options # Options for smushing ) # Determine the lengths of the first lines in both arrays $len1 = $output[0].Length $len2 = $lines[0].Length $overlap = 0 # Pad the shorter set of lines to match the length of the longer set if ($len1 -gt $len2) { $lines = Pad-Lines -lines $lines -numSpaces ($len1 - $len2) } elseif ($len2 -gt $len1) { $output = Pad-Lines -lines $output -numSpaces ($len2 - $len1) } # Calculate the vertical smush distance $overlap = Get-VerticalSmushDist -lines1 $output -lines2 $lines -opts $options $lines1 = $output $lines2 = $lines # Perform the vertical smush return Vertical-Smush -lines1 $lines1 -lines2 $lines2 -overlap $overlap -options $options } <# .SYNOPSIS Generates ASCII art text synchronously using a specified FIGlet font and options. .DESCRIPTION This function converts input text into ASCII art using the specified FIGlet font and rendering options. It validates the input, processes the provided options, and generates the ASCII art text by calling helper functions to load the font, rework font options, and render the text. .PARAMETER txt The input text to be converted into ASCII art. .PARAMETER options A hashtable containing font and rendering options. Supported properties include: - `font`: The name of the FIGlet font to use. - Additional font settings such as width, layout, and smushing rules. .EXAMPLE $txt = "Hello, World!" $options = @{ font = "Standard" width = 80 } $asciiArt = Text-Sync -txt $txt -options $options This example generates ASCII art for the text "Hello, World!" using the "Standard" FIGlet font. .EXAMPLE $txt = "Hello, World!" $asciiArt = Text-Sync -txt $txt -options "Standard" This example generates ASCII art for the text "Hello, World!" using the "Standard" FIGlet font by passing the font name directly. .NOTES This function relies on helper functions such as `Rework-FontOpts`, `Load-Font`, and `Generate-Text` to process the font and render the ASCII art. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Text-Sync { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$txt, # Input text [hashtable]$options # Options for font and settings ) # Initialize fontName $fontName = "" # Validate inputs $txt = [string]$txt # Handle options if ($options -is [string]) { $fontName = $options $options = @{} } else { $options = if($options){$options}else{@{}} $fontName = if ($options.font) { $options.font } else { $Script:FigDefaults.font } } # Rework font options $fontOpts = Rework-FontOpts -fontOpts (Load-Font -fontName "$fontName").options -options $options # Generate the ASCII art text return Generate-Text -fontName $fontName -options $fontOpts -txt $txt } <# .SYNOPSIS Applies universal smushing by overlapping two characters. .DESCRIPTION This function implements universal smushing, where the earlier character (`ch1`) is overridden by the later character (`ch2`) to produce an overlapping effect. If the later character is a space or empty, the earlier character is retained. If the later character is a hardblank and the earlier character is not a space, the earlier character is retained. Otherwise, the later character is used. .PARAMETER ch1 The first character to evaluate for smushing. .PARAMETER ch2 The second character to evaluate for smushing. .PARAMETER hardBlank The character used to represent hardblanks in FIGlet fonts. .EXAMPLE $ch1 = "H" $ch2 = "e" $hardBlank = "@" $result = uni-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $hardBlank This example applies universal smushing to the characters "H" and "e", resulting in "e". .EXAMPLE $ch1 = "H" $ch2 = " " $hardBlank = "@" $result = uni-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $hardBlank This example retains the earlier character "H" because the later character is a space. .EXAMPLE $ch1 = "H" $ch2 = "@" $hardBlank = "@" $result = uni-Smush -ch1 $ch1 -ch2 $ch2 -hardBlank $hardBlank This example retains the earlier character "H" because the later character is a hardblank. .NOTES This function implements universal smushing as defined in FIGlet smushing rules. Author: Oleksandr Nikolaiev (@onikolaiev) #> function uni-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$ch1, [string]$ch2, [string]$hardBlank ) if ($ch2 -eq " " -or $ch2 -eq "") { return $ch1 } elseif ($ch2 -eq $hardBlank -and $ch1 -ne " ") { return $ch1 } else { return $ch2 } } <# .SYNOPSIS Combines two sets of text lines vertically with optional overlapping smushing. .DESCRIPTION This function takes two sets of text lines (`lines1` and `lines2`) and combines them vertically. If an overlap is specified, the function applies vertical smushing rules to the overlapping lines using the `Vertically-SmushLines` helper function. The resulting text is returned as a single array of combined lines. .PARAMETER lines1 An array of strings representing the first set of text lines. .PARAMETER lines2 An array of strings representing the second set of text lines. .PARAMETER overlap The number of overlapping lines to smush. If set to 0, no smushing is applied, and the lines are simply concatenated. .PARAMETER opts A hashtable containing options for vertical smushing, including: - `fittingRules.vLayout`: Specifies the vertical layout type (e.g., Full, Fitted, ControlledSmushing). - Additional smushing rules for evaluating overlaps. .EXAMPLE $lines1 = @( "Hello", "World" ) $lines2 = @( "Foo", "Bar" ) $opts = @{ fittingRules = @{ vLayout = [LayoutType]::ControlledSmushing } } $result = Vertical-Smush -lines1 $lines1 -lines2 $lines2 -overlap 2 -opts $opts This example combines two sets of text lines with 2 lines of overlap using ControlledSmushing rules. .NOTES This function relies on the `Vertically-SmushLines` helper function to process overlapping lines and applies the specified smushing rules. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Vertical-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string[]]$lines1, # First set of lines [string[]]$lines2, # Second set of lines [int]$overlap, # Overlap length [hashtable]$opts # Options for smushing ) # Calculate lengths of the input arrays $len1 = $lines1.Count $len2 = $lines2.Count # Split the input arrays into pieces $piece1 = $lines1[0..([math]::Max(0, $len1 - $overlap - 1))] $piece2_1 = $lines1[([math]::Max(0, $len1 - $overlap -1))..($len1)] $piece2_2 = $lines2[0..([math]::Min($overlap, $len2))] # Initialize variables $piece2 = @() # Process the overlapping lines $len = $piece2_1.Count for ($ii = 1; $ii -lt $len; $ii++) { if ($ii -ge $len2) { $line = $piece2_1[$ii] } else { $line = Vertically-SmushLines -line1 $piece2_1[$ii] -line2 $piece2_2[$ii] -opts $opts } $piece2 += $line } # Get the remaining lines from lines2 $piece3 = $lines2[([math]::Min($overlap, $len2))..($len2 - 1)] # Concatenate all pieces and return the result return $piece1 + $piece2 + $piece3 } <# .SYNOPSIS Smushes two lines of text vertically based on specified smushing rules. .DESCRIPTION This function takes two lines of text (`line1` and `line2`) and combines them vertically by applying vertical smushing rules. The smushing behavior is determined by the `vLayout` and individual smushing rules (`vRule1` to `vRule5`) provided in the `opts` parameter. If no valid smushing rule applies, the characters from both lines are retained as-is. .PARAMETER line1 The first line of text to smush. .PARAMETER line2 The second line of text to smush. .PARAMETER opts A hashtable containing smushing options, including: - `fittingRules.vLayout`: Specifies the vertical layout type (e.g., Fitted, UniversalSmushing). - `fittingRules.vRule1` to `vRule5`: Boolean flags indicating which smushing rules to apply. .EXAMPLE $line1 = "Hello" $line2 = "World" $opts = @{ fittingRules = @{ vLayout = [LayoutType]::UniversalSmushing vRule1 = $true vRule2 = $false vRule3 = $true vRule4 = $false vRule5 = $true } } $result = Vertically-SmushLines -line1 $line1 -line2 $line2 -opts $opts This example smushes the lines "Hello" and "World" using UniversalSmushing and the specified smushing rules. .NOTES This function relies on helper functions (`Uni-Smush`, `vRule1-Smush`, `vRule2-Smush`, `vRule3-Smush`, `vRule4-Smush`, and `vRule5-Smush`) to evaluate individual character pairs for smushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Vertically-SmushLines { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','')] param ( [string]$line1, # First line of text [string]$line2, # Second line of text [hashtable]$opts # FIGlet options ) # Determine the minimum length of the two lines $len = [math]::Min($line1.Length, $line2.Length) $result = "" # Iterate through each character in the lines for ($ii = 0; $ii -lt $len; $ii++) { $ch1 = $line1.Substring($ii, 1) $ch2 = $line2.Substring($ii, 1) if ($ch1 -ne " " -and $ch2 -ne " ") { if ($opts.fittingRules.vLayout -eq [LayoutType]::Fitted) { $result += Uni-Smush -ch1 $ch1 -ch2 $ch2 } elseif ($opts.fittingRules.vLayout -eq [LayoutType]::UniversalSmushing) { $result += Uni-Smush -ch1 $ch1 -ch2 $ch2 } else { $validSmush = $false if ($opts.fittingRules.vRule5) { $validSmush = vRule5-Smush -ch1 $ch1 -ch2 $ch2 } if (-not $validSmush -and $opts.fittingRules.vRule1) { $validSmush = vRule1-Smush -ch1 $ch1 -ch2 $ch2 } if (-not $validSmush -and $opts.fittingRules.vRule2) { $validSmush = vRule2-Smush -ch1 $ch1 -ch2 $ch2 } if (-not $validSmush -and $opts.fittingRules.vRule3) { $validSmush = vRule3-Smush -ch1 $ch1 -ch2 $ch2 } if (-not $validSmush -and $opts.fittingRules.vRule4) { $validSmush = vRule4-Smush -ch1 $ch1 -ch2 $ch2 } if ($validSmush) { $result += $validSmush } else { # If no smushing rule applies, append both characters $result += $ch1 + $ch2 } } } else { # If one of the characters is a space, use universal smushing $result += Uni-Smush -ch1 $ch1 -ch2 $ch2 } } return $result } <# .SYNOPSIS Applies Rule 1: Equal Character Smushing for vertical smushing. .DESCRIPTION This function smushes two characters vertically if they are identical. Rule 1, known as "Equal Character Smushing," ensures that identical characters are combined into one. If the characters are not the same, the function returns `$false`. .PARAMETER ch1 The first character to evaluate for vertical smushing. .PARAMETER ch2 The second character to evaluate for vertical smushing. .EXAMPLE $ch1 = "H" $ch2 = "H" $result = vRule1-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the characters "H" and "H" into a single "H". .EXAMPLE $ch1 = "H" $ch2 = "e" $result = vRule1-Smush -ch1 $ch1 -ch2 $ch2 This example does not smush the characters "H" and "e" and returns `$false`. .NOTES This function implements Rule 1 of the FIGlet vertical smushing rules: Equal Character Smushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function vRule1-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$ch1, [string]$ch2 ) if ($ch1 -eq $ch2) { return $ch1 } return $false } <# .SYNOPSIS Applies Rule 2: Underscore Smushing for vertical smushing. .DESCRIPTION This function smushes an underscore (`_`) with specific characters (`|`, `/`, `\`, `[`, `]`, `{`, `}`, `(`, `)`, `<`, `>`) according to Rule 2 of the FIGlet vertical smushing rules. If one of the characters is an underscore and the other is in the allowed set, the underscore is replaced by the other character. .PARAMETER ch1 The first character to evaluate for vertical smushing. .PARAMETER ch2 The second character to evaluate for vertical smushing. .EXAMPLE $ch1 = "_" $ch2 = "|" $result = vRule2-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the underscore (`_`) with the pipe (`|`) and returns `|`. .EXAMPLE $ch1 = "/" $ch2 = "_" $result = vRule2-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the underscore (`_`) with the forward slash (`/`) and returns `/`. .EXAMPLE $ch1 = "_" $ch2 = "A" $result = vRule2-Smush -ch1 $ch1 -ch2 $ch2 This example does not smush the underscore (`_`) with the character `A` and returns `$false`. .NOTES This function implements Rule 2 of the FIGlet vertical smushing rules: Underscore Smushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function vRule2-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$ch1, [string]$ch2 ) $rule2Str = "|/\[]{}()<>" if ($ch1 -eq "_") { if ($rule2Str.Contains($ch2)) { return $ch2 } } elseif ($ch2 -eq "_") { if ($rule2Str.Contains($ch1)) { return $ch1 } } return $false } <# .SYNOPSIS Applies Rule 3: Hierarchy Smushing for vertical smushing. .DESCRIPTION This function smushes two characters vertically based on their hierarchy class according to Rule 3 of the FIGlet vertical smushing rules. A hierarchy of classes is defined: `|`, `/`, `\`, `[`, `]`, `{`, `}`, `(`, `)`, `<`, `>`. When two smushing characters belong to different classes, the character from the latter class in the hierarchy is used. If the characters belong to the same class, the function returns `$false`. .PARAMETER ch1 The first character to evaluate for vertical smushing. .PARAMETER ch2 The second character to evaluate for vertical smushing. .EXAMPLE $ch1 = "|" $ch2 = ">" $result = vRule3-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the characters "|" and ">" and returns ">". .EXAMPLE $ch1 = "(" $ch2 = "[" $result = vRule3-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the characters "(" and "[" and returns "[". .EXAMPLE $ch1 = "|" $ch2 = "|" $result = vRule3-Smush -ch1 $ch1 -ch2 $ch2 This example does not smush the characters "|" and "|" because they belong to the same class and returns `$false`. .NOTES This function implements Rule 3 of the FIGlet vertical smushing rules: Hierarchy Smushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function vRule3-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$ch1, [string]$ch2 ) # Define the hierarchy classes explicitly $rule3Classes = @("|", "/", "\", "[", "]", "{", "}", "(", ")", "<", ">") # Get the indices of the characters in the hierarchy $r3_pos1 = $rule3Classes.IndexOf($ch1) $r3_pos2 = $rule3Classes.IndexOf($ch2) # Ensure both characters are in the hierarchy if ($r3_pos1 -ne -1 -and $r3_pos2 -ne -1) { # Return $false if both characters are the same if ($r3_pos1 -eq $r3_pos2) { return $false } # Return the character from the latter class return $rule3Classes[[math]::Max($r3_pos1, $r3_pos2)] } return $false } <# .SYNOPSIS Applies Rule 4: Horizontal Line Smushing for vertical smushing. .DESCRIPTION This function smushes stacked pairs of `"-"` and `"_"` characters into a single `"="` sub-character according to Rule 4 of the FIGlet vertical smushing rules. The order of the characters does not matter; if one character is `"-"` and the other is `"_"`, they are replaced with `"="`. If the characters do not match this rule, the function returns `$false`. .PARAMETER ch1 The first character to evaluate for vertical smushing. .PARAMETER ch2 The second character to evaluate for vertical smushing. .EXAMPLE $ch1 = "-" $ch2 = "_" $result = vRule4-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the characters `"-"` and `"_"` into `"="`. .EXAMPLE $ch1 = "_" $ch2 = "-" $result = vRule4-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the characters `"_"` and `"-"` into `"="`. .EXAMPLE $ch1 = "-" $ch2 = "|" $result = vRule4-Smush -ch1 $ch1 -ch2 $ch2 This example does not smush the characters `"-"` and `"|"` and returns `$false`. .NOTES This function implements Rule 4 of the FIGlet vertical smushing rules: Horizontal Line Smushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function vRule4-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$ch1, [string]$ch2 ) if (($ch1 -eq "-" -and $ch2 -eq "_") -or ($ch1 -eq "_" -and $ch2 -eq "-")) { return "=" } return $false } <# .SYNOPSIS Applies Rule 5: Vertical Line Supersmushing. .DESCRIPTION This function smushes stacked vertical bars (`|`) into a single vertical bar according to Rule 5 of the FIGlet vertical smushing rules. If both characters are vertical bars, they are replaced with a single vertical bar. If the characters do not match this rule, the function returns `$false`. .PARAMETER ch1 The first character to evaluate for vertical smushing. .PARAMETER ch2 The second character to evaluate for vertical smushing. .EXAMPLE $ch1 = "|" $ch2 = "|" $result = vRule5-Smush -ch1 $ch1 -ch2 $ch2 This example smushes the characters `|` and `|` into a single `|`. .EXAMPLE $ch1 = "|" $ch2 = "-" $result = vRule5-Smush -ch1 $ch1 -ch2 $ch2 This example does not smush the characters `|` and `-` and returns `$false`. .NOTES This function implements Rule 5 of the FIGlet vertical smushing rules: Vertical Line Supersmushing. Author: Oleksandr Nikolaiev (@onikolaiev) #> function vRule5-Smush { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "")] param ( [string]$ch1, [string]$ch2 ) if ($ch1 -eq "|" -and $ch2 -eq "|") { return "|" } return $false } <# .SYNOPSIS Converts a given text into ASCII art using a specified font and customizable options. .DESCRIPTION The Convert-FSCPSTextToAscii function generates ASCII art from the provided text using the specified font. It supports optional customization, including border styles, text and border colors, layout types, and additional formatting options such as showing hard blanks or breaking lines at whitespace. The function is highly configurable and can be used to create visually appealing text banners or decorations for console outputs. The function also supports outputting the ASCII art with or without color to custom variables, allowing for further processing or storage of the generated ASCII art. .PARAMETER Text The text to be converted into ASCII art. This parameter is mandatory. .PARAMETER Font The font to be used for generating the ASCII art. This parameter is mandatory. .PARAMETER BorderType The type of border to apply around the ASCII art. Defaults to `None`. .PARAMETER TextColor The color to use for the ASCII art text. Defaults to `White`. .PARAMETER BorderColor The color to use for the border. Defaults to `Gray`. .PARAMETER Timestamp A switch to include a timestamp in the output. Defaults to `$false`. .PARAMETER VerticalLayout Specifies the vertical layout type for the ASCII art. Defaults to `Default`. .PARAMETER HorizontalLayout Specifies the horizontal layout type for the ASCII art. Defaults to `Default`. .PARAMETER ShowHardBlanks A switch to display hard blanks in the ASCII art. Defaults to `$false`. .PARAMETER WhitespaceBreak A switch to enable breaking lines at whitespace. Defaults to `$false`. .PARAMETER ScreenWigth The maximum width of the screen for rendering the ASCII art. Defaults to `100`. .PARAMETER Padding The padding to apply to the ASCII art. Defaults to `0`. .PARAMETER PrintDirection A switch to specify the print direction of the ASCII art. Defaults to left-to-right. .PARAMETER OutputColorVariable The name of the variable to store the ASCII art with color formatting. .PARAMETER OutputNoColorVariable The name of the variable to store the ASCII art without color formatting. .EXAMPLE PS C:\> Convert-FSCPSTextToAscii -Text "Hello, World!" -Font "Standard" -BorderType Box -TextColor Yellow -BorderColor Blue -Timestamp Converts the text "Hello, World!" into ASCII art using the "Standard" font, applies a box border, and uses yellow text with a blue border. A timestamp is included in the output. .EXAMPLE PS C:\> Convert-FSCPSTextToAscii -Text "PowerShell" -Font "Big" -BorderType Asterisk -TextColor Cyan -BorderColor Green -OutputColorVariable "ColoredOutput" -OutputNoColorVariable "PlainOutput" Converts the text "PowerShell" into ASCII art using the "Big" font, applies an asterisk border, and uses cyan text with a green border. The colored and plain outputs are stored in the variables `ColoredOutput` and `PlainOutput`, respectively. .NOTES This function uses the PSFramework module for logging and configuration management. Ensure the PSFramework module is installed and imported before using this function. Author: Oleksandr Nikolaiev (@onikolaiev) #> function Convert-FSCPSTextToAscii { [CmdletBinding()] [OutputType()] param( [Parameter(Mandatory=$true)] [string]$Text, [Parameter(Mandatory=$true)] [string]$Font, [Parameter(Mandatory=$false)] [BorderType]$BorderType = [BorderType]::None, [Parameter(Mandatory=$false)] [ValidateSet("Black", "DarkBlue", "DarkGreen", "DarkCyan", "DarkRed", "DarkMagenta", "DarkYellow", "Gray", "DarkGray", "Blue", "Green", "Cyan", "Red", "Magenta", "Yellow", "White")] [string]$TextColor = "White", [Parameter(Mandatory=$false)] [ValidateSet("Black", "DarkBlue", "DarkGreen", "DarkCyan", "DarkRed", "DarkMagenta", "DarkYellow", "Gray", "DarkGray", "Blue", "Green", "Cyan", "Red", "Magenta", "Yellow", "White")] [string]$BorderColor = "Gray", [Parameter(Mandatory=$false)] [switch]$Timestamp, [Parameter(Mandatory=$false)] [LayoutType]$VerticalLayout = [LayoutType]::Default, [Parameter(Mandatory=$false)] [LayoutType]$HorizontalLayout = [LayoutType]::Default, [Parameter(Mandatory=$false)] [switch]$ShowHardBlanks, [Parameter(Mandatory=$false)] [switch]$WhitespaceBreak, [Parameter(Mandatory=$false)] [int]$ScreenWigth = 100, [Parameter(Mandatory=$false)] [int]$Padding = 0, [Parameter(Mandatory=$false)] [switch]$PrintDirection, [Parameter(Mandatory=$false)] [string]$OutputColorVariable, [Parameter(Mandatory=$false)] [string]$OutputNoColorVariable ) begin { Invoke-TimeSignal -Start # Save the current state of the PSFramework message style settings $originalTimestampSetting = (Get-PSFConfig -Module PSFramework -Name 'Message.Style.Timestamp').Value $originalFunctionNameSetting = (Get-PSFConfig -Module PSFramework -Name 'Message.Style.FunctionName').Value # Apply the detailed info setting if ($Timestamp) { Set-PSFConfig -Module PSFramework -Name 'Message.Style.Timestamp' -Value $true Set-PSFConfig -Module PSFramework -Name 'Message.Style.FunctionName' -Value $false } else { Set-PSFConfig -Module PSFramework -Name 'Message.Style.Timestamp' -Value $false Set-PSFConfig -Module PSFramework -Name 'Message.Style.FunctionName' -Value $false } $border = Get-BorderSymbol -BorderType $BorderType $_printDirection = 0 if($PrintDirection) { $_printDirection = 1 } } PROCESS { $options = @{ font ="$Font" showHardBlanks = $ShowHardBlanks whitespaceBreak = $WhitespaceBreak verticalLayout = $VerticalLayout horizontalLayout = $HorizontalLayout width = $ScreenWigth printDirection = $_printDirection } # Call the function $outputLines = New-Object System.Collections.Generic.List[string] $resultColorLines = New-Object System.Collections.Generic.List[string] $resultNoColorLines = New-Object System.Collections.Generic.List[string] $null = (Get-FontMetadata -fontName $Font) $arrayLines = (Text-Sync -txt $Text -options $options) foreach ($line in $arrayLines -split "`n") { $outputLines.Add(((' ' * $Padding) + $line + (' ' * $Padding))) } $outputLines = $outputLines -split "`n" # Determine max line length $maxLen = ($outputLines | ForEach-Object { $_.Length } | Measure-Object -Maximum).Maximum # Calculate the total width of the content including side borders $totalWidth = $maxLen if ($BorderType -ne [BorderType]::None) { # Repeat spacer patterns to match the required total width $topBorder = $border.TopSpacer * ([math]::Ceiling($totalWidth / $border.TopSpacer.Length)) $topBorder = $topBorder.Substring(0, $topBorder.Length) # Trim to exact length $bottomBorder = $border.BottomSpacer * [math]::Ceiling($totalWidth / $border.BottomSpacer.Length) $bottomBorder = $bottomBorder.Substring(0, $bottomBorder.Length) # Trim to exact length # Draw top border $topBorderLine = $border.TopLeft + $topBorder + $border.TopRight $topBorderMessageColor = ('<c="'+$BorderColor.ToLower()+'">' + $topBorderLine + "</c>") $topBorderMessageNoColor = ($topBorderLine) $resultColorLines.Add($topBorderMessageColor) $resultNoColorLines.Add($topBorderMessageNoColor) Write-PSFMessage -Level Important -Message $topBorderMessageColor # Draw lines, padding each to the max length foreach ($line in $outputLines) { $curLineLength = $line.Length + $border.LeftSpacer.Length + $border.RightSpacer.Length $curAdvDifference = ($topBorderLine.Length - ($curLineLength)) $padded = $line.PadRight($line.Length + $curAdvDifference) $centerMessageColor = ('<c="'+$BorderColor.ToLower()+'">' + $border.LeftSpacer + "</c>" + '<c="'+$TextColor.ToLower()+'">' + $padded +"</c>" + '<c="'+$BorderColor.ToLower()+'">' + $border.RightSpacer + "</c>") $centerMessageNoColor = ($border.LeftSpacer + $padded + $border.RightSpacer) $resultColorLines.Add($centerMessageColor) $resultNoColorLines.Add($centerMessageNoColor) Write-PSFMessage -Level Important -Message $centerMessageColor } # Draw bottom border $bottomBorderMessageColor = ('<c="'+$BorderColor.ToLower()+'">' + $border.BottomLeft + $bottomBorder + $border.BottomRight + "</c>") $bottomBorderMessageNoColor = ($border.BottomLeft + $bottomBorder + $border.BottomRight) $resultColorLines.Add($bottomBorderMessageColor) $resultNoColorLines.Add($bottomBorderMessageNoColor) Write-PSFMessage -Level Host -Message $bottomBorderMessageColor } else { # Draw lines without borders foreach ($line in $outputLines) { Write-PSFMessage -Level Host -Message (('<c="'+$TextColor.ToLower()+'">' + $line + "</c>")) } } # If the custom output variable is provided, set its value if ($PSBoundParameters.ContainsKey('OutputNoColorVariable') -and $OutputNoColorVariable) { Set-Variable -Name $OutputNoColorVariable -Value $resultNoColorLines -Scope 1 } if ($PSBoundParameters.ContainsKey('OutputColorVariable') -and $OutputColorVariable) { Set-Variable -Name $OutputColorVariable -Value $resultColorLines -Scope 1 } } END { # Restore the original state of the PSFramework message style settings Set-PSFConfig -Module PSFramework -Name 'Message.Style.Timestamp' -Value $originalTimestampSetting Set-PSFConfig -Module PSFramework -Name 'Message.Style.FunctionName' -Value $originalFunctionNameSetting Invoke-TimeSignal -End } } |