您需要替换用于 Tab 完成的默认 PowerShell 函数,即大部分未记录的 TabExpansion2,您可以通过运行 get-content function:global:tabexpansion2 获取其内容。
因为此函数的内容在您的系统上可能有所不同,所以我不会完整地展示它,只展示相关部分,即返回计算出的选项卡完成可能性(这是来自运行在 PowerShell Core 7.3.2 x64 上的Windows 10 21H2 x64):
... rest of TabCompletion2...
End
{
if ($psCmdlet.ParameterSetName -eq 'ScriptInputSet')
{
return [System.Management.Automation.CommandCompletion]::CompleteInput(
<#inputScript#> $inputScript,
<#cursorColumn#> $cursorColumn,
<#options#> $options)
}
else
{
return [System.Management.Automation.CommandCompletion]::CompleteInput(
<#ast#> $ast,
<#tokens#> $tokens,
<#positionOfCursor#> $positionOfCursor,
<#options#> $options)
}
}
两个代码路径都调用静态 System.Management.Automation.CommandCompletion.CompleteInput 方法,根据传递给 TabExpansion2 的参数使用该方法的不同版本。
在这一点上,您可能认为我们需要深入研究这些方法的内部结构并调整它们以适应口味,但值得庆幸的是,情况并非如此。我们实际上不需要更改CommandCompletion.CompleteInput 的工作方式——我们只是想更改其建议的顺序。由于它已经完成了困难的工作,我们只需要重新排序!
因此,将 TabCompletion2 修改为以下内容:
End
{
if ($psCmdlet.ParameterSetName -eq 'ScriptInputSet')
{
$completion = [System.Management.Automation.CommandCompletion]::CompleteInput(
<#inputScript#> $inputScript,
<#cursorColumn#> $cursorColumn,
<#options#> $options)
}
else
{
$completion = [System.Management.Automation.CommandCompletion]::CompleteInput(
<#ast#> $ast,
<#tokens#> $tokens,
<#positionOfCursor#> $positionOfCursor,
<#options#> $options)
}
$exeMatches = $completion.CompletionMatches
|Where-Object { $_.CompletionText -Like "*.exe" }
$nonExeMatches = $completion.CompletionMatches
|Where-Object { $_.CompletionText -NotLike "*.exe" }
$allMatches = @($exeMatches) + @($nonExeMatches)
$completion.CompletionMatches = $allMatches
return $completion
}
它实际上非常简单:我们使用旧的 Where-Object cmdlet 来过滤 CommandCompletion 已经为我们填充的 CompletionMatches 集合,用我们排序的集合的结果覆盖这些默认匹配,然后返回它。
将这个更新的TabCompletion2安装到我们的profile中,并在通过输入.$profile并按下重新加载所述配置文件后进入, 输入 . 并按下标签现在产生了期望的结果:
> .d.exe
> .z.exe
> ..json
> ..dll
> .c.config