completers/onemd_completer/onemd_completer.ps1

# onemd tab completion for PowerShell
# Help-driven native completer for onemd and onemd.exe.

Set-StrictMode -Version 2.0

function New-OnemdCompletionResult {
    param(
        [string]$CompletionText,
        [string]$ResultType,
        [string]$ToolTip,
        [string]$ListItemText
    )

    if ([string]::IsNullOrWhiteSpace($ListItemText)) {
        $ListItemText = $CompletionText
    }

    if ([string]::IsNullOrWhiteSpace($ToolTip)) {
        $ToolTip = $CompletionText
    }

    [System.Management.Automation.CompletionResult]::new(
        $CompletionText,
        $ListItemText,
        $ResultType,
        $ToolTip
    )
}

function Get-OnemdCommandPath {
    foreach ($candidate in @('onemd', 'onemd.cmd', 'onemd.ps1', 'onemd.exe')) {
        $command = Get-Command -Name $candidate -ErrorAction SilentlyContinue |
            Where-Object { $_.CommandType -in @('Application', 'ExternalScript', 'Script') } |
            Select-Object -First 1

        if ($null -ne $command) {
            return $command.Source
        }
    }

    return $null
}

function Get-OnemdHelpOutput {
    param([string[]]$CommandPath)

    $resolvedCommandPath = Get-OnemdCommandPath
    if ([string]::IsNullOrWhiteSpace($resolvedCommandPath)) {
        return ''
    }

    $subcommandPath = @($CommandPath)

    try {
        if ($subcommandPath.Count -eq 0) {
            $resultText = ($null | & $resolvedCommandPath --help 2>&1 | ForEach-Object { $_ -replace '\e\[[0-9;?]*[ -/]*[@-~]', '' } | Out-String)
            if (-not [string]::IsNullOrWhiteSpace($resultText)) {
                return $resultText
            }

            return ($null | & $resolvedCommandPath help 2>&1 | ForEach-Object { $_ -replace '\e\[[0-9;?]*[ -/]*[@-~]', '' } | Out-String)
        }

        $resultText = ($null | & $resolvedCommandPath help $subcommandPath[0] 2>&1 | ForEach-Object { $_ -replace '\e\[[0-9;?]*[ -/]*[@-~]', '' } | Out-String)
        if (-not [string]::IsNullOrWhiteSpace($resultText)) {
            return $resultText
        }

        return ($null | & $resolvedCommandPath $subcommandPath[0] --help 2>&1 | ForEach-Object { $_ -replace '\e\[[0-9;?]*[ -/]*[@-~]', '' } | Out-String)
    } catch {
        return ''
    }
}

function ConvertTo-OnemdArray {
    param([object]$Value)

    if ($null -eq $Value) {
        return @()
    }

    if ($Value -is [System.Collections.IEnumerable] -and -not ($Value -is [string])) {
        $fullName = $Value.GetType().FullName
        if ($fullName -like 'System.Collections.Generic.List*' -or $fullName -like 'System.Collections.Generic.IReadOnlyList*') {
            return @($Value.ToArray())
        }
    }

    return @($Value)
}

function Get-OnemdSlotShape {
    param([string]$MetaVariable)

    # The metavariable in the help row decides the slot kind: <path>/<file>/<folder> are filesystem slots, everything
    # else (<n>, <seconds>, <guid>, <id|name>, <mode>, ...) is a typed value.
    $meta = if ($null -eq $MetaVariable) { '' } else { $MetaVariable.Trim('<', '>', '[', ']').ToLowerInvariant() }
    $pathLike = $false
    $directoryOnly = $false
    $extension = ''

    switch -Regex ($meta) {
        '^(folder|dir|directory)$' { $pathLike = $true; $directoryOnly = $true }
        '^(path|file)$' { $pathLike = $true }
        '^file\.([a-z0-9]+)$' { $pathLike = $true; $extension = '.' + $matches[1] }
    }

    [pscustomobject]@{
        PathLike      = $pathLike
        DirectoryOnly = $directoryOnly
        Extension     = $extension
    }
}

function Get-OnemdDescriptionValues {
    param([string]$Description)

    # Values stated in prose rather than in a (a|b|c) list: an "x, y, z" word list after a colon, small numeric
    # ranges, defaults, minimums and ceilings, and the literal "-" for stdin/stdout.
    $values = New-Object System.Collections.Generic.List[string]
    if ([string]::IsNullOrWhiteSpace($Description)) {
        return @()
    }

    if ($Description -match '\((?<values>[^)]+)\)') {
        $candidate = $matches.values
        if ($candidate -match '\|') {
            foreach ($value in @($candidate -split '\|' | ForEach-Object { $_.Trim() } | Where-Object { $_ })) {
                [void]$values.Add($value)
            }
        }
    }

    if ($values.Count -eq 0) {
        if ($Description -match ':\s*(?<list>[a-z]{3,}(?:,\s*[a-z]{3,})+)') {
            foreach ($value in @($matches.list -split ',\s*')) {
                [void]$values.Add($value)
            }
        }

        if ($Description -match '(?<!\w)(?<low>\d+)-(?<high>\d+)(?!\w)') {
            $low = [int]$matches.low
            $high = [int]$matches.high
            if ($high -gt $low -and ($high - $low) -le 10) {
                foreach ($number in $low..$high) { [void]$values.Add([string]$number) }
            } elseif ($high -gt $low) {
                [void]$values.Add([string]$low)
                [void]$values.Add([string]$high)
            }
        }

        foreach ($pattern in @('\bDefault:?\s+(\d+)', '\bminimum\s+(\d+)', '\bceiling\s+(\d+)')) {
            if ($Description -match $pattern -and -not $values.Contains($matches[1])) {
                [void]$values.Add($matches[1])
            }
        }

        if ($Description -match '"-"\s+(writes|reads)' -or $Description -match '\bor - to\b') {
            [void]$values.Add('-')
        }
    }

    @($values.ToArray())
}

function ConvertFrom-OnemdHelp {
    param([string]$HelpText)

    $lines = @([regex]::Split($HelpText, '\r?\n'))
    $commands = New-Object System.Collections.Generic.List[string]
    $options = New-Object System.Collections.Generic.List[object]
    $arguments = New-Object System.Collections.Generic.List[object]
    # Ordinal: -v (verbose) and -V (version) are different options.
    $seenOptionNames = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)

    $inCommands = $false
    $inArguments = $false
    $inOptions = $false

    for ($index = 0; $index -lt $lines.Count; $index++) {
        $line = $lines[$index]
        $trimmed = $line.Trim()

        if ($trimmed -eq 'Commands:') {
            $inCommands = $true
            $inArguments = $false
            $inOptions = $false
            continue
        }

        if ($trimmed -eq 'Arguments:') {
            $inCommands = $false
            $inArguments = $true
            $inOptions = $false
            continue
        }

        if ($trimmed -eq 'Options:' -or $trimmed -eq 'Global options:') {
            $inCommands = $false
            $inArguments = $false
            $inOptions = $true
            continue
        }

        if ($inCommands) {
            if ([string]::IsNullOrWhiteSpace($trimmed)) {
                continue
            }

            if ($trimmed -match '^(?<name>[A-Za-z0-9][A-Za-z0-9-]*)\s{2,}(?<description>.+)$') {
                [void]$commands.Add($matches.name)
            }

            continue
        }

        if ($inArguments) {
            if ([string]::IsNullOrWhiteSpace($trimmed)) {
                continue
            }

            if ($line -notmatch '^\s+\S') {
                $inArguments = $false
                continue
            }

            if ($trimmed -match '^(?<name><[^>]+>|\[[^]]+\]|[^\s][^\s]*)\s{2,}(?<description>.+)$') {
                $argumentName = $matches.name
                $description = $matches.description
                $shape = Get-OnemdSlotShape -MetaVariable $argumentName

                [void]$arguments.Add([pscustomobject]@{
                    Name = $argumentName
                    Description = $description
                    Values = @(Get-OnemdDescriptionValues -Description $description)
                    PathLike = $shape.PathLike
                    DirectoryOnly = $shape.DirectoryOnly
                    Extension = $shape.Extension
                })
            }

            continue
        }

        if ($inOptions) {
            if ([string]::IsNullOrWhiteSpace($trimmed)) {
                continue
            }

            # An option row is an indented line starting with '-'; anything else (a prose heading at the left
            # margin, a paragraph) ends the section so trailing prose is never parsed as more options.
            if ($line -notmatch '^\s+-') {
                $inOptions = $false
                continue
            }

            if ($trimmed -match '^(?<optionText>.+?)(\s{2,}|\s*$)(?<description>.+)$') {
                $optionText = $matches.optionText.Trim()
                $optionDescription = $matches.description

                $optionNames = @([regex]::Matches($optionText, '--?[A-Za-z0-9][A-Za-z0-9-]*') | ForEach-Object { $_.Value })
                if ($optionNames.Count -eq 0 -or $seenOptionNames.Contains($optionNames[0])) {
                    continue
                }
                foreach ($name in $optionNames) { [void]$seenOptionNames.Add($name) }

                $metaVariable = ''
                if ($optionText -match '(<[^>]+>)') {
                    $metaVariable = $matches[1]
                }
                $shape = Get-OnemdSlotShape -MetaVariable $metaVariable

                [void]$options.Add([pscustomobject]@{
                    Names = @($optionNames)
                    TakesValue = ($metaVariable -ne '')
                    MetaVariable = $metaVariable
                    Values = @(Get-OnemdDescriptionValues -Description $optionDescription)
                    Description = $optionDescription
                    PathLike = $shape.PathLike
                    DirectoryOnly = $shape.DirectoryOnly
                    Extension = $shape.Extension
                })
            }
        }
    }

    # Negated --no-* flags live in usage lines and descriptions, never in the left column.
    foreach ($match in [regex]::Matches($HelpText, '(?m)^.*?(--no-[a-z0-9-]+).*$')) {
        $name = $match.Groups[1].Value
        if (-not $seenOptionNames.Add($name)) {
            continue
        }
        [void]$options.Add([pscustomobject]@{
            Names = @($name)
            TakesValue = $false
            MetaVariable = ''
            Values = @()
            Description = $match.Value.Trim()
            PathLike = $false
            DirectoryOnly = $false
            Extension = ''
        })
    }

    [pscustomobject]@{
        Commands = (ConvertTo-OnemdArray -Value ($commands.ToArray() | Sort-Object -Unique))
        Options = (ConvertTo-OnemdArray -Value $options)
        Arguments = (ConvertTo-OnemdArray -Value $arguments)
    }
}

function Get-OnemdCompletionCatalog {
    $catalog = Get-Variable -Name 'OnemdCompletionCatalog' -Scope Script -ErrorAction Ignore
    if ($null -ne $catalog -and $null -ne $catalog.Value) {
        return $catalog.Value
    }

    $newCatalog = [ordered]@{
        Initialized = $false
        RootHelpText = ''
        RootHelp = $null
        CommandCatalogs = @{}
    }

    Set-Variable -Name 'OnemdCompletionCatalog' -Value $newCatalog -Scope Script
    return (Get-Variable -Name 'OnemdCompletionCatalog' -Scope Script).Value
}

function Initialize-OnemdCompletionCatalog {
    $catalog = Get-OnemdCompletionCatalog
    if ($catalog.Initialized) {
        return $catalog
    }

    $catalog.RootHelpText = Get-OnemdHelpOutput -CommandPath @()
    $catalog.RootHelp = ConvertFrom-OnemdHelp -HelpText $catalog.RootHelpText
    $catalog.CommandCatalogs[''] = [pscustomobject]@{
        Path = @()
        Commands = (ConvertTo-OnemdArray -Value $catalog.RootHelp.Commands)
        Options = (ConvertTo-OnemdArray -Value $catalog.RootHelp.Options)
        Arguments = (ConvertTo-OnemdArray -Value $catalog.RootHelp.Arguments)
    }

    $catalog.Initialized = $true
    Set-Variable -Name 'OnemdCompletionCatalog' -Value $catalog -Scope Script
    return (Get-Variable -Name 'OnemdCompletionCatalog' -Scope Script).Value
}

function Get-OnemdCatalog {
    param([string[]]$CommandPath)

    $catalog = Initialize-OnemdCompletionCatalog
    $key = if ($null -eq $CommandPath -or $CommandPath.Count -eq 0) { '' } else { $CommandPath -join "`u{1f}" }

    if ($catalog.CommandCatalogs.ContainsKey($key)) {
        return $catalog.CommandCatalogs[$key]
    }

    $helpText = Get-OnemdHelpOutput -CommandPath $CommandPath
    $parsed = ConvertFrom-OnemdHelp -HelpText $helpText
    $parsedCatalog = [pscustomobject]@{
        Path = @($CommandPath)
        Commands = (ConvertTo-OnemdArray -Value $parsed.Commands)
        Options = (ConvertTo-OnemdArray -Value $parsed.Options)
        Arguments = (ConvertTo-OnemdArray -Value $parsed.Arguments)
    }

    $catalog.CommandCatalogs[$key] = $parsedCatalog
    Set-Variable -Name 'OnemdCompletionCatalog' -Value $catalog -Scope Script
    return $catalog.CommandCatalogs[$key]
}

function Get-OnemdCommandTokens {
    param(
        [System.Management.Automation.Language.CommandAst]$CommandAst,
        [int]$CursorPosition,
        [string]$WordToComplete
    )

    # Elements that end before the cursor are completed tokens; the element under the cursor is the word being
    # typed (cut at the cursor); anything to the right of the cursor is ignored.
    $tokens = New-Object System.Collections.Generic.List[string]
    $currentWord = ''
    if ($null -ne $CommandAst) {
        foreach ($element in @($CommandAst.CommandElements | Select-Object -Skip 1)) {
            $extent = $element.Extent
            if ($extent.EndOffset -lt $CursorPosition) {
                $text = $extent.Text.Trim()
                if (-not [string]::IsNullOrWhiteSpace($text)) {
                    [void]$tokens.Add($text)
                }
                continue
            }

            if ($extent.StartOffset -le $CursorPosition) {
                $currentWord = $extent.Text.Substring(0, $CursorPosition - $extent.StartOffset)
            }
            break
        }
    }

    if ([string]::IsNullOrEmpty($currentWord) -and -not [string]::IsNullOrEmpty($WordToComplete)) {
        $currentWord = $WordToComplete
    }

    [pscustomobject]@{
        CurrentWord = $currentWord
        Tokens = (ConvertTo-OnemdArray -Value $tokens)
    }
}

function Get-OnemdPathCompletions {
    param([string]$InputPath, [bool]$DirectoryOnly, [string]$Extension = '', [string]$InlinePrefix = '')

    $cleanInput = if ($null -eq $InputPath) { '' } else { $InputPath }
    $alwaysQuote = -not [string]::IsNullOrEmpty($InputPath) -and ($InputPath.StartsWith('"') -or $InputPath.StartsWith("'"))
    $cleanInput = $cleanInput.Trim('"', "'")

    if ([string]::IsNullOrWhiteSpace($cleanInput)) {
        $parent = '.'
        $leaf = ''
    } elseif ($cleanInput -match '[\\/]+$') {
        $parent = $cleanInput
        $leaf = ''
    } else {
        $parent = Split-Path -Path $cleanInput -Parent
        if ([string]::IsNullOrWhiteSpace($parent)) {
            $parent = '.'
        }

        $leaf = Split-Path -Path $cleanInput -Leaf
    }

    if (-not (Test-Path -LiteralPath $parent -PathType Container)) {
        return @()
    }

    $items = @(Get-ChildItem -LiteralPath $parent -ErrorAction SilentlyContinue)
    $items = $items | Where-Object { $_.Name -like ([System.Management.Automation.WildcardPattern]::Escape($leaf) + '*') } | Sort-Object -Property Name

    foreach ($item in $items) {
        if (-not $item.PSIsContainer) {
            if ($DirectoryOnly) {
                continue
            }

            if ($Extension -and -not $item.Name.EndsWith($Extension, [System.StringComparison]::OrdinalIgnoreCase)) {
                continue
            }
        }

        $pathText = if ($parent -eq '.' -or [string]::IsNullOrWhiteSpace($cleanInput)) {
            $item.Name
        } else {
            Join-Path -Path $parent -ChildPath $item.Name
        }

        if ($item.PSIsContainer -and -not $pathText.EndsWith([System.IO.Path]::DirectorySeparatorChar)) {
            $pathText += [System.IO.Path]::DirectorySeparatorChar
        }

        $quotedPath = $pathText
        if (($alwaysQuote -or $pathText -match '\s') -and -not ($pathText.StartsWith('"') -and $pathText.EndsWith('"'))) {
            $escaped = $pathText.Replace('`', '``').Replace('"', '`"')
            $quotedPath = '"' + $escaped + '"'
        }

        if ($item.PSIsContainer) {
            New-OnemdCompletionResult -CompletionText ($InlinePrefix + $quotedPath) -ListItemText $pathText -ResultType 'ProviderContainer' -ToolTip $item.FullName
        } else {
            New-OnemdCompletionResult -CompletionText ($InlinePrefix + $quotedPath) -ListItemText $pathText -ResultType 'ProviderItem' -ToolTip $item.FullName
        }
    }
}

function Get-OnemdOptionSpec {
    param(
        [psobject]$Catalog,
        [string]$OptionName
    )

    if ($null -eq $Catalog -or [string]::IsNullOrWhiteSpace($OptionName)) {
        return $null
    }

    foreach ($option in @($Catalog.Options)) {
        if ($option.Names -contains $OptionName) {
            return $option
        }
    }

    return $null
}

function Get-OnemdValueCompletions {
    param(
        [psobject]$OptionSpec,
        [string]$CurrentWord,
        [string]$InlinePrefix = ''
    )

    if ($null -eq $OptionSpec) {
        return @()
    }

    $results = New-Object System.Collections.Generic.List[object]
    foreach ($value in @($OptionSpec.Values)) {
        if ($value -like ([System.Management.Automation.WildcardPattern]::Escape($CurrentWord) + '*')) {
            [void]$results.Add((New-OnemdCompletionResult -CompletionText ($InlinePrefix + $value) -ListItemText $value -ResultType 'ParameterValue' -ToolTip $OptionSpec.Description))
        }
    }

    if ($OptionSpec.PathLike) {
        foreach ($item in @(Get-OnemdPathCompletions -InputPath $CurrentWord -DirectoryOnly:$OptionSpec.DirectoryOnly -Extension $OptionSpec.Extension -InlinePrefix $InlinePrefix)) {
            [void]$results.Add($item)
        }
    }

    if ($results.Count -gt 0 -or $OptionSpec.PathLike) {
        return (ConvertTo-OnemdArray -Value $results)
    }

    if (-not [string]::IsNullOrEmpty($CurrentWord)) {
        return @()
    }

    $hint = if ($OptionSpec.PSObject.Properties['MetaVariable'] -and $OptionSpec.MetaVariable) { $OptionSpec.MetaVariable } else { '<value>' }
    return @(
        New-OnemdCompletionResult -CompletionText ($InlinePrefix + $hint) -ListItemText $hint -ResultType 'ParameterValue' -ToolTip $OptionSpec.Description
    )
}

function Complete-Onemd {
    param(
        [string]$wordToComplete,
        [System.Management.Automation.Language.CommandAst]$commandAst,
        [int]$cursorPosition
    )

    $tokenState = Get-OnemdCommandTokens -CommandAst $commandAst -CursorPosition $cursorPosition -WordToComplete $wordToComplete
    $currentWord = $tokenState.CurrentWord
    $tokensBeforeCurrent = @($tokenState.Tokens)
    $catalog = Get-OnemdCatalog -CommandPath @()
    $activePath = @()
    $activeCatalog = $catalog

    foreach ($token in $tokensBeforeCurrent) {
        if ($token.StartsWith('-')) {
            break
        }

        if ($activeCatalog.Commands -contains $token) {
            $activePath += $token
            $activeCatalog = Get-OnemdCatalog -CommandPath $activePath
            continue
        }

        break
    }

    if ($activePath.Count -eq 1 -and $activePath[0] -eq 'help') {
        # 'help' takes a command name: complete the root command list exactly once.
        $activeCatalog = [pscustomobject]@{
            Path = @('help')
            Commands = @($catalog.Commands)
            Options = @($activeCatalog.Options)
            Arguments = @()
        }
    }

    # Attached --option=value form.
    if ($currentWord -match '^(?<name>--?[A-Za-z0-9][A-Za-z0-9-]*)=(?<value>.*)$') {
        $optionSpec = Get-OnemdOptionSpec -Catalog $activeCatalog -OptionName $matches.name
        if ($null -ne $optionSpec -and $optionSpec.TakesValue) {
            return @(Get-OnemdValueCompletions -OptionSpec $optionSpec -CurrentWord $matches.value -InlinePrefix ($matches.name + '='))
        }

        return @()
    }

    $results = New-Object System.Collections.Generic.List[object]

    if ($tokensBeforeCurrent.Count -gt 0) {
        $lastToken = $tokensBeforeCurrent[-1]
        if ($lastToken -and $lastToken.StartsWith('-')) {
            $optionSpec = Get-OnemdOptionSpec -Catalog $activeCatalog -OptionName $lastToken
            if ($null -ne $optionSpec -and $optionSpec.TakesValue) {
                return @(Get-OnemdValueCompletions -OptionSpec $optionSpec -CurrentWord $currentWord)
            }
        }
    }

    if ($currentWord.StartsWith('-')) {
        foreach ($option in @($activeCatalog.Options)) {
            foreach ($name in @($option.Names)) {
                if ($name -like ([System.Management.Automation.WildcardPattern]::Escape($currentWord) + '*')) {
                    [void]$results.Add((New-OnemdCompletionResult -CompletionText $name -ListItemText $name -ResultType 'ParameterName' -ToolTip $option.Description))
                }
            }
        }

        return (ConvertTo-OnemdArray -Value $results)
    }

    $activeCommands = @($activeCatalog.Commands)
    $activeArguments = @($activeCatalog.Arguments)

    if ($activeCommands.Count -gt 0) {
        foreach ($commandName in $activeCommands) {
            if ($commandName -like ([System.Management.Automation.WildcardPattern]::Escape($currentWord) + '*')) {
                [void]$results.Add((New-OnemdCompletionResult -CompletionText $commandName -ListItemText $commandName -ResultType 'ParameterValue' -ToolTip 'onemd subcommand'))
            }
        }
    }

    foreach ($option in @($activeCatalog.Options)) {
        foreach ($name in @($option.Names)) {
            if ($currentWord -eq '' -or $name -like ([System.Management.Automation.WildcardPattern]::Escape($currentWord) + '*')) {
                [void]$results.Add((New-OnemdCompletionResult -CompletionText $name -ListItemText $name -ResultType 'ParameterName' -ToolTip $option.Description))
            }
        }
    }

    $positionalTokens = @()
    $pendingValue = $false
    foreach ($token in $tokensBeforeCurrent) {
        if ($pendingValue) {
            $pendingValue = $false
            continue
        }

        if ($token.StartsWith('-')) {
            $spec = Get-OnemdOptionSpec -Catalog $activeCatalog -OptionName $token
            if ($null -ne $spec -and $spec.TakesValue) {
                $pendingValue = $true
            }
            continue
        }

        $matchesSubcommand = $false
        foreach ($pathToken in $activePath) {
            if ($token -eq $pathToken) {
                $matchesSubcommand = $true
                break
            }
        }

        if ($matchesSubcommand) {
            continue
        }

        $positionalTokens += $token
    }

    if ($activeArguments.Count -gt 0 -and $positionalTokens.Count -lt $activeArguments.Count) {
        # Operand candidates come first, then the option names already collected, so flags stay discoverable.
        $argumentSpec = $activeArguments[$positionalTokens.Count]
        $argumentResults = New-Object System.Collections.Generic.List[object]
        foreach ($value in @($argumentSpec.Values)) {
            if ($value -like ([System.Management.Automation.WildcardPattern]::Escape($currentWord) + '*')) {
                [void]$argumentResults.Add((New-OnemdCompletionResult -CompletionText $value -ListItemText $value -ResultType 'ParameterValue' -ToolTip $argumentSpec.Description))
            }
        }

        if ($argumentSpec.PathLike) {
            foreach ($item in @(Get-OnemdPathCompletions -InputPath $currentWord -DirectoryOnly:$argumentSpec.DirectoryOnly -Extension $argumentSpec.Extension)) {
                [void]$argumentResults.Add($item)
            }
        } elseif ($argumentResults.Count -eq 0 -and $currentWord -eq '') {
            [void]$argumentResults.Add((New-OnemdCompletionResult -CompletionText $argumentSpec.Name -ListItemText $argumentSpec.Name -ResultType 'ParameterValue' -ToolTip $argumentSpec.Description))
        }

        return @(ConvertTo-OnemdArray -Value $argumentResults) + @(ConvertTo-OnemdArray -Value $results)
    }

    if ($results.Count -eq 0 -and $currentWord -ne '') {
        return @(
            New-OnemdCompletionResult -CompletionText $currentWord -ListItemText $currentWord -ResultType 'ParameterValue' -ToolTip 'onemd value'
        )
    }

    return (ConvertTo-OnemdArray -Value $results)
}

Register-ArgumentCompleter -Native -CommandName @('onemd', 'onemd.cmd', 'onemd.ps1', 'onemd.exe') -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)

    Complete-Onemd -wordToComplete $wordToComplete -commandAst $commandAst -cursorPosition $cursorPosition
}