AzureCliExpansion.ps1
# This PS script replicates the functionality in https://github.com/Azure/azure-xplat-cli/blob/90a20ee00e0741a5ec8cece69bf5e18bf1e0ecda/lib/autocomplete.js # An alternative approach would be to look at ways to directly invoke the functionality and capture the output :-) # This has a dependency on plugins json files (Use "azure --gen" to create) $installPath = Split-Path $MyInvocation.MyCommand.Path . "$installPath\utils.ps1" $global:_CLI_MODE=$null; $global:_CLI_DATA=$null; function AzureCliExpansion($line) { # TODO - error handling (e.g. azure.cmd not found, plugins.xxx.json not found) DebugMessage "autocomplete: $line" $azureCmdPath = GetAzureCmdPath $azurecliLibPath = GetAzureLibPath # Based on https://github.com/Azure/azure-xplat-cli/blob/90a20ee00e0741a5ec8cece69bf5e18bf1e0ecda/lib/util/utilsCore.js#L77 $config = Get-Content "~/.azure/config.json" | ConvertFrom-Json $mode = $config.mode DebugMessage "\tmode: $mode" if ( ($global:_CLI_MODE -eq $mode) -and ($global:_CLI_DATA -ne $null)) { $plugins = $global:_CLI_DATA } else { # Based on https://github.com/Azure/azure-xplat-cli/blob/90a20ee00e0741a5ec8cece69bf5e18bf1e0ecda/lib/autocomplete.js#L26 $datafile = "$azurecliLibPath/plugins.$mode.json" $plugins = Get-Content $datafile | ConvertFrom-Json $global:_CLI_MODE = $mode $global:_CLI_DATA = $plugins } # Based on https://github.com/Azure/azure-xplat-cli/blob/90a20ee00e0741a5ec8cece69bf5e18bf1e0ecda/lib/autocomplete.js#L49 $args = $line.Split(' ') | ?{ $_ -ne ''} | %{ $_.Trim() } # start from 1, so to discard "azure" word $currentCategory = $plugins; for ($index = 1; $index -lt $args.Length; $index++){ $arg = $args[$index] $parentCategory = $currentCategory if ( ($index -eq $args.Length -1) -and (-not $line.EndsWith(" ")) ) { # bail early if no space at the end of the line to avoid bogus completion. # i.e. don't match "vm" commands for "azure vm", only for "azure vm " # otherwise the vm command is replaced with the child commands! return $currentCategory.commands | where Name -eq $arg } $currentCategory = $currentCategory.categories.psobject.Properties[$arg].Value DebugMessage "\targ $($index): $arg" if( $currentCategory -eq $null){ DebugMessage "\targ $($index): $arg - no match" break } } $tempCategory = Coalesce $currentCategory $parentCategory $allSubCategoriesAndCommands = @($tempCategory.categories.PSObject.Properties | select -ExpandProperty Name) ` + @($tempCategory.commands | select -ExpandProperty Name) $currentCommand = $tempCategory.commands | where Name -eq $arg | select -First 1 # run out argument while have a valid category? if ($currentCategory -ne $null) { DebugMessage "\treturn all categories/commands (no category)" #return sub categories and command combind return $allSubCategoriesAndCommands | sort } if ($currentCommand -ne $null) { $allCommandOptions = @($currentCommand.options | select -ExpandProperty long) ` + @($currentCommand.options | select -ExpandProperty short -ErrorAction SilentlyContinue) # silent continue to ignore options without short property } # we are at the last arg, try match both categories and commands if ($index -eq $args.Length -1) { if ($currentCommand -ne $null) { DebugMessage "\treturn all commands" return $allCommandOptions | sort } else { DebugMessage "\treturn matches on prefix: $arg" return $allSubCategoriesAndCommands | ?{ $_.StartsWith($arg) } | sort } } # try to match a command's options $lastArg = $args[$args.Length - 1] if( ($currentCommand -ne $null) -and ($lastArg.StartsWith('-') ) ) { $option = $currentCommand.options | ?{ $_.fileRelatedOption -and ($_.short -eq $lastArg -or $_.long -eq $lastArg ) } | select -First 1 if ($option -ne $null) { # return this.reply(fs.readdirSync(process.cwd())); # Default PS behaviour is to complete files :-) DebugMessage "\treturn to allow default PowerShell file matching" return } else { DebugMessage "\treturn matches on lastArg: $lastArg" return $allCommandOptions | ?{ $_.StartsWith($lastArg) } | sort } } DebugMessage "\treturn all categories/commands" return $allSubCategoriesAndCommands | sort } # TODO - look at posh-git/posh-hg to link with powertab DebugMessage "Installing..." if(-not (Test-Path Function:\AzureCliTabExpansionBackup)){ if (Test-Path Function:\TabExpansion) { DebugMessage "\tbackup previous TabExpansion" Rename-Item Function:\TabExpansion AzureCliTabExpansionBackup } DebugMessage "\tInstalling TabExpansion hook" function TabExpansion($line, $lastWord) { $lastBlock = [regex]::Split($line, '[|;]')[-1].TrimStart() switch -Regex ($lastBlock) { "^azure (.*)" { AzureCliExpansion $lastBlock } # Fall back on existing tab expansion default { if (Test-Path Function:\AzureCliTabExpansionBackup) { AzureCliTabExpansionBackup $line $lastWord } } } } } |