Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

{Core} Proof of concept for PowerShell argument completion #13576

Draft
wants to merge 2 commits into
base: dev
Choose a base branch
from

Conversation

tibortakacs
Copy link

@tibortakacs tibortakacs commented May 19, 2020

Resolve #2324

Require kislyuk/argcomplete#302

This is a proof of concept implementation of Azure CLI argument completion in PowerShell.

Not ready to be merged.

It is based on this approach, please find the details there:
https://github.com/tibortakacs/powershell-argcomplete

How to use:

  • Install Azure CLI on the normal way.
  • . az.completion.ps1 (Dot source the completion script).
  • Use tab or ctrl+space to invoke argument completion on PowerShell.

@yonzhan yonzhan added this to the S171 milestone May 20, 2020
@yonzhan
Copy link
Collaborator

yonzhan commented May 20, 2020

Nice PoC to support PowerShell argument completion

@jiasli
Copy link
Member

jiasli commented May 20, 2020

+ Azure PowerShell owner of auto-complete @isra-fel

@jiasli
Copy link
Member

jiasli commented May 20, 2020

FYI, this is the corresponding Bash script to enable auto-complete using argcomplete:

$ register-python-argcomplete az

# Run something, muting output or redirecting it to the debug stream
# depending on the value of _ARC_DEBUG.
__python_argcomplete_run() {
    if [[ -z "$_ARC_DEBUG" ]]; then
        "$@" 8>&1 9>&2 1>/dev/null 2>&1
    else
        "$@" 8>&1 9>&2 1>&9 2>&1
    fi
}

_python_argcomplete() {
    local IFS=$'\013'
    local SUPPRESS_SPACE=0
    if compopt +o nospace 2> /dev/null; then
        SUPPRESS_SPACE=1
    fi
    COMPREPLY=( $(IFS="$IFS" \
                  COMP_LINE="$COMP_LINE" \
                  COMP_POINT="$COMP_POINT" \
                  COMP_TYPE="$COMP_TYPE" \
                  _ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS" \
                  _ARGCOMPLETE=1 \
                  _ARGCOMPLETE_SUPPRESS_SPACE=$SUPPRESS_SPACE \
                  __python_argcomplete_run "$1") )
    if [[ $? != 0 ]]; then
        unset COMPREPLY
    elif [[ $SUPPRESS_SPACE == 1 ]] && [[ "$COMPREPLY" =~ [=/:]$ ]]; then
        compopt -o nospace
    fi
}
complete -o nospace -o default -o bashdefault -F _python_argcomplete az

@isra-fel
Copy link
Member

An idea about how to enable autocomplete on startup: we can tell the user to add a line to their powershell profile, to be specific:

  1. Edit $PROFILE (this is a powershell variable that points to the actual url of the profile file), append a line: . az.completion.ps1

And I think a more official(pro) way is to publish this as a powershell module for example AzCliUtil, and expose this function as a cmdlet such as "Enable-AzCliAutoComplete". In this case customers will need to:

  1. Install-Module AzCliUtil
  2. Edit $PROFILE, append a line Enable-AzCliAutoComplete

# If there is only one completion item, it will be immediately used. In this case
# a trailing space is important to show the user that the complition for the current
# item is ready.
$items = $completionResult.Split()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Invoke-Expression failed, $completionResult will not have a Split() method and will error out.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid point. However, PowerShell argument completion engine hides all error, but you are right, it is better to cause any unexpected error. I have added a simple check there.

@jiasli jiasli modified the milestones: S171, Backlog May 20, 2020
@jiasli jiasli changed the title Proof of concept for PowerShell argument completion. {Core} Proof of concept for PowerShell argument completion May 20, 2020
* Only do Split if there were any result.
* Invoke-Expression exits from the script block in case of error. This
commit suppresses this with an empty try-catch block.
@itpropro
Copy link

Hi,
Any updates on this issue/PR?

# Since the environment variables are set, the argcomplete.autocomplete(...) function will be executed.
# The result will be printed on the standard output (see the details in the Python file).
try {
Invoke-Expression $AzCommand -OutVariable completionResult -ErrorVariable errorOut -ErrorAction SilentlyContinue | Out-Null

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need to use Invoke-Expression here, instead, you should use:

Suggested change
Invoke-Expression $AzCommand -OutVariable completionResult -ErrorVariable errorOut -ErrorAction SilentlyContinue | Out-Null
$completionResult = & $AzCommand

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is no longer applicable with the larger comment above, but leaving here as informing when not to use Invoke-Expression

Copy link

@SteveL-MSFT SteveL-MSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very interesting approach, some rework on the PowerShell side of things

}

# Mock bash with environment variable settings
New-Item -Path Env: -Name _ARGCOMPLETE -Value 1 | Out-Null # Enables tab complition in argcomplete

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very creative approach using the bash completer, however, since these env vars are for the process and gets inherited by az and then removed, it would be better to use .NET API to start the process and leveraging https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.environmentvariables?view=net-6.0#system-diagnostics-processstartinfo-environmentvariables

It would look something like:

$env = @{
  _ARGCOMPLETE = 1
  COMP_TYPE = 9
  _ARGCOMPLETE_IFS = " "
}

$psi = [System.Diagnostics.ProcessStartInfo]::new($AzCommand)
$psi.RedirectStandardError = $true
$psi.RedirectStandardOutput = $true

foreach ($var in $env.keys) {
  $psi.Environment.Add($var, $env.$var)
}

$az = [System.Diagnostics.Process]::Start($psi)
$az.Start()
$az.WaitForExit()
$completionResult = $az.StandardOutput.ReadToEnd()

# Since the environment variables are set, the argcomplete.autocomplete(...) function will be executed.
# The result will be printed on the standard output (see the details in the Python file).
try {
Invoke-Expression $AzCommand -OutVariable completionResult -ErrorVariable errorOut -ErrorAction SilentlyContinue | Out-Null

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is no longer applicable with the larger comment above, but leaving here as informing when not to use Invoke-Expression

@@ -0,0 +1,67 @@
$AzCommand = "az"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole script should probably be in a Enable-AzCompletion cmdlet and shouldn't be repeated in both a ps1 and psm1

@mgreenegit
Copy link
Member

Thank you for this contribution @tibortakacs. Please see the feedback above.

@yonzhan yonzhan requested review from bebound and removed request for arrownj and haroldrandom May 24, 2022 03:07
@mgreenegit
Copy link
Member

Following up @tibortakacs
Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support autocompletion in command line PowerShell console.
8 participants