Private/Console/Write-SpectreTree.ps1
|
# PSGuerrilla - Jim Tyler, Microsoft MVP - CC BY 4.0 # https://github.com/jimrtyler/PSGuerrilla | https://creativecommons.org/licenses/by/4.0/ # AI/LLM use: see AI-USAGE.md for required attribution function Write-SpectreTree { <# .SYNOPSIS Renders a themed tree view using Spectre.Console when available, falling back to indented text. .PARAMETER RootLabel The root node label. .PARAMETER RootColor Guerrilla color for the root node. Default: 'Parchment'. .PARAMETER Children Array of child hashtables: @{ Label = 'Node'; Color = 'Olive'; Children = @(...) } Children can be nested recursively. .PARAMETER GuideColor Guerrilla color for the tree guide lines. Default: 'Dim'. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$RootLabel, [string]$RootColor = 'Parchment', [Parameter(Mandatory)] [hashtable[]]$Children, [string]$GuideColor = 'Dim' ) if ($script:HasSpectre) { Write-SpectreTreeEnhanced @PSBoundParameters } else { Write-SpectreTreeFallback @PSBoundParameters } } function Write-SpectreTreeEnhanced { [CmdletBinding()] param( [string]$RootLabel, [string]$RootColor = 'Parchment', [hashtable[]]$Children, [string]$GuideColor = 'Dim' ) $rColor = $script:SpectreColors[$RootColor] ?? $script:SpectreColors.Parchment $gColor = $script:SpectreColors[$GuideColor] ?? $script:SpectreColors.Dim $escapedRoot = [Spectre.Console.Markup]::Escape($RootLabel) $rootMarkup = [Spectre.Console.Markup]::new("[bold $($rColor.ToMarkup())]$escapedRoot[/]") $tree = [Spectre.Console.Tree]::new($rootMarkup) $tree.Guide = [Spectre.Console.TreeGuide]::Line $tree.GuideColor($gColor) | Out-Null foreach ($child in $Children) { Add-SpectreTreeNode -Parent $tree -Node $child } [Spectre.Console.AnsiConsole]::Write($tree) } function Add-SpectreTreeNode { [CmdletBinding()] param( [object]$Parent, [hashtable]$Node ) $nodeColor = $script:SpectreColors[$Node.Color] ?? $script:SpectreColors.Olive $escapedLabel = [Spectre.Console.Markup]::Escape($Node.Label) $markup = [Spectre.Console.Markup]::new("[$($nodeColor.ToMarkup())]$escapedLabel[/]") $treeNode = $Parent.AddNode($markup) if ($Node.Children) { foreach ($child in $Node.Children) { Add-SpectreTreeNode -Parent $treeNode -Node $child } } } function Write-SpectreTreeFallback { [CmdletBinding()] param( [string]$RootLabel, [string]$RootColor = 'Parchment', [hashtable[]]$Children, [string]$GuideColor = 'Dim' ) Write-GuerrillaText " $RootLabel" -Color $RootColor -Bold for ($i = 0; $i -lt $Children.Count; $i++) { $isLast = ($i -eq $Children.Count - 1) Write-TreeNodeFallback -Node $Children[$i] -Prefix ' ' -IsLast $isLast -GuideColor $GuideColor } } function Write-TreeNodeFallback { [CmdletBinding()] param( [hashtable]$Node, [string]$Prefix, [bool]$IsLast, [string]$GuideColor = 'Dim' ) $connector = if ($IsLast) { "$([char]0x2514)$([char]0x2500) " } else { "$([char]0x251C)$([char]0x2500) " } $color = $Node.Color ?? 'Olive' Write-GuerrillaText $Prefix -Color $GuideColor -NoNewline Write-GuerrillaText $connector -Color $GuideColor -NoNewline Write-GuerrillaText $Node.Label -Color $color if ($Node.Children -and $Node.Children.Count -gt 0) { $childPrefix = $Prefix + $(if ($IsLast) { ' ' } else { "$([char]0x2502) " }) for ($i = 0; $i -lt $Node.Children.Count; $i++) { $childIsLast = ($i -eq $Node.Children.Count - 1) Write-TreeNodeFallback -Node $Node.Children[$i] -Prefix $childPrefix -IsLast $childIsLast -GuideColor $GuideColor } } } |