| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- ###-begin-{pkgname}-completion-###
- Register-ArgumentCompleter -CommandName '{pkgname}' -ScriptBlock {
- param(
- $WordToComplete,
- $CommandAst,
- $CursorPosition
- )
- function __{pkgname}_debug {
- if ($env:BASH_COMP_DEBUG_FILE) {
- "$args" | Out-File -Append -FilePath "$env:BASH_COMP_DEBUG_FILE"
- }
- }
- filter __{pkgname}_escapeStringWithSpecialChars {
- $_ -replace '\s|#|@|\$|;|,|''|\{|\}|\(|\)|"|`|\||<|>|&','`$&'
- }
- # Get the current command line and convert into a string
- $Command = $CommandAst.CommandElements
- $Command = "$Command"
- __{pkgname}_debug ""
- __{pkgname}_debug "========= starting completion logic =========="
- __{pkgname}_debug "WordToComplete: $WordToComplete Command: $Command CursorPosition: $CursorPosition"
- # The user could have moved the cursor backwards on the command-line.
- # We need to trigger completion from the $CursorPosition location, so we need
- # to truncate the command-line ($Command) up to the $CursorPosition location.
- # Make sure the $Command is longer then the $CursorPosition before we truncate.
- # This happens because the $Command does not include the last space.
- if ($Command.Length -gt $CursorPosition) {
- $Command=$Command.Substring(0,$CursorPosition)
- }
- __{pkgname}_debug "Truncated command: $Command"
- # Prepare the command to request completions for the program.
- # Split the command at the first space to separate the program and arguments.
- $Program,$Arguments = $Command.Split(" ",2)
- $RequestComp="$Program completion-server"
- __{pkgname}_debug "RequestComp: $RequestComp"
- # we cannot use $WordToComplete because it
- # has the wrong values if the cursor was moved
- # so use the last argument
- if ($WordToComplete -ne "" ) {
- $WordToComplete = $Arguments.Split(" ")[-1]
- }
- __{pkgname}_debug "New WordToComplete: $WordToComplete"
- # Check for flag with equal sign
- $IsEqualFlag = ($WordToComplete -Like "--*=*" )
- if ( $IsEqualFlag ) {
- __{pkgname}_debug "Completing equal sign flag"
- # Remove the flag part
- $Flag,$WordToComplete = $WordToComplete.Split("=",2)
- }
- if ( $WordToComplete -eq "" -And ( -Not $IsEqualFlag )) {
- # If the last parameter is complete (there is a space following it)
- # We add an extra empty parameter so we can indicate this to the go method.
- __{pkgname}_debug "Adding extra empty parameter"
- # We need to use `"`" to pass an empty argument a "" or '' does not work!!!
- $Command="$Command" + ' `"`"'
- }
- __{pkgname}_debug "Calling $RequestComp"
- $oldenv = ($env:SHELL, $env:COMP_CWORD, $env:COMP_LINE, $env:COMP_POINT)
- $env:SHELL = "pwsh"
- $env:COMP_CWORD = $Command.Split(" ").Count - 1
- $env:COMP_POINT = $CursorPosition
- $env:COMP_LINE = $Command
- try {
- #call the command store the output in $out and redirect stderr and stdout to null
- # $Out is an array contains each line per element
- Invoke-Expression -OutVariable out "$RequestComp" 2>&1 | Out-Null
- } finally {
- ($env:SHELL, $env:COMP_CWORD, $env:COMP_LINE, $env:COMP_POINT) = $oldenv
- }
- __{pkgname}_debug "The completions are: $Out"
- $Longest = 0
- $Values = $Out | ForEach-Object {
- #Split the output in name and description
- $Name, $Description = $_.Split("`t",2)
- __{pkgname}_debug "Name: $Name Description: $Description"
- # Look for the longest completion so that we can format things nicely
- if ($Longest -lt $Name.Length) {
- $Longest = $Name.Length
- }
- # Set the description to a one space string if there is none set.
- # This is needed because the CompletionResult does not accept an empty string as argument
- if (-Not $Description) {
- $Description = " "
- }
- @{Name="$Name";Description="$Description"}
- }
- $Space = " "
- $Values = $Values | Where-Object {
- # filter the result
- if (-not $WordToComplete.StartsWith("-") -and $_.Name.StartsWith("-")) {
- # skip flag completions unless a dash is present
- return
- } else {
- $_.Name -like "$WordToComplete*"
- }
- # Join the flag back if we have an equal sign flag
- if ( $IsEqualFlag ) {
- __{pkgname}_debug "Join the equal sign flag back to the completion value"
- $_.Name = $Flag + "=" + $_.Name
- }
- }
- # Get the current mode
- $Mode = (Get-PSReadLineKeyHandler | Where-Object {$_.Key -eq "Tab" }).Function
- __{pkgname}_debug "Mode: $Mode"
- $Values | ForEach-Object {
- # store temporary because switch will overwrite $_
- $comp = $_
- # PowerShell supports three different completion modes
- # - TabCompleteNext (default windows style - on each key press the next option is displayed)
- # - Complete (works like bash)
- # - MenuComplete (works like zsh)
- # You set the mode with Set-PSReadLineKeyHandler -Key Tab -Function <mode>
- # CompletionResult Arguments:
- # 1) CompletionText text to be used as the auto completion result
- # 2) ListItemText text to be displayed in the suggestion list
- # 3) ResultType type of completion result
- # 4) ToolTip text for the tooltip with details about the object
- switch ($Mode) {
- # bash like
- "Complete" {
- if ($Values.Length -eq 1) {
- __{pkgname}_debug "Only one completion left"
- # insert space after value
- [System.Management.Automation.CompletionResult]::new($($comp.Name | __{pkgname}_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
- } else {
- # Add the proper number of spaces to align the descriptions
- while($comp.Name.Length -lt $Longest) {
- $comp.Name = $comp.Name + " "
- }
- # Check for empty description and only add parentheses if needed
- if ($($comp.Description) -eq " " ) {
- $Description = ""
- } else {
- $Description = " ($($comp.Description))"
- }
- [System.Management.Automation.CompletionResult]::new("$($comp.Name)$Description", "$($comp.Name)$Description", 'ParameterValue', "$($comp.Description)")
- }
- }
- # zsh like
- "MenuComplete" {
- # insert space after value
- # MenuComplete will automatically show the ToolTip of
- # the highlighted value at the bottom of the suggestions.
- [System.Management.Automation.CompletionResult]::new($($comp.Name | __{pkgname}_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
- }
- # TabCompleteNext and in case we get something unknown
- Default {
- # Like MenuComplete but we don't want to add a space here because
- # the user need to press space anyway to get the completion.
- # Description will not be shown because that's not possible with TabCompleteNext
- [System.Management.Automation.CompletionResult]::new($($comp.Name | __{pkgname}_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
- }
- }
- }
- }
- ###-end-{pkgname}-completion-###
|