X Tutup
Skip to content
22 changes: 22 additions & 0 deletions src/System.Management.Automation/engine/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1311,6 +1311,28 @@ private static Type GetCommonType(Type minType, Type maxType)

return resultType;
}

/// <summary>
/// Returns only the elements that passed the attribute's validation.
/// </summary>
/// <param name="elementsToValidate">The objects to validate.</param>
internal IEnumerable GetValidatedElements(IEnumerable elementsToValidate)
{
foreach (var el in elementsToValidate)
{
try
{
ValidateElement(el);
}
catch (ValidationMetadataException)
{
// Element was not in range - drop
continue;
}

yield return el;
}
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1770,28 +1770,36 @@ private static void ProcessParameter(
{
RemoveLastNullCompletionResult(result);

string enumString = LanguagePrimitives.EnumSingleTypeConverter.EnumValues(parameterType);
string separator = CultureInfo.CurrentUICulture.TextInfo.ListSeparator;
string[] enumArray = enumString.Split(separator, StringSplitOptions.RemoveEmptyEntries);
IEnumerable enumValues = LanguagePrimitives.EnumSingleTypeConverter.GetEnumValues(parameterType);

// Exclude values not accepted by ValidateRange-attributes
foreach (ValidateArgumentsAttribute att in parameter.Parameter.ValidationAttributes)
{
if (att is ValidateRangeAttribute rangeAtt)
{
enumValues = rangeAtt.GetValidatedElements(enumValues);
}
}

string wordToComplete = context.WordToComplete ?? string.Empty;
string quote = HandleDoubleAndSingleQuote(ref wordToComplete);

var pattern = WildcardPattern.Get(wordToComplete + "*", WildcardOptions.IgnoreCase);
var enumList = new List<string>();

foreach (string value in enumArray)
foreach (Enum value in enumValues)
{
if (wordToComplete.Equals(value, StringComparison.OrdinalIgnoreCase))
string name = value.ToString();
if (wordToComplete.Equals(name, StringComparison.OrdinalIgnoreCase))
{
string completionText = quote == string.Empty ? value : quote + value + quote;
fullMatch = new CompletionResult(completionText, value, CompletionResultType.ParameterValue, value);
string completionText = quote == string.Empty ? name : quote + name + quote;
fullMatch = new CompletionResult(completionText, name, CompletionResultType.ParameterValue, name);
continue;
}

if (pattern.IsMatch(value))
if (pattern.IsMatch(name))
{
enumList.Add(value);
enumList.Add(name);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2085,6 +2085,14 @@ internal static string EnumValues(Type enumType)
return string.Join(CultureInfo.CurrentUICulture.TextInfo.ListSeparator, enumHashEntry.names);
}

/// <summary>
/// Returns all values for the provided enum type.
/// </summary>
/// <param name="enumType">The enum type to retrieve values from.</param>
/// <returns>Array of enum values for the specified type.</returns>
internal static Array GetEnumValues(Type enumType)
=> EnumSingleTypeConverter.GetEnumHashEntry(enumType).values;

public override object ConvertFrom(object sourceValue, Type destinationType, IFormatProvider formatProvider, bool ignoreCase)
{
return EnumSingleTypeConverter.BaseConvertFrom(sourceValue, destinationType, formatProvider, ignoreCase, false);
Expand Down
25 changes: 25 additions & 0 deletions test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -1345,6 +1345,31 @@ ConstructorTestClass(int i, bool b)
$res.CompletionMatches[1].CompletionText | Should -BeExactly 'Configuration'
}

It 'Tab completion for enum parameter is filtered against <Name>' -TestCases @(
@{ Name = 'ValidateRange with enum-values'; Attribute = '[ValidateRange([System.ConsoleColor]::Blue, [System.ConsoleColor]::Cyan)]' }
@{ Name = 'ValidateRange with int-values'; Attribute = '[ValidateRange(9, 11)]' }
@{ Name = 'multiple ValidateRange-attributes'; Attribute = '[ValidateRange([System.ConsoleColor]::Blue, [System.ConsoleColor]::Cyan)][ValidateRange([System.ConsoleColor]::Gray, [System.ConsoleColor]::Red)]' }
) {
param($Name, $Attribute)
$functionDefinition = 'param ( {0}[consolecolor]$color )' -f $Attribute
Set-Item -Path function:baz -Value $functionDefinition
$inputStr = 'baz -color '
$res = TabExpansion2 -inputScript $inputStr -cursorColumn $inputStr.Length
$res.CompletionMatches | Should -HaveCount 3
$res.CompletionMatches[0].CompletionText | Should -BeExactly 'Blue'
$res.CompletionMatches[1].CompletionText | Should -BeExactly 'Cyan'
$res.CompletionMatches[2].CompletionText | Should -BeExactly 'Green'
}

It 'Tab completion for enum parameter is filtered with ValidateRange using rangekind' {
$functionDefinition = 'param ( [ValidateRange([System.Management.Automation.ValidateRangeKind]::NonPositive)][consolecolor]$color )' -f $Attribute
Set-Item -Path function:baz -Value $functionDefinition
$inputStr = 'baz -color '
$res = TabExpansion2 -inputScript $inputStr -cursorColumn $inputStr.Length
$res.CompletionMatches | Should -HaveCount 1
$res.CompletionMatches[0].CompletionText | Should -BeExactly 'Black' # 0 = NonPositive
}

It "Test [CommandCompletion]::GetNextResult" {
$inputStr = "Get-Command -Type Alias,c"
$res = TabExpansion2 -inputScript $inputStr -cursorColumn $inputStr.Length
Expand Down
X Tutup