根据另一个参数的已指定值用 Tab 键完成一个参数值
Tab-complete a parameter value based on another parameter's already specified value
这个自我回答的问题针对以下场景:
给定命令的自定义制表符完成是否可以根据先前传递给同一命令行上的另一个参数的值动态确定完成,使用参数级 [ArgumentCompleter()]
attribute or the Register-ArgumentCompleter
cmdlet?
如果是这样,这种方法的局限性是什么?
示例场景:
假设的 Get-Property
命令有一个接受任何类型对象的 -Object
参数,以及一个接受 属性 名称的 -Property
参数,其值从对象中提取。
现在,在键入 Get-Property
调用的过程中,如果已经为 -Object
指定了一个值,制表符完成 -Property
应该循环指定对象的名称(public) 个属性。
$obj = [pscustomobject] @{ foo = 1; bar = 2; baz = 3 }
Get-Property -Object $obj -Property # <- pressing <tab> here should cycle
# through 'foo', 'bar', 'baz'
以下解决方案使用参数特定的 [ArgumentCompleter()]
属性作为 Get-Property
函数本身定义的一部分,但该解决方案类似地适用于通过 Register-CommandCompleter
命令。
限制:
PowerShell 调用的自定义完成脚本块 ({ ... }
) 从根本上说 只能看到通过 参数 指定的值,而不是通过管道.
- 也就是说,如果您键入
Get-Property -Object $obj -Property <tab>
,脚本块可以确定 $obj
的值将绑定到 -Object
参数,但这不起作用与
$obj | Get-Property -Property <tab>
(即使 -Object
被声明为管道绑定)。
即使在通过参数指定的那些值中,也只有可以评估的值没有副作用 实际上在脚本块中是可访问的;具体来说,这意味着:
- 文字 值(例如,
-Object ([pscustomobject] @{ foo = 1; bar = 2; baz = 3 })
- 简单变量引用(例如,
-Object $obj
)或属性-access或index-access 表达式(例如,-Object $obj.Foo
或 -Object $obj[0]
)
- 值得注意的是,以下值不可访问:
- 方法-调用结果(例如,
-Object $object.Foo()
)
- 命令输出(通过
(...)
、$(...)
或@(...)
,例如
-Object (Invoke-RestMethod http://example.org)
)
- 此限制的原因是在实际提交命令之前评估这些值可能会产生不良副作用和/或可能需要很长时间才能完成。
function Get-Property {
param(
[object] $Object,
[ArgumentCompleter({
# A fixed list of parameters is passed to an argument-completer script block.
# Here, only two are of interest:
# * $wordToComplete:
# The part of the value that the user has typed so far, if any.
# * $preBoundParameters (called $fakeBoundParameters
# in the docs):
# A hashtable of those (future) parameter values specified so
# far that are side effect-free (see above).
param($cmdName, $paramName, $wordToComplete, $cmdAst, $preBoundParameters)
# Was a side effect-free value specified for -Object?
if ($obj = $preBoundParameters['Object']) {
# Get all property names of the objects and filter them
# by the partial value already typed, if any,
# interpreted as a name prefix.
@($obj.psobject.Properties.Name) -like "$wordToComplete*"
}
})]
[string] $Property
)
# ...
}
这个自我回答的问题针对以下场景:
给定命令的自定义制表符完成是否可以根据先前传递给同一命令行上的另一个参数的值动态确定完成,使用参数级
[ArgumentCompleter()]
attribute or theRegister-ArgumentCompleter
cmdlet?如果是这样,这种方法的局限性是什么?
示例场景:
假设的 Get-Property
命令有一个接受任何类型对象的 -Object
参数,以及一个接受 属性 名称的 -Property
参数,其值从对象中提取。
现在,在键入 Get-Property
调用的过程中,如果已经为 -Object
指定了一个值,制表符完成 -Property
应该循环指定对象的名称(public) 个属性。
$obj = [pscustomobject] @{ foo = 1; bar = 2; baz = 3 }
Get-Property -Object $obj -Property # <- pressing <tab> here should cycle
# through 'foo', 'bar', 'baz'
以下解决方案使用参数特定的 [ArgumentCompleter()]
属性作为 Get-Property
函数本身定义的一部分,但该解决方案类似地适用于通过 Register-CommandCompleter
命令。
限制:
PowerShell 调用的自定义完成脚本块 (
{ ... }
) 从根本上说 只能看到通过 参数 指定的值,而不是通过管道.- 也就是说,如果您键入
Get-Property -Object $obj -Property <tab>
,脚本块可以确定$obj
的值将绑定到-Object
参数,但这不起作用与
$obj | Get-Property -Property <tab>
(即使-Object
被声明为管道绑定)。
- 也就是说,如果您键入
即使在通过参数指定的那些值中,也只有可以评估的值没有副作用 实际上在脚本块中是可访问的;具体来说,这意味着:
- 文字 值(例如,
-Object ([pscustomobject] @{ foo = 1; bar = 2; baz = 3 })
- 简单变量引用(例如,
-Object $obj
)或属性-access或index-access 表达式(例如,-Object $obj.Foo
或-Object $obj[0]
) - 值得注意的是,以下值不可访问:
- 方法-调用结果(例如,
-Object $object.Foo()
) - 命令输出(通过
(...)
、$(...)
或@(...)
,例如
-Object (Invoke-RestMethod http://example.org)
) - 此限制的原因是在实际提交命令之前评估这些值可能会产生不良副作用和/或可能需要很长时间才能完成。
- 方法-调用结果(例如,
- 文字 值(例如,
function Get-Property {
param(
[object] $Object,
[ArgumentCompleter({
# A fixed list of parameters is passed to an argument-completer script block.
# Here, only two are of interest:
# * $wordToComplete:
# The part of the value that the user has typed so far, if any.
# * $preBoundParameters (called $fakeBoundParameters
# in the docs):
# A hashtable of those (future) parameter values specified so
# far that are side effect-free (see above).
param($cmdName, $paramName, $wordToComplete, $cmdAst, $preBoundParameters)
# Was a side effect-free value specified for -Object?
if ($obj = $preBoundParameters['Object']) {
# Get all property names of the objects and filter them
# by the partial value already typed, if any,
# interpreted as a name prefix.
@($obj.psobject.Properties.Name) -like "$wordToComplete*"
}
})]
[string] $Property
)
# ...
}