completers/cargo_completer/cargo_completer.ps1
|
# cargo native argument completer for PowerShell # Help-driven completer for cargo root and subcommand switches with safe local discovery. Set-StrictMode -Version 2.0 function Get-CargoCompletionCache { $cache = Get-Variable -Name CargoCompletionCache -Scope Script -ErrorAction Ignore if ($cache) { return $cache.Value } $newCache = @{ Initialized = $false CommandName = $null RootCommands = @() RootOptions = @() CommandMetadata = @{} Toolchains = @() Targets = @() UnstableFlags = @() RootValueMap = @{} CommonValueMap = @{} PathOptions = @('-C', '--config') CommandPathOptions = @{ '<root>' = @('-C', '--config') } } Set-Variable -Name CargoCompletionCache -Scope Script -Value $newCache $newCache } function Resolve-CargoCommandName { $cache = Get-CargoCompletionCache if ($cache.CommandName) { return $cache.CommandName } $command = Get-Command -Name cargo.exe, cargo -ErrorAction SilentlyContinue | Select-Object -First 1 if ($command) { $cache.CommandName = if ($command.Source) { $command.Source } else { $command.Name } } $cache.CommandName } function Invoke-CargoText { param([string[]]$Arguments) $commandName = Resolve-CargoCommandName if (-not $commandName) { return @() } try { @($null | & $commandName @Arguments 2>&1 | ForEach-Object { $_.ToString() -replace '\e\[[0-9;?]*[ -/]*[@-~]', '' }) } catch { @() } } function New-CargoCompletionResult { param( [string]$CompletionText, [string]$ListItemText, [string]$ResultType, [string]$ToolTip ) if ([string]::IsNullOrWhiteSpace($ListItemText)) { $ListItemText = $CompletionText } if ([string]::IsNullOrWhiteSpace($ToolTip)) { $ToolTip = $CompletionText } [System.Management.Automation.CompletionResult]::new( $CompletionText, $ListItemText, $ResultType, $ToolTip ) } function Remove-CargoOuterQuotes { param([string]$Value) if ($null -eq $Value) { return '' } $Value.Trim([char[]]@([char]34, [char]39)) } function ConvertTo-CargoQuotedPath { param( [string]$Value, [bool]$AlwaysQuote = $false ) if ([string]::IsNullOrWhiteSpace($Value)) { return $Value } if (($AlwaysQuote -or $Value -match '\s') -and -not ($Value.StartsWith('"') -and $Value.EndsWith('"'))) { $escaped = $Value.Replace('`', '``').Replace('"', '`"') return '"' + $escaped + '"' } $Value } function Get-CargoPathCompletions { param([string]$InputPath) $cleanInput = Remove-CargoOuterQuotes -Value $InputPath $alwaysQuote = -not [string]::IsNullOrEmpty($InputPath) -and ($InputPath.StartsWith('"') -or $InputPath.StartsWith("'")) [System.Management.Automation.CompletionCompleters]::CompleteFilename($cleanInput) | ForEach-Object { $completionText = ConvertTo-CargoQuotedPath -Value $_.CompletionText -AlwaysQuote $alwaysQuote New-CargoCompletionResult -CompletionText $completionText -ListItemText $_.ListItemText -ResultType $_.ResultType -ToolTip $_.ToolTip } } function Get-CargoCurrentWord { param( [string]$Line, [int]$CursorPosition, [string]$Fallback ) if ([string]::IsNullOrWhiteSpace($Line)) { return $Fallback } $safeCursor = [Math]::Min([Math]::Max($CursorPosition, 0), $Line.Length) $prefix = $Line.Substring(0, $safeCursor) if ($prefix -match '\s$') { return '' } $parts = @([regex]::Matches($prefix, '"[^"]*"|''[^'']*''|\S+') | ForEach-Object { $_.Value }) if ($parts.Count -gt 0) { return $parts[-1] } $Fallback } function Get-CargoArgumentTokens { param( [System.Management.Automation.Language.CommandAst]$CommandAst, [int]$CursorPosition ) $tokens = @() foreach ($element in $CommandAst.CommandElements | Select-Object -Skip 1) { if ($element.Extent.EndOffset -lt $CursorPosition) { $tokens += $element.Extent.Text } } $tokens } function Get-CargoRootValueMap { @{ '--color' = @('auto', 'always', 'never') '--config' = @('<KEY=VALUE>', '<path>') '--explain' = @('<error-code>') '-Z' = @() } } function Get-CargoCommonValueMap { @{ '--color' = @('auto', 'always', 'never') '--message-format' = @('human', 'short', 'json', 'json-diagnostic-short', 'json-diagnostic-rendered-ansi', 'json-render-diagnostics') '--profile' = @('<profile>') '--target' = @() '--target-dir' = @('<path>') '--artifact-dir' = @('<path>') '--manifest-path' = @('<path>') '--config' = @('<KEY=VALUE>', '<path>') '-j' = @('<jobs>') '--jobs' = @('<jobs>') '-F' = @('<features>') '--features' = @('<features>') '-p' = @('<package-spec>') '--package' = @('<package-spec>') '--exclude' = @('<package-spec>') '--bin' = @('<target-name>') '--example' = @('<target-name>') '--test' = @('<target-name>') '--bench' = @('<target-name>') '--timings' = @('<format>') } } function Get-CargoCommandValueHints { param([string]$CommandName) switch ($CommandName) { 'add' { return @{ '--rename' = @('<crate-name>') '--registry' = @('<registry>') '--target' = @() '--path' = @('<path>') '--git' = @('<url>') '--branch' = @('<branch>') '--tag' = @('<tag>') '--rev' = @('<rev>') '--features' = @('<features>') '--base' = @('dev-dependencies', 'build-dependencies', 'dependencies') '--public' = @('true', 'false') } } 'install' { return @{ '--version' = @('<version>') '--git' = @('<url>') '--branch' = @('<branch>') '--tag' = @('<tag>') '--rev' = @('<rev>') '--path' = @('<path>') '--root' = @('<path>') '--registry' = @('<registry>') '--target' = @() '--profile' = @('<profile>') '--bin' = @('<binary-name>') '--example' = @('<example-name>') '--features' = @('<features>') } } 'new' { return @{ '--name' = @('<package-name>') '--vcs' = @('git', 'hg', 'pijul', 'fossil', 'none') '--registry' = @('<registry>') } } 'init' { return @{ '--name' = @('<package-name>') '--vcs' = @('git', 'hg', 'pijul', 'fossil', 'none') '--registry' = @('<registry>') } } 'publish' { return @{ '--registry' = @('<registry>') '--token' = @('<token>') '--target' = @() } } 'login' { return @{ '--registry' = @('<registry>') '--token' = @('<token>') } } 'owner' { return @{ '--registry' = @('<registry>') '--token' = @('<token>') '--add' = @('<user>') '--remove' = @('<user>') } } 'search' { return @{ '--limit' = @('<count>') '--registry' = @('<registry>') '--index' = @('<url>') } } 'test' { return @{ '--message-format' = @('human', 'short', 'json', 'json-diagnostic-short', 'json-diagnostic-rendered-ansi', 'json-render-diagnostics') '--target' = @() } } default { return @{} } } } function Get-CargoCommandPathOptions { param([string]$CommandName) switch ($CommandName) { 'build' { @('--manifest-path', '--target-dir', '--artifact-dir', '--config') } 'check' { @('--manifest-path', '--target-dir', '--artifact-dir', '--config') } 'clean' { @('--manifest-path', '--target-dir', '--config') } 'doc' { @('--manifest-path', '--target-dir', '--config') } 'run' { @('--manifest-path', '--target-dir', '--config') } 'test' { @('--manifest-path', '--target-dir', '--config') } 'bench' { @('--manifest-path', '--target-dir', '--config') } 'update' { @('--manifest-path', '--config') } 'search' { @('--config') } 'publish' { @('--manifest-path', '--config') } 'install' { @('--path', '--root', '--config') } 'uninstall' { @('--root', '--config') } 'metadata' { @('--manifest-path', '--config') } 'locate-project' { @('--manifest-path', '--config') } 'package' { @('--manifest-path', '--target-dir', '--config') } 'new' { @('--config') } 'init' { @('--config') } 'config' { @('--config') } default { @('--config') } } } function Get-CargoToolchainCompletions { param([string]$CurrentWord) $cache = Get-CargoCompletionCache if ($cache.Toolchains.Count -eq 0) { $lines = @(Invoke-CargoText -Arguments @('+stable', '--version')) if ($lines.Count -gt 0) { $cache.Toolchains += 'stable' } $rustup = Get-Command -Name rustup.exe, rustup -ErrorAction SilentlyContinue | Select-Object -First 1 if ($rustup) { try { $cache.Toolchains += @(& $rustup.Source 'toolchain' 'list' 2>$null | ForEach-Object { ($_ -replace '\s+\([^)]*\)$', '').Trim() } | Where-Object { $_ }) } catch { } } $cache.Toolchains = @($cache.Toolchains | Sort-Object -Unique) } foreach ($toolchain in $cache.Toolchains) { $completion = "+$toolchain" if ($completion.StartsWith($CurrentWord, [System.StringComparison]::OrdinalIgnoreCase)) { New-CargoCompletionResult -CompletionText $completion -ListItemText $completion -ResultType 'ParameterValue' -ToolTip 'Rustup toolchain override.' } } } function Get-CargoTargetValues { $cache = Get-CargoCompletionCache if ($cache.Targets.Count -eq 0) { $rustc = Get-Command -Name rustc.exe, rustc -ErrorAction SilentlyContinue | Select-Object -First 1 if ($rustc) { try { $cache.Targets = @(& $rustc.Source '--print' 'target-list' 2>$null | Where-Object { $_ } | Sort-Object -Unique) } catch { $cache.Targets = @() } } } $cache.Targets } function Get-CargoUnstableFlags { $cache = Get-CargoCompletionCache if ($cache.UnstableFlags.Count -eq 0) { $lines = Invoke-CargoText -Arguments @('-Z', 'help') $flags = foreach ($line in $lines) { if ($line -match '^\s+-Z\s+([a-z0-9][a-z0-9\-]*)\b') { $matches[1] } } $cache.UnstableFlags = @($flags | Sort-Object -Unique -CaseSensitive) } $cache.UnstableFlags } function Get-CargoCommandNamesFromList { $lines = Invoke-CargoText -Arguments @('--list') $commands = foreach ($line in $lines) { # Third-party subcommands such as binstall and miri print no description at all. if ($line -match '^\s{4}([A-Za-z0-9][A-Za-z0-9\-_]*)(\s{2,}.*)?$') { $matches[1] } } @($commands | Sort-Object -Unique) } function Get-CargoRootCommandsFromHelp { $lines = Invoke-CargoText -Arguments @('--help') $commands = foreach ($line in $lines) { if ($line -match '^\s{4}([A-Za-z0-9][A-Za-z0-9\-_]*)\s*,?\s*([A-Za-z0-9][A-Za-z0-9\-_]*)?\s{2,}.*$') { $matches[1] if ($matches[2]) { $matches[2] } } } @($commands | Sort-Object -Unique) } function Get-CargoOptionSpecsFromHelp { param([string[]]$Lines) # clap indents every option line by 2-7 spaces and wraps descriptions further in, so the flag # segment is whatever precedes the first run of two spaces on such a line. Both layouts cargo # emits are covered: ' -F, --features <FEATURES> Desc' and ' --public' with the # description on the following line. $specs = New-Object System.Collections.Generic.List[object] $seen = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) foreach ($line in @($Lines)) { if ($line -notmatch '^ {2,7}-\S') { continue } $segment = (($line.Trim() -split '\s{2,}')[0]) $metaVar = if ($segment -match '\[?<[^>]+>\]?') { $matches[0] } else { '' } foreach ($match in [regex]::Matches($segment, '(?<!\S)(--?[A-Za-z0-9][A-Za-z0-9-]*)')) { $token = $match.Groups[1].Value if (-not $seen.Add($token)) { continue } [void]$specs.Add([pscustomobject]@{ Token = $token MetaVar = $metaVar }) } } @($specs.ToArray()) } function Get-CargoValueHintTable { param( [object[]]$Specs, [hashtable[]]$Overlays ) $hints = [System.Collections.Generic.Dictionary[string, object]]::new([System.StringComparer]::Ordinal) foreach ($spec in @($Specs)) { if (-not $spec.MetaVar) { continue } $name = $spec.MetaVar.Trim([char[]]@('[', ']', '<', '>')).ToLowerInvariant() $hints[$spec.Token] = @("<$name>") } # Only options that help says carry a value get a curated hint, so a bare flag can never # swallow the following token. foreach ($overlay in @($Overlays)) { foreach ($key in $overlay.Keys) { if ($hints.ContainsKey($key)) { $hints[$key] = @($overlay[$key]) } } } $hints } function Initialize-CargoCompletionCache { $cache = Get-CargoCompletionCache if ($cache.Initialized) { return } $cache.RootValueMap = Get-CargoRootValueMap $cache.CommonValueMap = Get-CargoCommonValueMap $rootHelp = Invoke-CargoText -Arguments @('--help') $rootSpecs = @(Get-CargoOptionSpecsFromHelp -Lines $rootHelp) $cache.RootOptions = @($rootSpecs | ForEach-Object { $_.Token }) $cache.RootCommands = @( Get-CargoRootCommandsFromHelp Get-CargoCommandNamesFromList 'help' ) | Sort-Object -Unique $cache.CommandMetadata['<root>'] = [pscustomobject]@{ Options = @($cache.RootOptions) ValueHints = Get-CargoValueHintTable -Specs $rootSpecs -Overlays @($cache.RootValueMap) PathOptions = @($cache.PathOptions) } $cache.Initialized = $true } function Get-CargoCommandMetadata { param([string]$CommandName) Initialize-CargoCompletionCache $cache = Get-CargoCompletionCache $lookupName = if ([string]::IsNullOrWhiteSpace($CommandName)) { '<root>' } else { $CommandName } if ($cache.CommandMetadata.ContainsKey($lookupName)) { return $cache.CommandMetadata[$lookupName] } # clap's own '<sub> --help' carries both option forms plus the metavar that says whether the # option takes a value; 'cargo help <sub>' is a man page that drops the long form of every pair. $helpLines = Invoke-CargoText -Arguments @($CommandName, '--help') # A subcommand whose help fails (an uninstalled third-party one, for example) yields no specs, # and the empty result has to stay an array or it reads back as a single $null element. $specs = @(Get-CargoOptionSpecsFromHelp -Lines $helpLines) $options = @($specs | ForEach-Object { $_.Token }) $valueHints = Get-CargoValueHintTable -Specs $specs -Overlays @( $cache.CommonValueMap (Get-CargoCommandValueHints -CommandName $CommandName) ) if ($options -contains '-Z') { $valueHints['-Z'] = @() } $metadata = [pscustomobject]@{ Options = @($options) ValueHints = $valueHints PathOptions = @(Get-CargoCommandPathOptions -CommandName $CommandName) } $cache.CommandMetadata[$lookupName] = $metadata $metadata } function Get-CargoState { param([string[]]$TokensBeforeCurrent) Initialize-CargoCompletionCache $cache = Get-CargoCompletionCache $globalOptionsWithValues = @('+toolchain', '--config', '--color', '--explain', '-Z', '-C') $rootCommands = @($cache.RootCommands) $commandName = $null $commandTokens = New-Object System.Collections.Generic.List[string] $pendingOption = $null $sawDoubleDash = $false for ($i = 0; $i -lt $TokensBeforeCurrent.Count; $i++) { $token = Remove-CargoOuterQuotes -Value $TokensBeforeCurrent[$i] if ([string]::IsNullOrWhiteSpace($token)) { continue } if ($pendingOption) { if (-not $commandName) { $pendingOption = $null continue } $commandTokens.Add($token) $pendingOption = $null continue } if ($sawDoubleDash) { $commandTokens.Add($token) continue } if ($token -eq '--') { if ($commandName) { # Hand '--' to the subcommand loop so it can stop treating cargo switches as # arguments of the program cargo is about to run. $commandTokens.Add($token) $sawDoubleDash = $true } else { $pendingOption = $null } continue } if (-not $commandName) { if ($token.StartsWith('+')) { continue } if ($token -match '^(--config|--color|--explain|-Z|-C)$') { $pendingOption = $token continue } if ($token.StartsWith('-')) { continue } if ($rootCommands -contains $token) { $commandName = $token continue } continue } $commandTokens.Add($token) } $commandMetadata = Get-CargoCommandMetadata -CommandName $commandName $commandPendingOption = $null $positionals = New-Object System.Collections.Generic.List[string] $afterDoubleDash = $false foreach ($token in $commandTokens) { if ($commandPendingOption) { $positionals.Add($token) $commandPendingOption = $null continue } if ($token -eq '--') { $afterDoubleDash = $true continue } if (-not $afterDoubleDash -and $token -in $commandMetadata.Options) { if ($commandMetadata.ValueHints.ContainsKey($token) -or $commandMetadata.PathOptions -contains $token) { $commandPendingOption = $token continue } continue } $positionals.Add($token) } [pscustomobject]@{ CommandName = $commandName CommandMetadata = $commandMetadata PendingGlobalOption = $pendingOption PendingOption = $commandPendingOption Positionals = @($positionals) AfterDoubleDash = $afterDoubleDash } } function Get-CargoValueCompletions { param( [string]$OptionName, [string]$CurrentWord, [pscustomobject]$State ) $current = Remove-CargoOuterQuotes -Value $CurrentWord switch ($OptionName) { '+toolchain' { return @(Get-CargoToolchainCompletions -CurrentWord $CurrentWord) } '-C' { return @(Get-CargoPathCompletions -InputPath $CurrentWord) } '--config' { $results = @() $results += @(Get-CargoPathCompletions -InputPath $CurrentWord) foreach ($placeholder in @('<KEY=VALUE>')) { if ($placeholder.StartsWith($current, [System.StringComparison]::OrdinalIgnoreCase)) { $results += New-CargoCompletionResult -CompletionText $placeholder -ListItemText $placeholder -ResultType 'ParameterValue' -ToolTip 'Cargo configuration override.' } } return @($results) } '--target' { return @( Get-CargoTargetValues | Where-Object { $_.StartsWith($current, [System.StringComparison]::OrdinalIgnoreCase) } | ForEach-Object { New-CargoCompletionResult -CompletionText $_ -ListItemText $_ -ResultType 'ParameterValue' -ToolTip 'Rust target triple.' } ) } '-Z' { return @( Get-CargoUnstableFlags | Where-Object { $_.StartsWith($current, [System.StringComparison]::OrdinalIgnoreCase) } | ForEach-Object { New-CargoCompletionResult -CompletionText $_ -ListItemText $_ -ResultType 'ParameterValue' -ToolTip 'Cargo unstable flag.' } ) } } if ($State.CommandMetadata.PathOptions -contains $OptionName) { return @(Get-CargoPathCompletions -InputPath $CurrentWord) } if ($State.CommandMetadata.ValueHints.ContainsKey($OptionName)) { return @( $State.CommandMetadata.ValueHints[$OptionName] | Where-Object { $_.StartsWith($current, [System.StringComparison]::OrdinalIgnoreCase) } | ForEach-Object { New-CargoCompletionResult -CompletionText $_ -ListItemText $_ -ResultType 'ParameterValue' -ToolTip "$OptionName value" } ) } @() } function Get-CargoOptionCompletions { param( [string[]]$Options, [string]$CurrentWord ) $current = Remove-CargoOuterQuotes -Value $CurrentWord # cargo's short flags are case-significant (-V is --version, -v is --verbose), so both the # de-duplication and the prefix test have to stay ordinal for single-dash words. $comparison = if ($current -match '^-[^-]') { [System.StringComparison]::Ordinal } else { [System.StringComparison]::OrdinalIgnoreCase } foreach ($option in $Options | Sort-Object -Unique -CaseSensitive) { if ($option.StartsWith($current, $comparison)) { New-CargoCompletionResult -CompletionText $option -ListItemText $option -ResultType 'ParameterName' -ToolTip $option } } } function Get-CargoCommandCompletions { param([string]$CurrentWord) Initialize-CargoCompletionCache $cache = Get-CargoCompletionCache $current = Remove-CargoOuterQuotes -Value $CurrentWord foreach ($command in $cache.RootCommands) { if ($command.StartsWith($current, [System.StringComparison]::OrdinalIgnoreCase)) { New-CargoCompletionResult -CompletionText $command -ListItemText $command -ResultType 'ParameterValue' -ToolTip 'cargo subcommand' } } } function Complete-Cargo { param( [string]$wordToComplete, [System.Management.Automation.Language.CommandAst]$commandAst, [int]$cursorPosition ) Initialize-CargoCompletionCache $currentWord = if ($cursorPosition -gt $commandAst.Extent.EndOffset) { '' } else { Get-CargoCurrentWord -Line $commandAst.ToString() -CursorPosition ($cursorPosition - $commandAst.Extent.StartOffset) -Fallback $wordToComplete } $state = Get-CargoState -TokensBeforeCurrent @(Get-CargoArgumentTokens -CommandAst $commandAst -CursorPosition $cursorPosition) if (-not $state.CommandName) { if ($state.PendingGlobalOption) { return @(Get-CargoValueCompletions -OptionName $state.PendingGlobalOption -CurrentWord $currentWord -State $state) } if ($currentWord.StartsWith('+')) { return @(Get-CargoToolchainCompletions -CurrentWord $currentWord) } $results = @() if ($currentWord.StartsWith('-')) { return @(Get-CargoOptionCompletions -Options $state.CommandMetadata.Options -CurrentWord $currentWord) } if ([string]::IsNullOrWhiteSpace($currentWord)) { $results += @(Get-CargoOptionCompletions -Options $state.CommandMetadata.Options -CurrentWord '') } $results += @(Get-CargoCommandCompletions -CurrentWord $currentWord) if ([string]::IsNullOrWhiteSpace($currentWord)) { $results += @(Get-CargoToolchainCompletions -CurrentWord '') } return @($results) } if ($state.CommandName -eq 'help' -and $state.Positionals.Count -eq 0 -and -not $state.PendingOption) { if ($currentWord.StartsWith('-')) { return @(Get-CargoOptionCompletions -Options $state.CommandMetadata.Options -CurrentWord $currentWord) } $results = @() if ([string]::IsNullOrWhiteSpace($currentWord)) { $results += @(Get-CargoOptionCompletions -Options $state.CommandMetadata.Options -CurrentWord '') } $results += @(Get-CargoCommandCompletions -CurrentWord $currentWord) return @($results) } if ($state.PendingOption) { return @(Get-CargoValueCompletions -OptionName $state.PendingOption -CurrentWord $currentWord -State $state) } if ($state.AfterDoubleDash) { return @() } $optionResults = @() if ($currentWord.StartsWith('-')) { return @(Get-CargoOptionCompletions -Options $state.CommandMetadata.Options -CurrentWord $currentWord) } if ([string]::IsNullOrWhiteSpace($currentWord)) { $optionResults = @(Get-CargoOptionCompletions -Options $state.CommandMetadata.Options -CurrentWord '') } switch ($state.CommandName) { 'new' { if ($state.Positionals.Count -eq 0) { return @($optionResults + @(Get-CargoPathCompletions -InputPath $currentWord)) } } 'init' { if ($state.Positionals.Count -eq 0) { return @($optionResults + @(Get-CargoPathCompletions -InputPath $currentWord)) } } 'install' { if ($state.Positionals.Count -eq 0) { $results = @() $results += @(Get-CargoPathCompletions -InputPath $currentWord) if ('<crate>'.StartsWith((Remove-CargoOuterQuotes -Value $currentWord), [System.StringComparison]::OrdinalIgnoreCase)) { $results += New-CargoCompletionResult -CompletionText '<crate>' -ListItemText '<crate>' -ResultType 'ParameterValue' -ToolTip 'Crate name or path.' } return @($optionResults + $results) } } 'uninstall' { if ($state.Positionals.Count -eq 0) { if ('<crate>'.StartsWith((Remove-CargoOuterQuotes -Value $currentWord), [System.StringComparison]::OrdinalIgnoreCase)) { return @($optionResults + @(New-CargoCompletionResult -CompletionText '<crate>' -ListItemText '<crate>' -ResultType 'ParameterValue' -ToolTip 'Installed crate name.')) } } } 'search' { if ($state.Positionals.Count -eq 0) { if ('<query>'.StartsWith((Remove-CargoOuterQuotes -Value $currentWord), [System.StringComparison]::OrdinalIgnoreCase)) { return @($optionResults + @(New-CargoCompletionResult -CompletionText '<query>' -ListItemText '<query>' -ResultType 'ParameterValue' -ToolTip 'Search query.')) } } } 'test' { if ($state.Positionals.Count -eq 0) { if ('<test-filter>'.StartsWith((Remove-CargoOuterQuotes -Value $currentWord), [System.StringComparison]::OrdinalIgnoreCase)) { return @($optionResults + @(New-CargoCompletionResult -CompletionText '<test-filter>' -ListItemText '<test-filter>' -ResultType 'ParameterValue' -ToolTip 'Optional test name filter.')) } } } } @($optionResults) } Register-ArgumentCompleter -Native -CommandName @('cargo', 'cargo.exe') -ScriptBlock { param($wordToComplete, $commandAst, $cursorPosition) Complete-Cargo -wordToComplete $wordToComplete -commandAst $commandAst -cursorPosition $cursorPosition } |