Skip to content

Commit

Permalink
fix: add command help, fixed variable wrong export
Browse files Browse the repository at this point in the history
  • Loading branch information
axiaoan committed Jun 28, 2022
1 parent 5f50849 commit 6ef4bc1
Show file tree
Hide file tree
Showing 7 changed files with 364 additions and 251 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ Register-Completion rc_object "

`Register-Completion` module export the variables:

+ `$cache_all_completion`: cache all the avaliable completion
+ `$cache_command_list`: cache the register completion list
+ `$CacheAllCompletions`: cache all the avaliable completion
+ `$CacheCommands`: cache the register completion list

## License

Expand Down
209 changes: 209 additions & 0 deletions src/Completion.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
[hashtable]$CacheAllCompletions = @{}
[hashtable]$CacheCommands = @{}

<#
.SYNOPSIS
Convert to hashtable format.
.DESCRIPTION
Recursive conversion of data to hashtable format. hashtable values will be converted to hashtable.
e.g.
@{arg1 = "arg1_1"} -> @{arg1 = @{arg1_1 = ""}}
.PARAMETER InputObject
Input data, support for basic data types
.EXAMPLE
ConvertTo-Hash "arg"
Convert string to hashtable format
.EXAMPLE
ConvertTo-Hash 100
Convert number to hashtable format
.EXAMPLE
ConvertTo-Hash "['hello','world']"
Convert Javascript array to hashtable format
.EXAMPLE
ConvertTo-Hash "[{arg: {arg_1: 'arg_1_1'}}]"
Convert Javascript array object to hashtable format
.EXAMPLE
ConvertTo-Hash "[{arg: {arg_1: {arg_1_1: ['arg_1_1_1', 'arg_1_1_2']}}}]"
Convert Javascript nested array object to hashtable format
.EXAMPLE
ConvertTo-Hash "[100, 'hello', {arg1: 'arg1_1'}, ['arg2', 'arg3']]"
Convert Javascript array to hashtable format
.EXAMPLE
ConvertTo-Hash @("arg1", "arg2")
Convert array to hashtable format
.EXAMPLE
ConvertTo-Hash @("arg1", @{arg2 = "arg2_1"; arg3 = @("arg3_1", "arg3_2")})
Convert nested array to hashtable format
.EXAMPLE
@("arg1", "arg2") | ConvertTo-Hash
Convert array to hashtable format by pipeline input
.INPUTS
None.
.OUTPUTS
System.Collections.Hashtable
#>
function ConvertTo-Hash {
Param($InputObject)

if (!$InputObject) {
return ""
}

[hashtable]$hash = @{}
$inputType = $InputObject.getType()

if ($inputType -eq [hashtable]) {
$InputObject.Keys | ForEach-Object { $hash[$_] = ConvertTo-Hash $InputObject[$_] }
}
elseif ($inputType -eq [Object[]]) {
$InputObject | ForEach-Object { $hash += ConvertTo-Hash $_ }
}
else {
try {
$json = ConvertFrom-Json -InputObject $InputObject -AsHashtable
if ($json.getType() -in [hashtable],[Object[]]) {
$hash = ConvertTo-Hash $json
}
else {
$hash.Add($json, "")
}
}
catch {
$hash.Add($InputObject, "")
}
}
return $hash
}

<#
.SYNOPSIS
Get the completion keys.
.DESCRIPTION
According to the input word and data, return the corresponding command keys.
it usually used in the cmdlet `Register-ArgumentCompleter`, when provide datasets, it will return the right completion keys.
.PARAMETER Word
The input word. From `$wordToComplete`
.PARAMETER Ast
The input data. From `$commandAst`
.PARAMETER HashList
The datasets, support basic data types.
.EXAMPLE
Get-CompletionKeys "" "case" "hello","world"
Returns `hello` and `world`
.EXAMPLE
Get-CompletionKeys "h" "case h" "hello","world"
Returns `hello`
.EXAMPLE
Get-CompletionKeys "" "case h" "hello","world"
Returns None.
.INPUTS
None.
.OUTPUTS
System.Array
#>
function Get-CompletionKeys {
Param([string]$Word, $Ast, $HashList)

if (!$HashList) {
return @()
}

$arr = $Ast.ToString().Split().ToLower() | Where-Object { $null -ne $_ }

# Empty, need to return children completion keys
if (!$Word) {
[string]$key = ($arr -join ".").trim(".")
$keyLevel = $arr
}
# Character, need to return sibling completion keys
else {
[string]$key = (($arr | Select-Object -SkipLast 1) -join ".").trim(".")
$keyLevel = $key | ForEach-Object { $_.split(".") }
}

if (!$CacheAllCompletions.ContainsKey($key)) {
$map = ConvertTo-Hash $HashList
$prefix = ""
$keyLevel | ForEach-Object {
if ($prefix) {
$map = $map[$_]
$prefix = "$prefix.$($_)"
}
else {
$prefix = $_
}
if (!$CacheAllCompletions.ContainsKey($prefix)) {
$CacheAllCompletions[$prefix] = $map.Keys
}
}
}

$CacheAllCompletions[$key] |
Where-Object { $_ -Like "*$Word*" } |
Sort-Object -Property @{Expression = { $_.ToString().StartsWith($Word) }; Descending = $true }, @{Expression = { $_.ToString().indexOf($Word) }; Descending = $false }, @{Expression = { $_ }; Descending = $false }
}

function Remove-Completion {
Param([string]$Command)

$CacheCommands.Remove($Command)
$CacheAllCompletions.Clone().Keys |
Where-Object { $_.StartsWith("$Command.") -or ($_ -eq $Command) } |
ForEach-Object { $CacheAllCompletions.Remove($_) }
}

<#
.SYNOPSIS
Register a completion.
.DESCRIPTION
Register a completion. provide the command name and the completion datasets. when type the command name, and press `Tab`, it will show the completion keys.
.PARAMETER Command
The command name.
.PARAMETER HashList
The datasets, support basic data types.
.PARAMETER Force
Enable replaced the existing completion. default is false.
.EXAMPLE
New-Completion demo "hello","world"
Register a completion with command name `demo` and datasets `hello`、`world`.
Press `demo <Tab>` will get `demo hello`
.EXAMPLE
New-Completion demo "100" -Force
Replace the existing completion with command name `demo` and datasets `100`.
Press `demo <Tab>` will get `demo 100`
.INPUTS
None.
.OUTPUTS
None.
#>
function New-Completion {
Param(
[string]$Command,
$HashList,
[switch]$Force = $false
)

if ($CacheCommands.ContainsKey($Command)) {
if ($Force) {
Remove-Completion $Command
}
else {
return
}
}
$CacheCommands.Add($Command, $HashList)

Register-ArgumentCompleter -Native -CommandName $Command -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
[Console]::InputEncoding = [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new()

$cmd = $commandAst.CommandElements[0].Value
$cmdHashList = $CacheCommands[$cmd]

if ($null -ne $cmdHashList) {
Get-CompletionKeys $wordToComplete $commandAst $cmdHashList |
ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ PowerShellVersion = '5.0'
# NestedModules = @()

# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = 'ConvertTo-Hash', 'Get-CompletionKeys', 'Register-Completion'
FunctionsToExport = 'New-Completion', 'Get-CompletionKeys', 'ConvertTo-Hash'

# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = @()

# Variables to export from this module
VariablesToExport = 'cache_all_completion', 'cache_command_list'
VariablesToExport = 'CacheAllCompletions', 'CacheCommands'

# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = @()
Expand Down Expand Up @@ -123,7 +123,7 @@ PrivateData = @{
} # End of PrivateData hashtable

# HelpInfo URI of this module
# HelpInfoURI = ''
HelpInfoURI = 'https:/aliuq/Register-Completion'

# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''
Expand Down
10 changes: 10 additions & 0 deletions src/Register-Completion.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
if (Get-Module New-Completion) { return }

. $PSScriptRoot\Completion.ps1

$exportModuleMemberParams = @{
Function = @('New-Completion', 'Get-CompletionKeys', 'ConvertTo-Hash')
Variable = @('CacheAllCompletions', 'CacheCommands')
}
Export-ModuleMember @exportModuleMemberParams

116 changes: 0 additions & 116 deletions src/Register-Completion/Register-Completion.ps1

This file was deleted.

3 changes: 0 additions & 3 deletions src/Register-Completion/Register-Completion.psm1

This file was deleted.

Loading

0 comments on commit 6ef4bc1

Please sign in to comment.