Avoid binding positional parameters when completing parameter in front of value (#17693)

This commit is contained in:
MartinGC94
2022-07-18 14:28:04 -07:00
committed by GitHub
parent 08baf27b80
commit b06bcee10e
3 changed files with 34 additions and 8 deletions
@@ -533,6 +533,7 @@ namespace System.Management.Automation
return result;
}
bool bindPositionalParameters = true;
if (parameterAst != null)
{
// Parent must be a command
@@ -551,10 +552,24 @@ namespace System.Management.Automation
// Parent must be a command
commandAst = (CommandAst)dashAst.Parent;
partialName = string.Empty;
// If the user tries to tab complete a new parameter in front of a positional argument like: dir -<Tab> C:\
// the user may want to add the parameter name so we don't want to bind positional arguments
if (commandAst is not null)
{
foreach (var element in commandAst.CommandElements)
{
if (element.Extent.StartOffset > context.TokenAtCursor.Extent.StartOffset)
{
bindPositionalParameters = element is CommandParameterAst;
break;
}
}
}
}
PseudoBindingInfo pseudoBinding = new PseudoParameterBinder()
.DoPseudoParameterBinding(commandAst, null, parameterAst, PseudoParameterBinder.BindingType.ParameterCompletion);
.DoPseudoParameterBinding(commandAst, null, parameterAst, PseudoParameterBinder.BindingType.ParameterCompletion, bindPositionalParameters);
// The command cannot be found or it's not a cmdlet, not a script cmdlet, not a function.
// Try completing as if it the parameter is a command argument for native command completion.
if (pseudoBinding == null)
@@ -949,8 +949,9 @@ namespace System.Management.Automation.Language
/// <param name="pipeArgumentType">Indicate the type of the piped-in argument.</param>
/// <param name="paramAstAtCursor">The CommandParameterAst the cursor is pointing at.</param>
/// <param name="bindingType">Indicates whether pseudo binding is for argument binding, argument completion, or parameter completion.</param>
/// <param name="bindPositional">Indicates if the pseudo binding should bind positional parameters</param>
/// <returns>PseudoBindingInfo.</returns>
internal PseudoBindingInfo DoPseudoParameterBinding(CommandAst command, Type pipeArgumentType, CommandParameterAst paramAstAtCursor, BindingType bindingType)
internal PseudoBindingInfo DoPseudoParameterBinding(CommandAst command, Type pipeArgumentType, CommandParameterAst paramAstAtCursor, BindingType bindingType, bool bindPositional = true)
{
if (command == null)
{
@@ -1008,12 +1009,15 @@ namespace System.Management.Automation.Language
unboundArguments = BindNamedParameters();
_bindingEffective = _currentParameterSetFlag != 0;
// positional binding
unboundArguments = BindPositionalParameter(
unboundArguments,
_currentParameterSetFlag,
_defaultParameterSetFlag,
bindingType);
if (bindPositional)
{
// positional binding
unboundArguments = BindPositionalParameter(
unboundArguments,
_currentParameterSetFlag,
_defaultParameterSetFlag,
bindingType);
}
// VFRA/pipeline binding if the given command is a binary cmdlet or a script cmdlet
if (!_function)
@@ -691,6 +691,13 @@ ConstructorTestClass(int i, bool b)
$completionText -join ' ' | Should -BeExactly 'blg csv tsv'
}
it 'Should include positionally bound parameters when completing in front of parameter value' {
$TestString = 'Get-ChildItem -^ $HOME'
$CursorIndex = $TestString.IndexOf('^')
$res = TabExpansion2 -inputScript $TestString.Remove($CursorIndex, 1) -cursorColumn $CursorIndex
$res.CompletionMatches.CompletionText | Should -Contain "-Path"
}
Context "Script name completion" {
BeforeAll {
Setup -f 'install-powershell.ps1' -Content ""