PsComplete.psm1

# immediately chain into the next argument if its a switch
# or stop if input is expected
using namespace System.Management.Automation
function HandleReplacementArgChain($replacement) {

    if ($replacement.ResultType -eq 'ProviderContainer') {
    }
    switch ($replacement.ArgumentType) {
        "psobject" {
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert('.');
            Invoke-GuiPsComplete;
        } 
        "switch" { 
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' -');
            Invoke-GuiPsComplete;
        }
        "IDictionary" { 
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' @{ "" = "" }');
            [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursorPosition + $replacement.CompletionText.Length + 4);
        }
        "string array" { 
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ');
        }
        { @("CommandTypes", "ActionPreference") -contains $_ } {
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ');
            Invoke-GuiPsComplete;
        }
        Default {
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ');
        }
    }
}

# function writeDebug($variable) {
# $variable | ConvertTo-Json -Depth 5 > $env:HOME/Desktop/sample.json
# }

## Command Helpers
function CommandGetType {
    [OutputType([System.Management.Automation.CommandTypes])]
    Param ([CommandInfo]$commandinfo)   
    $commandinfo 
    | Select-Object -First 1 -ExpandProperty CommandType
}
function GetPositionParameters {
    [OutputType([CommandParameterInfo])]
    Param ($parameters)   
    $parameters
    | Where-Object -Property Position -NE ([Int32]::MinValue)
    | Sort-Object -Property Position
}

$PsCompleteSettings = @{
    ExpandPositionParameters = $true
}


function HandleCompletionCommand($commandname) {
    
    $command = Get-Command $commandname
    [System.Management.Automation.CommandTypes] $commandType = CommandGetType $command
                    
    switch ($commandType) {
        ([System.Management.Automation.CommandTypes]::Application) { 
            ## e.g. apt, cmd, /bin/sh
        }
        ([System.Management.Automation.CommandTypes]::Cmdlet) {
            $params = $command.ParameterSets[0].Parameters
            $posParameters = GetPositionParameters($params)
            # writeDebug $posParameters.Count
                            
            if ($posParameters.Length -gt 0) {
                $p1 = $posParameters[0]
                [System.Type] $p1Type = $p1.ParameterType
                [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ')
                if ($PsCompleteSettings.ExpandPositionParameters) {
                    switch ($p1Type.FullName) {
                                        ("System.String[]") { 
                            [Microsoft.PowerShell.PSConsoleReadLine]::Insert("''")
                            $cmdlen = "$replacement.CompletionText".Length + 1
                            [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cmdlen)
                        }
                        Default {}
                    }
                    ## don't expand invokes
                    if ($command.Verb -ne 'Invoke') {
                        Invoke-GuiPsComplete
                    }
                }
            }
                            
        }
        ([System.Management.Automation.CommandTypes]::Function) {
        }
                        
        Default {
        }
    }
}

function Invoke-GuiPsComplete() {
    $buffer = ''
    $cursorPosition = 0
    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$buffer, [ref]$cursorPosition)
    if ($buffer -eq '') { return }
    $completion = TabExpansion2 $buffer $cursorPosition 
    
    if ($completion.CompletionMatches.Count -eq 0) {
        return
    }

    $replacement = 
    Invoke-PsComplete `
        -Content $completion.CompletionMatches `
        -CommandParameter "$buffer" `
         

    # debug
    # writeDebug @{r=$replacement; r2=$completion}
    # Write-Warning "`n`n$replacement.ResultType"
    
    if ($replacement) {
        switch ($replacement.ExitKey) {
            Tab {
                [Microsoft.PowerShell.PSConsoleReadLine]::Replace($completion.ReplacementIndex, $completion.ReplacementLength, $replacement.CompletionText)

                if ($replacement.ResultType -eq 'Command') {
                    HandleCompletionCommand $replacement.CompletionText
                }
                elseif ($replacement.ResultType -eq 'ParameterName') {
                    HandleReplacementArgChain $replacement
                }
                elseif ($replacement.ResultType -eq 'ProviderContainer') {
                    if ([System.Environment]::OSVersion.Platform -eq 'Unix') {
                        [Microsoft.PowerShell.PSConsoleReadLine]::Insert('/');
                    }
                    else {
                        [Microsoft.PowerShell.PSConsoleReadLine]::Insert('\');
                    }
                }
            }
            Enter {
                [Microsoft.PowerShell.PSConsoleReadLine]::Replace($completion.ReplacementIndex, $completion.ReplacementLength, $replacement.CompletionText)
            }
            Escape {
                [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursorPosition);
            }
            ## if there is a single option
            None {
                [Microsoft.PowerShell.PSConsoleReadLine]::Replace($completion.ReplacementIndex, $completion.ReplacementLength, $replacement.CompletionText)
                if ($replacement.ResultType -eq 'Command') {
                    HandleCompletionCommand $replacement.CompletionText
                }
                elseif ($replacement.ResultType -eq 'ProviderContainer') {
                    if ([System.Environment]::OSVersion.Platform -eq 'Unix') {
                        [Microsoft.PowerShell.PSConsoleReadLine]::Insert('/');
                    }
                    else {
                        [Microsoft.PowerShell.PSConsoleReadLine]::Insert('\');
                    }
                }
            }
        }
    }
}


function Install-PsComplete() {
    $loadedAssemblies = `
        [System.AppDomain]::CurrentDomain.GetAssemblies() `
    | Where-Object Location `
    | ForEach-Object { $_.GetName().Name };
   
    if (!($loadedAssemblies.Contains('FSharp.Core'))) {
        Import-Module "$PSScriptRoot/FSharp.Core.dll"    
    }
    if (!($loadedAssemblies.Contains('aciq.pscomplete'))) {
        Import-Module "$PSScriptRoot/aciq.pscomplete.dll"   
    }

    Set-PSReadLineKeyHandler -Chord 'Tab' -ScriptBlock { 
        Invoke-GuiPsComplete 
    }
}

Install-PsComplete

# Import-Module '/home/ian/f/publicrepos/aciq.pscomplete/src/bin/Debug/net6.0/aciq.pscomplete.dll' -DisableNameChecking
# Import-Module '/home/ian/f/publicrepos/aciq.pscomplete/src/bin/Release/net6.0/aciq.pscomplete.dll' -DisableNameChecking

# Set-PSReadLineKeyHandler -Chord 'Tab' -ScriptBlock { Invoke-GuiPsComplete }
# Set-PSReadLineKeyHandler -Chord 'Ctrl+q' -ScriptBlock { Invoke-GuiPsComplete }