Private/PowerTree/Output/Get-TreeView.ps1

function Get-TreeView {
    param (
        [Parameter(Mandatory=$true)]
        [TreeConfig]$TreeConfig,
        [Parameter(Mandatory=$true)]
        [hashtable]$ChildItemDirectoryParams,
        [Parameter(Mandatory=$true)]
        [hashtable]$ChildItemFileParams,
        [Parameter(Mandatory=$true)]
        [TreeStats]$TreeStats,
        [string]$CurrentPath = $TreeConfig.Path,
        [string]$TreeIndent = "",
        [bool]$Last = $false,
        [bool]$IsRoot = $true,
        [int]$CurrentDepth = 0,
        [Parameter(Mandatory=$false)]
        [System.Text.StringBuilder]$OutputBuilder = $null,
        [Parameter(Mandatory=$false)]
        [switch]$IsEmptyCheck = $false
    )

    if ($TreeConfig.MaxDepth -ne -1 -and $CurrentDepth -ge $TreeConfig.MaxDepth) {
        return $false
    }

    if ($IsRoot) {
        $TreeStats.MaxDepth += 1
    }
    
    $TreeStats.UpdateMaxDepth($CurrentDepth)

    # Get directories filtering out excluded directories
    $dirItems = Get-ChildItem @ChildItemDirectoryParams -LiteralPath $CurrentPath
    $directories = if ($null -ne $dirItems -and $dirItems.Count -gt 0) {
        $filteredDirs = $dirItems | Where-Object {
            $TreeConfig.ExcludeDirectories.Count -eq 0 -or $TreeConfig.ExcludeDirectories -notcontains $_.Name
        }
        
        if ($null -ne $filteredDirs -and $filteredDirs.Count -gt 0) {
            if ($TreeConfig.SortFolders) {
                Group-Items -Items $filteredDirs -SortBy $TreeConfig.SortBy -SortDescending $TreeConfig.SortDescending
            } else {
                $filteredDirs
            }
        } else {
            @()
        }
    } else {
        @()
    }

    $files = if (-not $TreeConfig.DirectoryOnly) { 
        $fileList = Get-ChildItem -LiteralPath $CurrentPath @ChildItemFileParams 
        
        if ($null -ne $fileList -and $fileList.Count -gt 0) {
            $filteredBySize = Get-FilesByFilteredSize $fileList -FileSizeBounds $TreeConfig.FileSizeBounds
            Group-Items -Items $filteredBySize -SortBy $TreeConfig.SortBy -SortDescending $TreeConfig.SortDescending
        } else {
            @()
        }
    } else { 
        @() 
    }

    # Return true immediately if this is just an empty check and we have files
    if ($IsEmptyCheck -and -not $TreeConfig.DirectoryOnly -and $files.Count -gt 0) {
        return $true
    }

    # If this is just an empty check and we have no files but we do have directories,
    # we need to check if any of those directories are non-empty after filtering
    if ($IsEmptyCheck -and $files.Count -eq 0 -and $directories.Count -gt 0) {
        foreach ($dir in $directories) {
            $dirHasContent = Get-TreeView -TreeConfig $TreeConfig `
                          -TreeStats $TreeStats `
                          -ChildItemDirectoryParams $ChildItemDirectoryParams `
                          -ChildItemFileParams $ChildItemFileParams `
                          -CurrentPath $dir.FullName `
                          -TreeIndent "" `
                          -Last $false `
                          -IsRoot $false `
                          -CurrentDepth ($CurrentDepth + 1) `
                          -OutputBuilder $null `
                          -IsEmptyCheck:$true
                          
            if ($dirHasContent) {
                return $true
            }
        }
        # If we get here, all subdirectories were empty or filtered out
        return $false
    }
    
    # For empty check with no files and no directories, return false
    if ($IsEmptyCheck -and $files.Count -eq 0 -and $directories.Count -eq 0) {
        return $false
    }
    
    # Initialize the hasVisibleContent variable - true if we have visible files
    $hasVisibleContent = (-not $TreeConfig.DirectoryOnly -and $files.Count -gt 0)

    # Filter directories for pruning if enabled
    $visibleDirectories = @()
    if ($directories.Count -gt 0) {
        foreach ($dir in $directories) {
            $skipDir = $false
            if ($TreeConfig.PruneEmptyFolders) {
                $dirHasContent = Get-TreeView -TreeConfig $TreeConfig `
                              -TreeStats $TreeStats `
                              -ChildItemDirectoryParams $ChildItemDirectoryParams `
                              -ChildItemFileParams $ChildItemFileParams `
                              -CurrentPath $dir.FullName `
                              -TreeIndent "" `
                              -Last $false `
                              -IsRoot $false `
                              -CurrentDepth ($CurrentDepth + 1) `
                              -OutputBuilder $null `
                              -IsEmptyCheck:$true
                
                if (-not $dirHasContent) {
                    $skipDir = $true
                }
            }
            
            if (-not $skipDir) {
                $visibleDirectories += $dir
                $hasVisibleContent = $true
            }
        }
    }

    # Calculate total items and process them in the correct order
    $totalItems = $files.Count + $visibleDirectories.Count
    $currentItemIndex = 0

    # Process files first (they appear before directories in tree output)
    if (-not $TreeConfig.DirectoryOnly -and $files.Count -gt 0) {
        foreach ($file in $files) {
            $currentItemIndex++
            $isLastItem = ($currentItemIndex -eq $totalItems)
            
            # Build the tree prefix for files
            $treeBranch = if ($isLastItem) { $TreeConfig.lineStyle.LastBranch } else { $TreeConfig.lineStyle.Branch }
            $treePrefix = if ($IsRoot) { $treeBranch } else { "$TreeIndent$treeBranch" }
            
            $outputInfo = Build-OutputLine -HeaderTable $TreeConfig.HeaderTable `
                                        -Item $file `
                                        -TreePrefix $treePrefix `
                                        -HumanReadableSizes $TreeConfig.HumanReadableSizes

            if ($outputInfo.SizeColor -and $outputInfo.SizePosition -ge 0 -and $outputInfo.SizeLength -gt 0) {
                $before = $outputInfo.Line.Substring(0, $outputInfo.SizePosition)
                $size = $outputInfo.Line.Substring($outputInfo.SizePosition, $outputInfo.SizeLength)
                $after = $outputInfo.Line.Substring($outputInfo.SizePosition + $outputInfo.SizeLength)
                
                if ($null -ne $OutputBuilder) {
                    [void]$OutputBuilder.AppendLine($outputInfo.Line)
                } else {
                    Write-Host $before -NoNewline
                    Write-Host $size -ForegroundColor $outputInfo.SizeColor -NoNewline
                    Write-Host $after
                }
            } else {
                Write-OutputLine -Line $outputInfo.Line `
                                 -OutputBuilder $OutputBuilder
            }
            
            $TreeStats.AddFile($file)
        }
    }

    # Process directories
    foreach ($dir in $visibleDirectories) {
        $currentItemIndex++
        $isLastItem = ($currentItemIndex -eq $totalItems)
      
        # Print connector line to make it look prettier, can be turned on/off in settings
        if($TreeConfig.ShowConnectorLines -and $files.Count -gt 0) {
            $hierarchyPos = $TreeConfig.HeaderTable.Indentations["Hierarchy"]
            $connector = " " * $hierarchyPos + "$TreeIndent$($TreeConfig.lineStyle.Vertical)"
            Write-OutputLine -Line $connector `
                             -OutputBuilder $OutputBuilder 
        }

        # Create the directory prefix with appropriate tree symbols
        $treeBranch = if ($isLastItem) { $TreeConfig.lineStyle.LastBranch } else { $TreeConfig.lineStyle.Branch }
        $treePrefix = if ($IsRoot) { $treeBranch } else { "$TreeIndent$treeBranch" }
        
        # Build and output the directory line
        $outputInfo = Build-OutputLine -HeaderTable $TreeConfig.HeaderTable `
                                    -Item $dir `
                                    -TreePrefix $treePrefix `
                                    -HumanReadableSizes $TreeConfig.HumanReadableSizes

        Write-OutputLine -Line $outputInfo.Line `
                         -OutputBuilder $OutputBuilder
                         
        $TreeStats.FoldersPrinted++
        
        # Use the already calculated folder size for the stats
        if ($outputInfo.DirSize -gt 0) {
            $TreeStats.UpdateLargestFolder($dir.FullName, $outputInfo.DirSize)
        }

        # Calculate the new tree indent for child items
        $newTreeIndent = if ($IsRoot) {
            if ($isLastItem) { $TreeConfig.lineStyle.Space } else { $TreeConfig.lineStyle.VerticalLine }
        } else {
            if ($isLastItem) { "$TreeIndent$($TreeConfig.lineStyle.Space)" } else { "$TreeIndent$($TreeConfig.lineStyle.VerticalLine)" }
        }

        # Recursively process the directory
        Get-TreeView -TreeConfig $TreeConfig `
                     -TreeStats $TreeStats `
                     -ChildItemDirectoryParams $ChildItemDirectoryParams `
                     -ChildItemFileParams $ChildItemFileParams `
                     -CurrentPath $dir.FullName `
                     -TreeIndent $newTreeIndent `
                     -Last $isLastItem `
                     -IsRoot $false `
                     -CurrentDepth ($CurrentDepth + 1) `
                     -OutputBuilder $OutputBuilder
    }
    
    # Return whether this directory has any visible content after filtering
    return $hasVisibleContent
}