Skip to content

Commit

Permalink
Merge pull request #9307 from Luap99/powershell-completion
Browse files Browse the repository at this point in the history
Add powershell completions
  • Loading branch information
openshift-merge-robot committed Mar 29, 2021
2 parents 00792f8 + 6a78fca commit 08eab3f
Show file tree
Hide file tree
Showing 6 changed files with 481 additions and 13 deletions.
3 changes: 2 additions & 1 deletion Makefile
Expand Up @@ -536,6 +536,7 @@ install.completions:
install ${SELINUXOPT} -d -m 755 ${DESTDIR}${FISHINSTALLDIR}
install ${SELINUXOPT} -m 644 completions/fish/podman.fish ${DESTDIR}${FISHINSTALLDIR}
install ${SELINUXOPT} -m 644 completions/fish/podman-remote.fish ${DESTDIR}${FISHINSTALLDIR}
# There is no common location for powershell files so do not install them. Users have to source the file from their powershell profile.

.PHONY: install.cni
install.cni:
Expand Down Expand Up @@ -658,7 +659,7 @@ install.libseccomp.sudo:
.PHONY: completions
completions: podman podman-remote
# key = shell, value = completion filename
declare -A outfiles=([bash]=%s [zsh]=_%s [fish]=%s.fish);\
declare -A outfiles=([bash]=%s [zsh]=_%s [fish]=%s.fish [powershell]=%s.ps1);\
for shell in $${!outfiles[*]}; do \
for remote in "" "-remote"; do \
podman="podman$$remote"; \
Expand Down
8 changes: 7 additions & 1 deletion cmd/podman/completion/completion.go
Expand Up @@ -21,7 +21,7 @@ const (
var (
file string
noDesc bool
shells = []string{"bash", "zsh", "fish"}
shells = []string{"bash", "zsh", "fish", "powershell"}
completionCmd = &cobra.Command{
Use: fmt.Sprintf("completion [options] {%s}", strings.Join(shells, "|")),
Short: "Generate shell autocompletions",
Expand Down Expand Up @@ -76,6 +76,12 @@ func completion(cmd *cobra.Command, args []string) error {
}
case "fish":
err = cmd.Root().GenFishCompletion(w, !noDesc)
case "powershell":
if noDesc {
err = cmd.Root().GenPowerShellCompletion(w)
} else {
err = cmd.Root().GenPowerShellCompletionWithDesc(w)
}
}

if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions cmd/podman/root.go
Expand Up @@ -3,7 +3,7 @@ package main
import (
"fmt"
"os"
"path"
"path/filepath"
"runtime"
"runtime/pprof"
"strings"
Expand Down Expand Up @@ -57,7 +57,7 @@ Options:

var (
rootCmd = &cobra.Command{
Use: path.Base(os.Args[0]) + " [options]",
Use: filepath.Base(os.Args[0]) + " [options]",
Long: "Manage pods, containers and images",
SilenceUsage: true,
SilenceErrors: true,
Expand Down
227 changes: 227 additions & 0 deletions completions/powershell/podman-remote.ps1
@@ -0,0 +1,227 @@
# powershell completion for podman-remote -*- shell-script -*-

function __podman-remote_debug {
if ($env:BASH_COMP_DEBUG_FILE) {
"$args" | Out-File -Append -FilePath "$env:BASH_COMP_DEBUG_FILE"
}
}

filter __podman-remote_escapeStringWithSpecialChars {
$_ -replace '\s|#|@|\$|;|,|''|\{|\}|\(|\)|"|`|\||<|>|&','`$&'
}

Register-ArgumentCompleter -CommandName 'podman-remote' -ScriptBlock {
param(
$WordToComplete,
$CommandAst,
$CursorPosition
)

# Get the current command line and convert into a string
$Command = $CommandAst.CommandElements
$Command = "$Command"

__podman-remote_debug ""
__podman-remote_debug "========= starting completion logic =========="
__podman-remote_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)
}
__podman-remote_debug "Truncated command: $Command"

$ShellCompDirectiveError=1
$ShellCompDirectiveNoSpace=2
$ShellCompDirectiveNoFileComp=4
$ShellCompDirectiveFilterFileExt=8
$ShellCompDirectiveFilterDirs=16

# 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 __complete $Arguments"
__podman-remote_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]
}
__podman-remote_debug "New WordToComplete: $WordToComplete"


# Check for flag with equal sign
$IsEqualFlag = ($WordToComplete -Like "--*=*" )
if ( $IsEqualFlag ) {
__podman-remote_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.
__podman-remote_debug "Adding extra empty parameter"
# We need to use `"`" to pass an empty argument a "" or '' does not work!!!
$RequestComp="$RequestComp" + ' `"`"'
}

__podman-remote_debug "Calling $RequestComp"
#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


# get directive from last line
[int]$Directive = $Out[-1].TrimStart(':')
if ($Directive -eq "") {
# There is no directive specified
$Directive = 0
}
__podman-remote_debug "The completion directive is: $Directive"

# remove directive (last element) from out
$Out = $Out | Where-Object { $_ -ne $Out[-1] }
__podman-remote_debug "The completions are: $Out"

if (($Directive -band $ShellCompDirectiveError) -ne 0 ) {
# Error code. No completion.
__podman-remote_debug "Received error from custom completion go code"
return
}
$Longest = 0
$Values = $Out | ForEach-Object {
#Split the output in name and description
$Name, $Description = $_.Split("`t",2)
__podman-remote_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 = " "
if (($Directive -band $ShellCompDirectiveNoSpace) -ne 0 ) {
# remove the space here
__podman-remote_debug "ShellCompDirectiveNoSpace is called"
$Space = ""
}
if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) {
__podman-remote_debug "ShellCompDirectiveNoFileComp is called"
if ($Values.Length -eq 0) {
# Just print an empty string here so the
# shell does not start to complete paths.
# We cannot use CompletionResult here because
# it does not accept an empty string as argument.
""
return
}
}
if ((($Directive -band $ShellCompDirectiveFilterFileExt) -ne 0 ) -or
(($Directive -band $ShellCompDirectiveFilterDirs) -ne 0 )) {
__podman-remote_debug "ShellCompDirectiveFilterFileExt ShellCompDirectiveFilterDirs are not supported"

# return here to prevent the completion of the extensions
return
}

$Values = $Values | Where-Object {
# filter the result
$_.Name -like "$WordToComplete*"

# Join the flag back if we have a equal sign flag
if ( $IsEqualFlag ) {
__podman-remote_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
__podman-remote_debug "Mode: $Mode"

$Values | ForEach-Object {

# store temporay 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) {
__podman-remote_debug "Only one completion left"

# insert space after value
[System.Management.Automation.CompletionResult]::new($($comp.Name | __podman-remote_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 | __podman-remote_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 thats not possible with TabCompleteNext
[System.Management.Automation.CompletionResult]::new($($comp.Name | __podman-remote_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
}
}

}
}

# This file is generated with "podman-remote completion"; see: podman-completion(1)

0 comments on commit 08eab3f

Please sign in to comment.