Utils/fold.ps1

Register-GnuUtil @{
    Name          = 'fold'
    Category      = 'Viewing file contents'
    Synopsis      = 'Wrap each input line to fit in specified width.'
    Usage         = @('fold [OPTION]... [FILE]...')
    Description   = @('Wrap input lines in each FILE, writing to standard output.', '', 'With no FILE, or when FILE is -, read standard input.')
    FileOperands  = $true
    NumericOption = 'w'
    Options       = @(
        @{ Short = 'b'; Long = 'bytes'; Help = 'count bytes rather than columns' }
        @{ Short = 's'; Long = 'spaces'; Help = 'break at spaces' }
        @{ Short = 'w'; Long = 'width'; Arg = 'WIDTH'; Help = 'use WIDTH columns instead of 80' }
    )
    Notes         = @('PowerShell note: -b counts characters (UTF-16 code units), not UTF-8 bytes.')
}



function script:Get-GnuFoldColumn {
    <#
    .SYNOPSIS
    The column after printing Char at Column (GNU fold's adjust_column).
    #>

    param([int]$Column, [char]$Char, [bool]$Bytes)

    if ($Bytes) { return $Column + 1 }
    switch ([int]$Char) {
        8 { if ($Column -gt 0) { return $Column - 1 } else { return 0 } }
        13 { return 0 }
        9 { return $Column + 8 - ($Column % 8) }
    }
    $Column + 1
}

function script:Split-GnuFoldLine {
    <#
    .SYNOPSIS
    Folds one input line into output lines.
    #>

    param(
        [Parameter(Mandatory)][AllowEmptyString()][string]$Line,
        [int]$Width,
        [bool]$Bytes,
        [bool]$Spaces
    )

    $buffer = New-Object System.Text.StringBuilder
    $column = 0
    $index = 0
    while ($index -lt $Line.Length) {
        $char = $Line[$index]
        $next = Get-GnuFoldColumn -Column $column -Char $char -Bytes $Bytes
        if ($next -gt $Width -and $buffer.Length -gt 0) {
            if ($Spaces) {
                $text = $buffer.ToString()
                $blank = $text.LastIndexOfAny([char[]]@(' ', "`t"))
                if ($blank -ge 0) {
                    $text.Substring(0, $blank + 1)
                    $rest = $text.Substring($blank + 1)
                    [void]$buffer.Clear().Append($rest)
                    $column = 0
                    foreach ($restChar in $rest.ToCharArray()) { $column = Get-GnuFoldColumn -Column $column -Char $restChar -Bytes $Bytes }
                    continue
                }
            }
            $buffer.ToString()
            [void]$buffer.Clear()
            $column = 0
            continue
        }
        [void]$buffer.Append($char)
        $column = $next
        $index++
    }
    $buffer.ToString()
}