Public/Table.ps1


function New-RichTable {
    <#
    .SYNOPSIS
        Creates a new Rich Table object.
    .DESCRIPTION
        Initializes a table object that can be customized with columns and rows, and then rendered to the console.
    .PARAMETER Title
        An optional title for the table.
    .PARAMETER HeaderStyle
        The style for the table header. Defaults to "bold magenta".
    .PARAMETER BorderStyle
        The style for the table borders. Defaults to "white".
    .PARAMETER ShowHeader
        Whether to display the header row. Defaults to $true.
    .PARAMETER Border
        The border style: "rounded", "simple", or "none". Defaults to "rounded".
    .PARAMETER Columns
        Legacy support: A list of column headers.
    .PARAMETER Rows
        Legacy support: A list of rows (arrays of values).
    .EXAMPLE
        $table = New-RichTable -Title "Process List"
        $null = New-RichTableColumn -Table $table -Header "Name"
        $null = New-RichTableColumn -Table $table -Header "ID"
        Add-RichTableRow -Table $table -Values @("pwsh", 1234)
        $table | Write-Rich
    #>

    param(
        [string]$Title,
        [string]$HeaderStyle = "bold magenta",
        [string]$BorderStyle = "white",
        [bool]$ShowHeader = $true,
        [string]$Border = "rounded", # rounded, simple, none
        
        # Legacy support for the old signature
        [string[]]$Columns,
        [array]$Rows
    )

    $table = [PSCustomObject]@{
        _Type       = "RichTable"
        Title       = $Title
        HeaderStyle = $HeaderStyle
        BorderStyle = $BorderStyle
        ShowHeader  = $ShowHeader
        Border      = $Border
        Columns     = [System.Collections.Generic.List[object]]::new()
        Rows        = [System.Collections.Generic.List[array]]::new()
    }

    # Handle legacy parameters
    if ($Columns) {
        foreach ($col in $Columns) {
            $null = New-RichTableColumn -Table $table -Header $col
        }
    }

    if ($Rows) {
        foreach ($row in $Rows) {
            $null = Add-RichTableRow -Table $table -Values $row
        }
    }

    return $table
}

function New-RichTableColumn {
    <#
    .SYNOPSIS
        Adds a column definition to a Rich Table.
    .DESCRIPTION
        Defines a column with header text, width, style, and justification.
    .PARAMETER Table
        The table object to add the column to.
    .PARAMETER Header
        The header text for the column.
    .PARAMETER Width
        An optional fixed width for the column.
    .PARAMETER Style
        The style for the column content.
    .PARAMETER Justify
        The text justification: "Left", "Right", or "Center". Defaults to "Left".
    #>

    param(
        [Parameter(Mandatory = $true)]
        $Table,

        [string]$Header = "",
        [int]$Width = 0,
        [string]$Style = "",
        [string]$Justify = "Left"
    )

    $column = [PSCustomObject]@{
        Header  = $Header
        Width   = $Width
        Style   = $Style
        Justify = $Justify
    }

    $Table.Columns.Add($column)
    return $column
}

function Add-RichTableRow {
    <#
    .SYNOPSIS
        Adds a row of data to a Rich Table.
    .DESCRIPTION
        Appends a row of values to the specified table.
    .PARAMETER Table
        The table object to add the row to.
    .PARAMETER Values
        An array of values for the row.
    #>

    param(
        [Parameter(Mandatory = $true)]
        $Table,

        [Parameter(Mandatory = $true)]
        [array]$Values
    )

    $Table.Rows.Add($Values)
}

function Format-RichTable {
    <#
    .SYNOPSIS
        Renders a Rich Table to a string.
    .DESCRIPTION
        Calculates column widths and renders the table with borders and styles into a single string.
    .PARAMETER Table
        The table object to render.
    #>

    param(
        [Parameter(Mandatory = $true)]
        $Table
    )

    if ($Table.Columns.Count -eq 0) { return "" }

    $colCount = $Table.Columns.Count
    $widths = New-Object int[] $colCount

    # Calculate widths
    for ($i = 0; $i -lt $colCount; $i++) {
        $col = $Table.Columns[$i]
        $widths[$i] = [Math]::Max($col.Width, (Get-VisibleLength (Convert-RichMarkup -InputString $col.Header)))
    }

    foreach ($row in $Table.Rows) {
        for ($i = 0; $i -lt $colCount; $i++) {
            if ($i -lt $row.Count) {
                $len = Get-VisibleLength (Convert-RichMarkup -InputString ($row[$i].ToString()))
                if ($len -gt $widths[$i]) {
                    $widths[$i] = $len
                }
            }
        }
    }

    $output = New-Object System.Collections.Generic.List[string]

    if ($Table.Title) {
        $output.Add((Format-RichText -Text " $($Table.Title)" -Style "bold underline"))
    }

    # Border characters
    $chars = @{
        top_left     = "┌"; top_mid = "┬"; top_right = "┐"
        mid_left     = "├"; mid_mid = "┼"; mid_right = "┤"
        bottom_left  = "└"; bottom_mid = "┴"; bottom_right = "┘"
        v            = "│"; h = "─"
    }

    if ($Table.Border -eq "simple") {
        $chars = @{
            top_left     = " "; top_mid = " "; top_right = " "
            mid_left     = " "; mid_mid = "─"; mid_right = " "
            bottom_left  = " "; bottom_mid = "─"; bottom_right = " "
            v            = " "; h = "─"
        }
    }
    elseif ($Table.Border -eq "none") {
        $chars = @{
            top_left     = ""; top_mid = ""; top_right = ""
            mid_left     = ""; mid_mid = ""; mid_right = ""
            bottom_left  = ""; bottom_mid = ""; bottom_right = ""
            v            = ""; h = ""
        }
    }

    # Top border
    if ($Table.Border -ne "none") {
        $top = $chars.top_left
        for ($i = 0; $i -lt $colCount; $i++) {
            $top += ($chars.h * ($widths[$i] + 2))
            if ($i -lt $colCount - 1) { $top += $chars.top_mid }
        }
        $top += $chars.top_right
        if ($top.Trim()) { $output.Add((Format-RichText -Text $top -Style $Table.BorderStyle)) }
    }

    # Header
    if ($Table.ShowHeader) {
        $headerRow = $chars.v
        for ($i = 0; $i -lt $colCount; $i++) {
            $col = $Table.Columns[$i]
            $val = Convert-RichMarkup -InputString $col.Header
            $padding = " " * ($widths[$i] - (Get-VisibleLength $val))
            $headerRow += " " + $val + $padding + " " + $chars.v
        }
        $output.Add((Format-RichText -Text $headerRow -Style $Table.HeaderStyle))

        # Separator
        if ($Table.Border -ne "none") {
            $sep = $chars.mid_left
            for ($i = 0; $i -lt $colCount; $i++) {
                $sep += ($chars.h * ($widths[$i] + 2))
                if ($i -lt $colCount - 1) { $sep += $chars.mid_mid }
            }
            $sep += $chars.mid_right
            $output.Add((Format-RichText -Text $sep -Style $Table.BorderStyle))
        }
    }

    # Rows
    foreach ($row in $Table.Rows) {
        $r = $chars.v
        for ($i = 0; $i -lt $colCount; $i++) {
            $col = $Table.Columns[$i]
            $val = if ($i -lt $row.Count) { Convert-RichMarkup -InputString ($row[$i].ToString()) } else { "" }
            
            if ($col.Style) {
                $val = Format-RichText -Text $val -Style $col.Style
            }

            $visibleLen = Get-VisibleLength $val
            $paddingTotal = $widths[$i] - $visibleLen
            
            if ($col.Justify -eq "Right") {
                $r += " " + (" " * $paddingTotal) + $val + " " + $chars.v
            } elseif ($col.Justify -eq "Center") {
                $leftPad = [int]($paddingTotal / 2)
                $rightPad = $paddingTotal - $leftPad
                $r += " " + (" " * $leftPad) + $val + (" " * $rightPad) + " " + $chars.v
            } else {
                $r += " " + $val + (" " * $paddingTotal) + " " + $chars.v
            }
        }
        $output.Add((Format-RichText -Text $r -Style $Table.BorderStyle))
    }

    # Bottom border
    if ($Table.Border -ne "none") {
        $bottom = $chars.bottom_left
        for ($i = 0; $i -lt $colCount; $i++) {
            $bottom += ($chars.h * ($widths[$i] + 2))
            if ($i -lt $colCount - 1) { $bottom += $chars.bottom_mid }
        }
        $bottom += $chars.bottom_right
        if ($bottom.Trim()) { $output.Add((Format-RichText -Text $bottom -Style $Table.BorderStyle)) }
    }

    return $output -join "`n"
}