Private/Show-TreeInternal.ps1
|
# Show-Tree\Private\Show-TreeInternal.ps1 #region Entry Point <# .SYNOPSIS Core recursive engine for Show-Tree. .DESCRIPTION This function renders a directory tree using graphical connectors, optional color, optional file inclusion, and optional gap logic. It is called once from Show-Tree.ps1 and then recursively by itself. Responsibilities: • Normalize and validate the root path • Initialize gap state • Enumerate directories/files (raw Win32 or PowerShell) • Applies stable-order filtering using Get-FilteredTreeItems (Hidden/System/Include/Exclude with exact/glob precedence) • Render files, directories, and gap lines • Manage recursion depth and prefix construction • Maintain gap-mode state machine (Internal, Tail, Sibling) This function is internal-only and not exported. #> enum GapMode { None Internal Tail Sibling } function Show-TreeInternal { [CmdletBinding()] param ( # Absolute or relative path to render [string]$Path, # Output mode [ValidateSet('Normal','Tree','List')] [string]$Mode = 'Normal', # Maximum recursion depth (-1 = unlimited) [int]$MaxDepth = -1, # Enable color output [switch]$Colorize, # Include files in output [switch]$IncludeFiles, # Hide hidden items [switch]$HideHidden, # Hide system items [switch]$HideSystem, # Show reparse point targets [switch]$ShowTargets, # Glob-based include/exclude filtering [string[]]$Exclude, [string[]]$Include, # Enable gap logic (blank lines between blocks) [switch]$Gap, # Use ASCII connectors instead of Unicode [switch]$Ascii, # Show attribute debug info [switch]$DebugAttributes, # Current recursion depth (internal) [int]$CurrentDepth = 0, # Prefix string built from parent connectors [string]$Prefix = "", # Whether the parent directory was the last sibling [bool]$IsLastParent = $false ) # # Depth cap enforcement # if ($MaxDepth -ne -1 -and $CurrentDepth -ge $MaxDepth) { return } # # Directory enumeration # if ($Mode -eq 'Tree') { # Raw Win32 enumeration for Tree.com compatibility $raw = Get-RawDirectoryEntries -Path $Path $files = $IncludeFiles ? $raw.Files : @() $dirs = $raw.Directories } else { # Standard PowerShell enumeration $files = $IncludeFiles ? (Get-ChildItem -Path $Path -File -Force -ErrorAction SilentlyContinue) : @() $dirs = Get-ChildItem -Path $Path -Directory -Force -ErrorAction SilentlyContinue } # # Filtering # $dirs = Get-FilteredTreeItems -Items $dirs -Include $Include -Exclude $Exclude -HideHidden:$HideHidden -HideSystem:$HideSystem $files = Get-FilteredTreeItems -Items $files -Include $Include -Exclude $Exclude -HideHidden:$HideHidden -HideSystem:$HideSystem $fileCount = $files.Count $dirCount = $dirs.Count # Tree.com: suppress file connectors when no subdirectories exist $noSpan = $Mode -eq 'Tree' -and $dirCount -eq 0 # # FILE RENDERING # for ($j = 0; $j -lt $fileCount; $j++) { $file = $files[$j] $isLastFile = ($j -eq $fileCount - 1) -and ($dirCount -eq 0) Write-TreeItem ` -Item $file ` -Type File ` -Prefix $Prefix ` -IsLast $isLastFile ` -Mode $Mode ` -Ascii:$Ascii ` -Colorize:$Colorize ` -ShowTargets:$ShowTargets ` -DebugAttributes:$DebugAttributes ` -Recurse:$false ` -NoSpan $noSpan ` -MaxDepth $MaxDepth ` -CurrentDepth $CurrentDepth ` -IncludeFiles:$IncludeFiles ` -Include $Include ` -Exclude $Exclude ` -Gap:$Gap ` -HideHidden:$HideHidden ` -HideSystem:$HideSystem } # # INTERNAL GAP (files → directories) # # Precompute ANSI sequences $esc = [char]27 $colorReset = $Colorize ? "${esc}[0m" : "" $colorGap = $Colorize ? "${esc}[90m" : "" # Precompute gap connector $gapConnector = Get-Connector -Type Gap -Mode $Mode -Ascii:$Ascii if ($Gap -and $script:GapState.LastGapMode -eq [GapMode]::None -and $IncludeFiles -and $fileCount -gt 0) { if ($dirCount -gt 0) { # Files + directories → connector gap Write-Gap $colorGap $Prefix $gapConnector $colorReset ([GapMode]::Internal) } else { # Files only → tail gap if ($Mode -eq 'Tree' -or (-not $IsLastParent)) { Write-Gap $colorGap $Prefix $null $colorReset ([GapMode]::Tail) } } } # # DIRECTORY RENDERING # for ($i = 0; $i -lt $dirCount; $i++) { $dir = $dirs[$i] $isLastDir = ($i -eq $dirCount - 1) Write-TreeItem ` -Item $dir ` -Type Directory ` -Prefix $Prefix ` -IsLast $isLastDir ` -Mode $Mode ` -Ascii:$Ascii ` -Colorize:$Colorize ` -ShowTargets:$ShowTargets ` -DebugAttributes:$DebugAttributes ` -Recurse ` -NoSpan $false ` -MaxDepth $MaxDepth ` -CurrentDepth $CurrentDepth ` -IncludeFiles:$IncludeFiles ` -Include $Include ` -Exclude $Exclude ` -Gap:$Gap ` -HideHidden:$HideHidden ` -HideSystem:$HideSystem # # SIBLING / COUSIN GAP LOGIC # if ($Gap -and $i -lt $dirCount - 1) { # Tail gap suppresses immediate sibling gap if ($script:GapState.LastGapMode -eq [GapMode]::Tail) { $script:GapState.LastGapMode = [GapMode]::None continue } # Prevent consecutive gaps if ($script:GapState.LastGapMode -ne [GapMode]::None) { continue } # Normal mode: only if left sibling has visible children if ($Mode -ne 'Tree') { if (Test-HasChildrenForGap -Dir $dirs[$i] -CurrentDepth $CurrentDepth -MaxDepth $MaxDepth) { Write-Gap $colorGap $Prefix $gapConnector $colorReset ([GapMode]::Sibling) } } } } } #endregion |