mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Add completion single/double quote support for -Noun parameter (#24977)
This commit is contained in:
@@ -8421,6 +8421,33 @@ namespace System.Management.Automation
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls Get-Command to get command info objects.
|
||||
/// </summary>
|
||||
/// <param name="fakeBoundParameters">The fake bound parameters.</param>
|
||||
/// <param name="parametersToAdd">The parameters to add.</param>
|
||||
/// <returns>Collection of command info objects.</returns>
|
||||
internal static Collection<CommandInfo> GetCommandInfo(
|
||||
IDictionary fakeBoundParameters,
|
||||
params string[] parametersToAdd)
|
||||
{
|
||||
using var ps = PowerShell.Create(RunspaceMode.CurrentRunspace);
|
||||
|
||||
ps.AddCommand("Get-Command");
|
||||
|
||||
foreach (string parameter in parametersToAdd)
|
||||
{
|
||||
if (fakeBoundParameters.Contains(parameter))
|
||||
{
|
||||
ps.AddParameter(parameter, fakeBoundParameters[parameter]);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<CommandInfo> commands = ps.Invoke<CommandInfo>();
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
internal static bool IsSplattedVariable(Ast targetExpr)
|
||||
{
|
||||
if (targetExpr is VariableExpressionAst && ((VariableExpressionAst)targetExpr).Splatted)
|
||||
|
||||
@@ -1694,40 +1694,50 @@ namespace Microsoft.PowerShell.Commands
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides argument completion for Noun parameter.
|
||||
/// </summary>
|
||||
public class NounArgumentCompleter : IArgumentCompleter
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public IEnumerable<CompletionResult> CompleteArgument(string commandName, string parameterName, string wordToComplete, CommandAst commandAst, IDictionary fakeBoundParameters)
|
||||
/// Returns completion results for Noun parameter.
|
||||
/// </summary>
|
||||
/// <param name="commandName">The command name.</param>
|
||||
/// <param name="parameterName">The parameter name.</param>
|
||||
/// <param name="wordToComplete">The word to complete.</param>
|
||||
/// <param name="commandAst">The command AST.</param>
|
||||
/// <param name="fakeBoundParameters">The fake bound parameters.</param>
|
||||
/// <returns>List of completion results.</returns>
|
||||
public IEnumerable<CompletionResult> CompleteArgument(
|
||||
string commandName,
|
||||
string parameterName,
|
||||
string wordToComplete,
|
||||
CommandAst commandAst,
|
||||
IDictionary fakeBoundParameters) => CompletionCompleters.GetMatchingResults(
|
||||
wordToComplete,
|
||||
possibleCompletionValues: GetCommandNouns(fakeBoundParameters));
|
||||
|
||||
/// <summary>
|
||||
/// Get sorted set of command nouns using Get-Command.
|
||||
/// </summary>
|
||||
/// <param name="fakeBoundParameters">The fake bound parameters.</param>
|
||||
/// <returns>Sorted set of command nouns.</returns>
|
||||
private static SortedSet<string> GetCommandNouns(IDictionary fakeBoundParameters)
|
||||
{
|
||||
if (fakeBoundParameters == null)
|
||||
{
|
||||
throw PSTraceSource.NewArgumentNullException(nameof(fakeBoundParameters));
|
||||
}
|
||||
Collection<CommandInfo> commands = CompletionCompleters.GetCommandInfo(fakeBoundParameters, "Module", "Verb");
|
||||
SortedSet<string> nouns = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var commandInfo = new CmdletInfo("Get-Command", typeof(GetCommandCommand));
|
||||
var ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace)
|
||||
.AddCommand(commandInfo)
|
||||
.AddParameter("Noun", wordToComplete + "*");
|
||||
|
||||
if (fakeBoundParameters.Contains("Module"))
|
||||
foreach (CommandInfo command in commands)
|
||||
{
|
||||
ps.AddParameter("Module", fakeBoundParameters["Module"]);
|
||||
}
|
||||
|
||||
HashSet<string> nouns = new HashSet<string>();
|
||||
var results = ps.Invoke<CommandInfo>();
|
||||
foreach (var result in results)
|
||||
{
|
||||
var dash = result.Name.IndexOf('-');
|
||||
if (dash != -1)
|
||||
string commandName = command.Name;
|
||||
int dashIndex = commandName.IndexOf('-');
|
||||
if (dashIndex != -1)
|
||||
{
|
||||
nouns.Add(result.Name.Substring(dash + 1));
|
||||
string noun = commandName.Substring(dashIndex + 1);
|
||||
nouns.Add(noun);
|
||||
}
|
||||
}
|
||||
|
||||
return nouns.Order().Select(static noun => new CompletionResult(noun, noun, CompletionResultType.Text, noun));
|
||||
return nouns;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1078,6 +1078,86 @@ ConstructorTestClass(int i, bool b)
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Get-Command -Noun parameter completion' {
|
||||
BeforeAll {
|
||||
function GetModuleCommandNouns(
|
||||
[string]$Module,
|
||||
[string]$Verb,
|
||||
[switch]$SingleQuote,
|
||||
[switch]$DoubleQuote)
|
||||
{
|
||||
|
||||
$commandParams = @{}
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('Module')) {
|
||||
$commandParams['Module'] = $Module
|
||||
}
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('Verb')) {
|
||||
$commandParams['Verb'] = $Verb
|
||||
}
|
||||
|
||||
$nouns = (Get-Command @commandParams).Noun
|
||||
|
||||
if ($SingleQuote) {
|
||||
return ($nouns | ForEach-Object { "'$_'" })
|
||||
}
|
||||
elseif ($DoubleQuote) {
|
||||
return ($nouns | ForEach-Object { """$_""" })
|
||||
}
|
||||
|
||||
return $nouns
|
||||
}
|
||||
|
||||
$utilityModuleName = 'Microsoft.PowerShell.Utility'
|
||||
|
||||
$allUtilityCommandNouns = GetModuleCommandNouns -Module $utilityModuleName
|
||||
$allUtilityCommandNounsSingleQuote = GetModuleCommandNouns -Module $utilityModuleName -SingleQuote
|
||||
$allUtilityCommandNounsDoubleQuote = GetModuleCommandNouns -Module $utilityModuleName -DoubleQuote
|
||||
$utilityCommandNounsStartingWithF = $allUtilityCommandNouns | Where-Object { $_ -like 'F*'}
|
||||
$utilityCommandNounsStartingWithFSingleQuote = $allUtilityCommandNounsSingleQuote | Where-Object { $_ -like "'F*"}
|
||||
$utilityCommandNounsStartingWithFDoubleQuote = $allUtilityCommandNounsDoubleQuote | Where-Object { $_ -like """F*"}
|
||||
|
||||
$allUtilityCommandNounsWithConvertToVerb = GetModuleCommandNouns -Module $utilityModuleName -Verb 'ConvertTo'
|
||||
$allUtilityCommandNounsWithConvertToVerbSingleQuote = GetModuleCommandNouns -Module $utilityModuleName -SingleQuote -Verb 'ConvertTo'
|
||||
$allUtilityCommandNounsWithConvertToVerbDoubleQuote = GetModuleCommandNouns -Module $utilityModuleName -DoubleQuote -Verb 'ConvertTo'
|
||||
$utilityCommandNounsWithConvertToVerb = $allUtilityCommandNounsWithConvertToVerb | Where-Object { $_ -in 'CliXml', 'Csv', 'Html', 'Json', 'Xml' }
|
||||
$utilityCommandNounsWithConvertToVerbSingleQuote = $allUtilityCommandNounsWithConvertToVerbSingleQuote | Where-Object { $_ -in "'CliXml'", "'Csv'", "'Html'", "'Json'", "'Xml'" }
|
||||
$utilityCommandNounsWithConvertToVerbDoubleQuote = $allUtilityCommandNounsWithConvertToVerbDoubleQuote | Where-Object { $_ -in """CliXml""", """Csv""", """Html""", """Json""", """Xml""" }
|
||||
$utilityCommandNounsWithConvertToVerbStartingWithC = $allUtilityCommandNounsWithConvertToVerb | Where-Object { $_ -in 'CliXml', 'Csv' }
|
||||
$utilityCommandNounsWithConvertToVerbStartingWithCSingleQuote = $allUtilityCommandNounsWithConvertToVerbSingleQuote | Where-Object { $_ -in "'CliXml'", "'Csv'" }
|
||||
$utilityCommandNounsWithConvertToVerbStartingWithCDoubleQuote = $allUtilityCommandNounsWithConvertToVerbDoubleQuote | Where-Object { $_ -in """CliXml""", """Csv""" }
|
||||
}
|
||||
|
||||
It "Should complete Noun for '<TextInput>'" -TestCases @(
|
||||
@{ TextInput = "Get-Command -Module $utilityModuleName -Noun "; ExpectedNouns = $allUtilityCommandNouns }
|
||||
@{ TextInput = "Get-Command -Module $utilityModuleName -Noun '"; ExpectedNouns = $allUtilityCommandNounsSingleQuote }
|
||||
@{ TextInput = "Get-Command -Module $utilityModuleName -Noun """; ExpectedNouns = $allUtilityCommandNounsDoubleQuote }
|
||||
@{ TextInput = "Get-Command -Module $utilityModuleName -Noun F"; ExpectedNouns = $utilityCommandNounsStartingWithF }
|
||||
@{ TextInput = "Get-Command -Module $utilityModuleName -Noun 'F"; ExpectedNouns = $utilityCommandNounsStartingWithFSingleQuote }
|
||||
@{ TextInput = "Get-Command -Module $utilityModuleName -Noun ""F"; ExpectedNouns = $utilityCommandNounsStartingWithFDoubleQuote }
|
||||
@{ TextInput = "Get-Command -Module $utilityModuleName -Verb ConvertTo -Noun "; ExpectedNouns = $utilityCommandNounsWithConvertToVerb }
|
||||
@{ TextInput = "Get-Command -Module $utilityModuleName -Verb ConvertTo -Noun '"; ExpectedNouns = $utilityCommandNounsWithConvertToVerbSingleQuote }
|
||||
@{ TextInput = "Get-Command -Module $utilityModuleName -Verb ConvertTo -Noun """; ExpectedNouns = $utilityCommandNounsWithConvertToVerbDoubleQuote }
|
||||
@{ TextInput = "Get-Command -Module $utilityModuleName -Verb ConvertTo -Noun C"; ExpectedNouns = $utilityCommandNounsWithConvertToVerbStartingWithC }
|
||||
@{ TextInput = "Get-Command -Module $utilityModuleName -Verb ConvertTo -Noun 'C"; ExpectedNouns = $utilityCommandNounsWithConvertToVerbStartingWithCSingleQuote }
|
||||
@{ TextInput = "Get-Command -Module $utilityModuleName -Verb ConvertTo -Noun ""C"; ExpectedNouns = $utilityCommandNounsWithConvertToVerbStartingWithCDoubleQuote }
|
||||
) {
|
||||
param($TextInput, $ExpectedNouns)
|
||||
$res = TabExpansion2 -inputScript $TextInput -cursorColumn $TextInput.Length
|
||||
$completionText = $res.CompletionMatches.CompletionText
|
||||
|
||||
# Avoid using Sort-Object -Unique because it generates different order than SortedSet on MacOS/Linux
|
||||
$sortedSetExpectedNouns = [System.Collections.Generic.SortedSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
|
||||
foreach ($noun in $ExpectedNouns)
|
||||
{
|
||||
$sortedSetExpectedNouns.Add($noun) | Out-Null
|
||||
}
|
||||
|
||||
$completionText -join ' ' | Should -BeExactly ($sortedSetExpectedNouns -join ' ')
|
||||
}
|
||||
}
|
||||
|
||||
Context "Format cmdlet's View paramter completion" {
|
||||
BeforeAll {
|
||||
$viewDefinition = @'
|
||||
|
||||
Reference in New Issue
Block a user