Public/Show-Tree.ps1
|
#region Style Profile <# .SYNOPSIS Defines the ANSI color style profile used by Show‑Tree. .DESCRIPTION This profile controls: • Base colors for files, directories, symlinks, junctions • Attribute overlays (Hidden, System, Temporary, etc.) • Foreground overrides for specific attribute/type combinations The profile is consumed by Get-ItemStyle in Show‑TreeInternal.ps1. #> $script:StyleProfile = @{ Base = @{ File = "37" Directory = "36" Symlink = "37" Junction = "36" } Attributes = @{ None = @{ Attributes = "90" } ReadOnly = @{ Attributes = "3" } Hidden = @{ Attributes = "2" } System = @{ OverrideForeground = @{ File = "31" Directory = "35" } } Directory = @{ Attributes = "" } Archive = @{ Attributes = "" } Device = @{ Attributes = "" } Normal = @{ Attributes = "" } Temporary = @{ Attributes = "7" } SparseFile = @{ Attributes = "7" } ReparsePoint = @{ Attributes = "4" } Compressed = @{ Attributes = "" } Offline = @{ Attributes = "7" } NotContentIndexed = @{ Attributes = "" } Encrypted = @{ Attributes = "" } IntegrityStream = @{ Attributes = "" } NoScrubData = @{ Attributes = "" } } } #endregion #region Public Entry Point <# .SYNOPSIS Displays a directory tree in graphical, tree.com, or listing mode. .DESCRIPTION Show‑Tree is the public entry point for the module. It determines: • Which mode is active (Normal, Tree, Listing) • Effective defaults for depth, color, file inclusion, and gaps • Whether to show hidden/system items • Whether to show reparse point targets • Whether to use ASCII or Unicode connectors After computing effective settings, it delegates all rendering to Show‑TreeInternal, which performs recursion, gap logic, and formatting. .PARAMETER Path The root path to display. Defaults to the current directory. .PARAMETER Tree Enables DOS tree.com compatibility mode. .PARAMETER List Enables indentation‑only listing mode. .PARAMETER MaxDepth Maximum recursion depth. -1 means unlimited. .PARAMETER Recurse Shortcut for unlimited depth. .PARAMETER Mono Disable color output. .PARAMETER Color Enable color output in Tree mode. .PARAMETER NoFiles / Files Control whether files are included. .PARAMETER HideHidden / ShowHidden Control visibility of hidden items. .PARAMETER HideSystem / ShowSystem Control visibility of system items. .PARAMETER NoGap Disable gap lines between blocks. .PARAMETER NoTargets / ShowTargets Control whether reparse point targets are shown. .PARAMETER Ascii Use ASCII connectors instead of Unicode. .PARAMETER DebugAttributes Show attribute debug info for each item. .PARAMETER Legend Display a color legend instead of rendering a tree. .EXAMPLE Show-Tree C:\ .EXAMPLE Show-Tree -Tree C:\Windows .EXAMPLE Show-Tree -List -Recurse .NOTES Author: Ryan Beesley Version: 1.1.0 Last Updated: April 2026 #> function Show-Tree { [CmdletBinding(DefaultParameterSetName = 'Normal')] param ( # Root path to display [Parameter(Position = 0, ParameterSetName='Normal')] [Parameter(Position = 0, ParameterSetName='Tree')] [Parameter(Position = 0, ParameterSetName='Listing')] [string]$Path = ".", # Tree.com compatibility mode [Parameter(ParameterSetName='Tree')] [switch]$Tree, # Listing mode (indentation only) [Parameter(ParameterSetName='Listing')] [Alias("Listing")] [switch]$List, # Maximum recursion depth [Parameter(ParameterSetName='Normal')] [Parameter(ParameterSetName='Tree')] [Parameter(ParameterSetName='Listing')] [Alias("Depth")] [int]$MaxDepth = $null, # Unlimited depth [Parameter(ParameterSetName='Normal')] [Parameter(ParameterSetName='Tree')] [Parameter(ParameterSetName='Listing')] [switch]$Recurse, # Disable color [Parameter(ParameterSetName='Normal')] [Parameter(ParameterSetName='Listing')] [Alias("NoColor")] [switch]$Mono, # Enable color in Tree mode [Parameter(ParameterSetName='Tree')] [switch]$Color, # Hide files [Parameter(ParameterSetName='Normal')] [Parameter(ParameterSetName='Listing')] [switch]$NoFiles, # Show files in Tree mode [Parameter(ParameterSetName='Tree')] [switch]$Files, # Hide hidden items [Parameter(ParameterSetName='Normal')] [Parameter(ParameterSetName='Listing')] [switch]$HideHidden, # Show hidden items in Tree mode [Parameter(ParameterSetName='Tree')] [switch]$ShowHidden, # Hide system items [Parameter(ParameterSetName='Normal')] [Parameter(ParameterSetName='Listing')] [switch]$HideSystem, # Show system items in Tree mode [Parameter(ParameterSetName='Tree')] [switch]$ShowSystem, # Disable gap lines [Parameter(ParameterSetName='Normal')] [Parameter(ParameterSetName='Tree')] [switch]$NoGap, # Disable reparse point targets [Parameter(ParameterSetName='Normal')] [Parameter(ParameterSetName='Tree')] [switch]$NoTargets, # Show reparse point targets in Listing mode [Parameter(ParameterSetName='Listing')] [switch]$ShowTargets, # ASCII connectors [Parameter(ParameterSetName='Normal')] [Parameter(ParameterSetName='Tree')] [switch]$Ascii, # Show attribute debug info [Parameter(ParameterSetName='Normal')] [Parameter(ParameterSetName='Tree')] [Parameter(ParameterSetName='Listing')] [switch]$DebugAttributes, # Show color legend [switch]$Legend ) # # Legend mode: no tree rendering # if ($Legend) { Show-TreeLegend return } # # Compute effective mode settings # if ($PSCmdlet.ParameterSetName -eq 'Tree') { $EffectiveMaxDepth = $PSBoundParameters.ContainsKey('MaxDepth') ? $MaxDepth : -1 $EffectiveColorize = $Color.IsPresent $EffectiveFiles = $Files.IsPresent $EffectiveHideHidden = -not $ShowHidden.IsPresent $EffectiveHideSystem = -not $ShowSystem.IsPresent $EffectiveShowTargets = -not $NoTargets.IsPresent $EffectiveGap = -not $NoGap } elseif ($PSCmdlet.ParameterSetName -eq 'Listing') { $EffectiveMaxDepth = $PSBoundParameters.ContainsKey('MaxDepth') ? $MaxDepth : -1 $EffectiveColorize = -not $Mono $EffectiveFiles = -not $NoFiles $EffectiveHideHidden = $HideHidden.IsPresent $EffectiveHideSystem = $HideSystem.IsPresent $EffectiveShowTargets = $ShowTargets.IsPresent $EffectiveGap = $false } else { # Normal mode $EffectiveMaxDepth = $Recurse.IsPresent ? -1 : ($PSBoundParameters.ContainsKey('MaxDepth') ? $MaxDepth : 6) $EffectiveColorize = -not $Mono $EffectiveFiles = -not $NoFiles $EffectiveHideHidden = $HideHidden.IsPresent $EffectiveHideSystem = $HideSystem.IsPresent $EffectiveShowTargets = -not $NoTargets.IsPresent $EffectiveGap = -not $NoGap } # # Resolve the path (with proper error record) # try { $resolved = Resolve-Path -LiteralPath $Path -ErrorAction Stop $Path = $resolved.ProviderPath } catch { $msg = "Cannot find path '$Path' because it does not exist." $exception = New-Object System.Management.Automation.ItemNotFoundException $msg $category = [System.Management.Automation.ErrorCategory]::ObjectNotFound $errorRecord = New-Object System.Management.Automation.ErrorRecord ` $exception, 'ItemNotFound', $category, $Path $PSCmdlet.WriteError($errorRecord) return } # # Delegate to internal engine # Show-TreeInternal ` -Path $Path ` -Tree:$Tree ` -List:$List ` -MaxDepth $EffectiveMaxDepth ` -Colorize:$EffectiveColorize ` -IncludeFiles:$EffectiveFiles ` -HideHidden:$EffectiveHideHidden ` -HideSystem:$EffectiveHideSystem ` -ShowTargets:$EffectiveShowTargets ` -Gap:$EffectiveGap ` -Ascii:$Ascii ` -DebugAttributes:$DebugAttributes } #endregion #region Legend Rendering <# .SYNOPSIS Displays a color legend for all base types and attribute overlays. .DESCRIPTION Useful for understanding how Show‑Tree applies color to files, directories, symlinks, junctions, and attribute combinations. #> function Show-TreeLegend { param( $StyleProfile = $script:StyleProfile ) $esc = [char]27 $reset = "${esc}[0m" Write-Output "" Write-Output "Legend" Write-Output "------" Write-Output "" # # Helper to render a sample line # function Show-Sample { param( [string]$Name, $Item ) $style = Get-ItemStyle -Item $Item -Colorize:$true $ansi = $style.Ansi Write-Output ("{0,-18} {1}{2}{3}" -f $Name, $ansi, $Name, $reset) } # # Base types # Write-Output "Types:" Show-Sample "Directory" ([pscustomobject]@{ PSIsContainer = $true; Attributes = [IO.FileAttributes]::Directory }) Show-Sample "File" ([pscustomobject]@{ PSIsContainer = $false; Attributes = [IO.FileAttributes]::Archive }) Show-Sample "Symlink" ([pscustomobject]@{ PSIsContainer = $false; Attributes = [IO.FileAttributes]::ReparsePoint }) Show-Sample "Junction" ([pscustomobject]@{ PSIsContainer = $true; Attributes = [IO.FileAttributes]::Directory -bor [IO.FileAttributes]::ReparsePoint }) Write-Output "" # # Attribute overlays # Write-Output "Attributes:" foreach ($attr in $StyleProfile.Attributes.Keys) { $flag = [IO.FileAttributes]::$attr $item = [pscustomobject]@{ PSIsContainer = $false Attributes = $flag } Show-Sample $attr $item } Write-Output "" } #endregion |