Private/Rendering/ConvertTo-AnsiPatch.ps1

function ConvertTo-AnsiPatch {
    <#
    .SYNOPSIS
        Converts a list of view-diff patches into an incremental ANSI escape sequence string.

    .DESCRIPTION
        Processes each patch from Compare-ElmViewTree:

        - Replace: emits a cursor-position sequence (ESC[{Y+1};{X+1}H) followed by
          the styled content from Apply-ElmStyle.
        - Clear: emits a cursor-position sequence followed by spaces spanning Width
          for each row in Height, erasing the vacated region.
        - FullRedraw: skipped. The caller is expected to detect FullRedraw patches
          and invoke ConvertTo-AnsiOutput instead.

    .PARAMETER Patches
        An array of patch PSCustomObjects produced by Compare-ElmViewTree. Each object
        has a Type property ('Replace', 'Clear', or 'FullRedraw').

    .OUTPUTS
        [string] — A single ANSI escape sequence string ready for Console output.
        Returns an empty string when the patch list is empty or contains only FullRedraw.

    .EXAMPLE
        $patches = Compare-ElmViewTree -OldTree $prev -NewTree $new
        $ansi = ConvertTo-AnsiPatch -Patches $patches
        [Console]::Out.Write($ansi)

    .NOTES
        Does not emit hide/show cursor or clear-screen sequences. The caller (event loop)
        manages cursor visibility around full renders.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [AllowEmptyCollection()]
        [object[]]$Patches
    )

    $esc = [char]27
    $sb  = [System.Text.StringBuilder]::new()

    foreach ($patch in $Patches) {
        switch ($patch.Type) {
            'Replace' {
                $row        = $patch.Y + 1
                $col        = $patch.X + 1
                $patchWidth = if ($patch.PSObject.Properties['Width'] -and $null -ne $patch.Width) { $patch.Width } else { $patch.Content.Length }
                $content    = Apply-ElmStyle -Content $patch.Content -Style $patch.Style -Width $patchWidth
                # ESC[K erases from cursor to end of line, clearing any leftover chars from a wider previous value
                [void]$sb.Append("$esc[$row;${col}H$esc[K$content")
            }
            'Clear' {
                $row    = $patch.Y + 1
                $col    = $patch.X + 1
                $spaces = ' ' * $patch.Width
                for ($r = 0; $r -lt $patch.Height; $r++) {
                    $currentRow = $row + $r
                    [void]$sb.Append("$esc[$currentRow;${col}H$spaces")
                }
            }
            'FullRedraw' {
                # Intentionally skipped — caller handles full-redraw via ConvertTo-AnsiOutput
            }
        }
    }

    return $sb.ToString()
}