使用散列表优化函数创建和随后的自动完成配置



首要问题

我的问题是是否有可能用哈希表优化函数的创建和随后的自动完成设置。

我想优化的函数,例如在下面的哈希表上使用ForEach:

Function wu([string]$PackageName) {winget upgrade --include-unknown $PackageName}
Function wui([string]$PackageName) {winget upgrade -i $PackageName}
Function wi([string]$PackageName) {winget install $PackageName}
Function wii([string]$PackageName) {winget install -i -e $PackageName}
Function ws([string]$PackageName) {winget search $PackageName}

随后的自动完成设置,我已经为我创建的wu函数调整了-CommandName"$Local:ast".Replace('wu ', 'winget upgrade ')",需要为上面的每个其他Function进行调整。原始自动完成的来源是https://github.com/microsoft/winget-cli/blob/master/doc/Completion.md

据我所知,我需要为每一个Function创建这个。我想优化,例如,与ForEach调用以及:

Register-ArgumentCompleter -Native -CommandName wu -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
[Console]::InputEncoding = [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new()
$Local:word = $wordToComplete.Replace('"', '""')
$Local:ast = $commandAst.ToString().Replace('"', '""')
winget complete --word="$Local:word" --commandline "$Local:ast".Replace('wu ', 'winget upgrade ') --position $cursorPosition | ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
}

这是我创建的哈希表,我不能正确地使用它们来创建Functions和自动完成配置:

$functions = @{
"wu" = "winget upgrade --include-unknown";
"wui" = "winget upgrade -i -e";
"wi" = "winget install -i";
"wii" = "winget install -i -e";
"ws" = "winget search"
}

我尝试这样创建函数,但它不计算表达式:

ForEach($item in $functions.keys) {                                                   
[Microsoft.PowerShell.PSConsoleReadLine]::Insert("Function $item ([string]$PackageName) {$($functions[$item])}")
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
}


辅助问题(已回答)

我仍然有两个代码块用于自动完成部分。一个用于原始的winget命令(包含-CommandName winget--commandline "$Local:ast"),另一个用于我的散列表命令(包含-CommandName $funcName--commandline "$Local:new_ast")。我可以将它们整齐地组合成一个代码块吗?

# Hashtable autocomplete configuration
foreach($funcName in $functions.PSBase.Keys){
Register-ArgumentCompleter -Native -CommandName $funcName -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
[Console]::InputEncoding = [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new()
$Local:word = $wordToComplete.Replace('"', '""')
$Local:ast = $commandAst.ToString().Replace('"', '""')
$Local:new_ast = $Local:ast -replace '^w[uis]{1,2}b', {
if($functions.ContainsKey($_.Value)){ return $functions[$_.Value] } return $_.Value
}
winget complete --word="$Local:word" --commandline "$Local:new_ast" --position $cursorPosition | ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
}
}
# Original autocomplete configuration
Register-ArgumentCompleter -Native -CommandName winget -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
[Console]::InputEncoding = [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new()
$Local:word = $wordToComplete.Replace('"', '""')
$Local:ast = $commandAst.ToString().Replace('"', '""')
winget complete --word="$Local:word" --commandline "$Local:ast" --position $cursorPosition | ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
}

我认为这样的东西可能会起作用,因为winget会被正则表达式忽略,因为它不在函数哈希表中。但我不能找出语法,因为类型是KeyCollection:

foreach($funcName in $($functions.PSBase.Keys + @{'winget'}))
答案

完成的结果在我的$PROFILE感谢@mathias-r-jessen:

$functions = @{
"wu" = "winget upgrade --include-unknown";
"wui" = "winget upgrade -i -e";
"wi" = "winget install -i";
"wii" = "winget install -i -e";
"ws" = "winget search"
}
foreach($funcName in $functions.PSBase.Keys){
New-Item function: -Name $funcName -Value $([scriptblock]::Create($functions[$funcName])) | Out-Null
}
foreach($funcName in @($functions.PSBase.Keys; 'winget')){
Register-ArgumentCompleter -Native -CommandName $funcName -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
[Console]::InputEncoding = [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new()
$Local:word = $wordToComplete.Replace('"', '""')
$Local:ast = $commandAst.ToString().Replace('"', '""')
$Local:new_ast = $Local:ast -replace '^w[uis]{1,2}b', {
if($functions.ContainsKey($_.Value)){ return $functions[$_.Value] } return $_.Value
}
winget complete --word="$Local:word" --commandline "$Local:new_ast" --position $cursorPosition | ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
}
}

以编程方式注册函数就像在functions:驱动器中创建新项一样简单:

$functions = @{
"wu" = "winget upgrade --include-unknown";
"wui" = "winget upgrade -i -e";
"wi" = "winget install -i";
"wii" = "winget install -i -e";
"ws" = "winget search"
}
foreach($funcName in $functions.PSBase.Keys){
New-Item function: -Name $funcName -Value $functions[$funcName]
}

这将注册表中的所有键值条目,使用键作为函数名,并将值作为函数体的源代码。

确保在全局作用域中执行此代码(例如:通过从配置文件脚本调用注册代码,或者通过显式导出结果函数(如果是模块的一部分)。

对于参数补全器,使用-replace来搜索任何以w开头的2或3个字母的单词,然后使用scriptblock作为匹配求值器来查找正确的翻译:

$functions = @{
"wu" = "winget upgrade --include-unknown";
"wui" = "winget upgrade -i -e";
"wi" = "winget install -i";
"wii" = "winget install -i -e";
"ws" = "winget search"
}
$commandLine = 'wu somePackage'
$commandLine -replace '^w[uis]{1,2}b', {
if($functions.ContainsKey($_.Value)){
return $functions[$_.Value]
}
return $_.Value
}

$translated现在保存字符串值"winget upgrade --include-unknown somePackage"


在6.1之前的PowerShell版本中,您可以通过直接调用[regex]::Replace()来实现相同的功能:

$functions = @{
"wu" = "winget upgrade --include-unknown";
"wui" = "winget upgrade -i -e";
"wi" = "winget install -i";
"wii" = "winget install -i -e";
"ws" = "winget search"
}
$commandLine = 'wu somePackage'
$translated = [regex]::Replace($commandLine, '^w[uis]{1,2}b', {
param($match)
if($functions.ContainsKey($match.Value)){
return $functions[$match.Value]
}
return $match.Value
})

最新更新