Refactor CompletionCompleters.cs to avoid constructing unnecessary CompletionContext instances (#4048)

This commit is contained in:
Dongbo Wang
2017-06-21 11:43:06 -07:00
committed by GitHub
parent 20862d6204
commit da8dd28942
@@ -76,7 +76,8 @@ namespace System.Management.Automation
}
var helper = new PowerShellExecutionHelper(PowerShell.Create(RunspaceMode.CurrentRunspace));
return CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = helper, ExecutionContext = helper.CurrentPowerShell.GetContextFromTLS() }, moduleName, commandTypes);
var executionContext = helper.CurrentPowerShell.Runspace.ExecutionContext;
return CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = helper, ExecutionContext = executionContext }, moduleName, commandTypes);
}
internal static List<CompletionResult> CompleteCommand(CompletionContext context)
@@ -118,7 +119,7 @@ namespace System.Management.Automation
var commandInfos = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
// Complete against pseudo commands that work only in the script workflow.
// It's for argument completion when RelatedAst is null, don't complete pseudo commands for arguments
// If RelatedAst is null then it's for argument completion, because we don't complete pseudo commands for arguments
if (lastAst != null)
{
commandInfos = CompleteWorkflowCommand(commandName, lastAst, commandInfos);
@@ -128,11 +129,11 @@ namespace System.Management.Automation
{
// OrderBy is using stable sorting
var sortedCommandInfos = commandInfos.OrderBy(a => a, new CommandNameComparer());
commandResults = MakeCommandsUnique(sortedCommandInfos, false, addAmpersandIfNecessary, quote, context);
commandResults = MakeCommandsUnique(sortedCommandInfos, /* includeModulePrefix: */ false, addAmpersandIfNecessary, quote);
}
else
{
commandResults = MakeCommandsUnique(commandInfos, false, addAmpersandIfNecessary, quote, context);
commandResults = MakeCommandsUnique(commandInfos, /* includeModulePrefix: */ false, addAmpersandIfNecessary, quote);
}
if (lastAst != null)
@@ -184,11 +185,11 @@ namespace System.Management.Automation
if (commandInfos != null && commandInfos.Count > 1)
{
var sortedCommandInfos = commandInfos.OrderBy(a => a, new CommandNameComparer());
commandResults = MakeCommandsUnique(sortedCommandInfos, true, addAmpersandIfNecessary, quote, context);
commandResults = MakeCommandsUnique(sortedCommandInfos, /* includeModulePrefix: */ true, addAmpersandIfNecessary, quote);
}
else
{
commandResults = MakeCommandsUnique(commandInfos, true, addAmpersandIfNecessary, quote, context);
commandResults = MakeCommandsUnique(commandInfos, /* includeModulePrefix: */ true, addAmpersandIfNecessary, quote);
}
}
}
@@ -196,6 +197,21 @@ namespace System.Management.Automation
return commandResults;
}
/// <summary>
/// Construct a new instance of CompletionContext with RelatedAst = null.
/// For argument completion, we don't want to complete against pseudo commands that only work in the script workflow.
/// The way to avoid that is to pass in a CompletionContext with RelatedAst = null.
/// </summary>
private static CompletionContext NewContextToCompleteCommandAsArgument(CompletionContext context)
{
return new CompletionContext {
WordToComplete = context.WordToComplete,
Helper = context.Helper,
ExecutionContext = context.ExecutionContext,
Options = context.Options
};
}
private static readonly HashSet<string> s_keywordsToExcludeFromAddingAmpersand
= new HashSet<string>(StringComparer.OrdinalIgnoreCase) { TokenKind.InlineScript.ToString(), TokenKind.Configuration.ToString() };
internal static CompletionResult GetCommandNameCompletionResult(string name, object command, bool addAmpersandIfNecessary, string quote)
@@ -252,7 +268,7 @@ namespace System.Management.Automation
return new CompletionResult(name, listItem, CompletionResultType.Command, syntax);
}
internal static List<CompletionResult> MakeCommandsUnique(IEnumerable<PSObject> commandInfoPsObjs, bool includeModulePrefix, bool addAmpersandIfNecessary, string quote, CompletionContext context)
internal static List<CompletionResult> MakeCommandsUnique(IEnumerable<PSObject> commandInfoPsObjs, bool includeModulePrefix, bool addAmpersandIfNecessary, string quote)
{
List<CompletionResult> results = new List<CompletionResult>();
if (commandInfoPsObjs == null || !commandInfoPsObjs.Any())
@@ -579,7 +595,7 @@ namespace System.Management.Automation
if (result.Count == 0)
{
result = pseudoBinding.CommandName.Equals("Set-Location", StringComparison.OrdinalIgnoreCase)
? new List<CompletionResult>(CompleteFilename(context, true, null))
? new List<CompletionResult>(CompleteFilename(context, containerOnly: true, extension: null))
: new List<CompletionResult>(CompleteFilename(context));
}
@@ -1325,7 +1341,8 @@ namespace System.Management.Automation
{
// For argument completion, we don't want to complete against pseudo commands that only work in the script workflow.
// The way to avoid that is to pass in a CompletionContext with RelatedAst = null
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = context.WordToComplete, Helper = context.Helper, ExecutionContext = context.ExecutionContext });
var newContext = NewContextToCompleteCommandAsArgument(context);
var commandResults = CompleteCommand(newContext);
if (commandResults != null)
result.AddRange(commandResults);
}
@@ -2042,7 +2059,7 @@ namespace System.Management.Automation
{
if (parameterName.Equals("Module", StringComparison.OrdinalIgnoreCase))
{
NativeCompletionGetCommand(context.WordToComplete, null, parameterName, result, context);
NativeCompletionGetCommand(context, /* moduleName: */ null, parameterName, result);
break;
}
if (parameterName.Equals("Name", StringComparison.OrdinalIgnoreCase))
@@ -2053,12 +2070,12 @@ namespace System.Management.Automation
{
foreach (string module in moduleNames)
{
NativeCompletionGetCommand(context.WordToComplete, module, parameterName, result, context);
NativeCompletionGetCommand(context, module, parameterName, result);
}
}
else
{
NativeCompletionGetCommand(context.WordToComplete, null, parameterName, result, context);
NativeCompletionGetCommand(context, /* moduleName: */ null, parameterName, result);
}
break;
}
@@ -2073,13 +2090,13 @@ namespace System.Management.Automation
}
case "Show-Command":
{
NativeCompletionGetHelpCommand(context.WordToComplete, parameterName, false, result, context);
NativeCompletionGetHelpCommand(context, parameterName, /* isHelpRelated: */ false, result);
break;
}
case "help":
case "Get-Help":
{
NativeCompletionGetHelpCommand(context.WordToComplete, parameterName, true, result, context);
NativeCompletionGetHelpCommand(context, parameterName, /* isHelpRelated: */ true, result);
break;
}
case "Invoke-Expression":
@@ -2088,7 +2105,8 @@ namespace System.Management.Automation
{
// For argument completion, we don't want to complete against pseudo commands that only work in the script workflow.
// The way to avoid that is to pass in a CompletionContext with RelatedAst = null
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = context.WordToComplete, Helper = context.Helper, ExecutionContext = context.ExecutionContext });
var newContext = NewContextToCompleteCommandAsArgument(context);
var commandResults = CompleteCommand(newContext);
if (commandResults != null)
result.AddRange(commandResults);
}
@@ -2100,7 +2118,7 @@ namespace System.Management.Automation
case "Remove-EventLog":
case "Write-EventLog":
{
NativeCompletionEventLogCommands(context.WordToComplete, parameterName, result, context);
NativeCompletionEventLogCommands(context, parameterName, result);
break;
}
case "Get-Job":
@@ -2111,7 +2129,7 @@ namespace System.Management.Automation
case "Suspend-Job":
case "Resume-Job":
{
NativeCompletionJobCommands(context.WordToComplete, parameterName, result, context);
NativeCompletionJobCommands(context, parameterName, result);
break;
}
case "Disable-ScheduledJob":
@@ -2119,23 +2137,23 @@ namespace System.Management.Automation
case "Get-ScheduledJob":
case "Unregister-ScheduledJob":
{
NativeCompletionScheduledJobCommands(context.WordToComplete, parameterName, result, context);
NativeCompletionScheduledJobCommands(context, parameterName, result);
break;
}
case "Get-Module":
{
bool loadedModulesOnly = boundArguments == null || !boundArguments.ContainsKey("ListAvailable");
NativeCompletionModuleCommands(context.WordToComplete, parameterName, loadedModulesOnly, false, result, context);
NativeCompletionModuleCommands(context, parameterName, loadedModulesOnly, /* isImportModule: */ false, result);
break;
}
case "Remove-Module":
{
NativeCompletionModuleCommands(context.WordToComplete, parameterName, true, false, result, context);
NativeCompletionModuleCommands(context, parameterName, /* loadedModulesOnly: */ true, /* isImportModule: */ false, result);
break;
}
case "Import-Module":
{
NativeCompletionModuleCommands(context.WordToComplete, parameterName, false, true, result, context);
NativeCompletionModuleCommands(context, parameterName, /* loadedModulesOnly: */ false, /* isImportModule: */ true, result);
break;
}
case "Debug-Process":
@@ -2144,7 +2162,7 @@ namespace System.Management.Automation
case "Wait-Process":
case "Enter-PSHostProcess":
{
NativeCompletionProcessCommands(context.WordToComplete, parameterName, result, context);
NativeCompletionProcessCommands(context, parameterName, result);
break;
}
case "Get-PSDrive":
@@ -2152,7 +2170,7 @@ namespace System.Management.Automation
{
if (parameterName.Equals("PSProvider", StringComparison.OrdinalIgnoreCase))
{
NativeCompletionProviderCommands(context.WordToComplete, parameterName, result, context);
NativeCompletionProviderCommands(context, parameterName, result);
}
else if (parameterName.Equals("Name", StringComparison.OrdinalIgnoreCase))
{
@@ -2161,12 +2179,12 @@ namespace System.Management.Automation
{
foreach (string psProvider in psProviders)
{
NativeCompletionDriveCommands(context.WordToComplete, psProvider, parameterName, result, context);
NativeCompletionDriveCommands(context, psProvider, parameterName, result);
}
}
else
{
NativeCompletionDriveCommands(context.WordToComplete, null, parameterName, result, context);
NativeCompletionDriveCommands(context, /* psProvider: */ null, parameterName, result);
}
}
@@ -2174,12 +2192,12 @@ namespace System.Management.Automation
}
case "New-PSDrive":
{
NativeCompletionProviderCommands(context.WordToComplete, parameterName, result, context);
NativeCompletionProviderCommands(context, parameterName, result);
break;
}
case "Get-PSProvider":
{
NativeCompletionProviderCommands(context.WordToComplete, parameterName, result, context);
NativeCompletionProviderCommands(context, parameterName, result);
break;
}
case "Get-Service":
@@ -2190,7 +2208,7 @@ namespace System.Management.Automation
case "Stop-Service":
case "Suspend-Service":
{
NativeCompletionServiceCommands(context.WordToComplete, parameterName, result, context);
NativeCompletionServiceCommands(context, parameterName, result);
break;
}
case "Clear-Variable":
@@ -2198,43 +2216,43 @@ namespace System.Management.Automation
case "Remove-Variable":
case "Set-Variable":
{
NativeCompletionVariableCommands(context.WordToComplete, parameterName, result, context);
NativeCompletionVariableCommands(context, parameterName, result);
break;
}
case "Get-Alias":
{
NativeCompletionAliasCommands(context.WordToComplete, parameterName, result, context);
NativeCompletionAliasCommands(context, parameterName, result);
break;
}
case "Get-TraceSource":
case "Set-TraceSource":
case "Trace-Command":
{
NativeCompletionTraceSourceCommands(context.WordToComplete, parameterName, result, context);
NativeCompletionTraceSourceCommands(context, parameterName, result);
break;
}
case "Push-Location":
case "Set-Location":
{
NativeCompletionSetLocationCommand(context.WordToComplete, parameterName, result, context);
NativeCompletionSetLocationCommand(context, parameterName, result);
break;
}
case "Move-Item":
case "Copy-Item":
{
NativeCompletionCopyMoveItemCommand(context.WordToComplete, parameterName, result, context);
NativeCompletionCopyMoveItemCommand(context, parameterName, result);
break;
}
case "New-Item":
{
NativeCompletionNewItemCommand(context.WordToComplete, parameterName, result, context);
NativeCompletionNewItemCommand(context, parameterName, result);
break;
}
case "ForEach-Object":
{
if (parameterName.Equals("MemberName", StringComparison.OrdinalIgnoreCase))
{
NativeCompletionMemberName(context.WordToComplete, result, commandAst, context);
NativeCompletionMemberName(context, result, commandAst);
}
break;
}
@@ -2249,7 +2267,7 @@ namespace System.Management.Automation
{
if (parameterName.Equals("Property", StringComparison.OrdinalIgnoreCase))
{
NativeCompletionMemberName(context.WordToComplete, result, commandAst, context);
NativeCompletionMemberName(context, result, commandAst);
}
break;
}
@@ -2259,7 +2277,7 @@ namespace System.Management.Automation
|| parameterName.Equals("ExcludeProperty", StringComparison.OrdinalIgnoreCase)
|| parameterName.Equals("ExpandProperty", StringComparison.OrdinalIgnoreCase))
{
NativeCompletionMemberName(context.WordToComplete, result, commandAst, context);
NativeCompletionMemberName(context, result, commandAst);
}
break;
}
@@ -2286,7 +2304,7 @@ namespace System.Management.Automation
default:
{
NativeCompletionPathArgument(context.WordToComplete, parameterName, result, context);
NativeCompletionPathArgument(context, parameterName, result);
break;
}
}
@@ -2771,14 +2789,17 @@ namespace System.Management.Automation
result.AddRange(namespaceResults.OrderBy(x => x.ListItemText, StringComparer.OrdinalIgnoreCase));
}
private static void NativeCompletionGetCommand(string commandName, string moduleName, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionGetCommand(CompletionContext context, string moduleName, string paramName, List<CompletionResult> result)
{
if (!string.IsNullOrEmpty(paramName) && paramName.Equals("Name", StringComparison.OrdinalIgnoreCase))
{
RemoveLastNullCompletionResult(result);
// Available commands
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, moduleName);
// For argument completion, we don't want to complete against pseudo commands that only work in the script workflow.
// The way to avoid that is to pass in a CompletionContext with RelatedAst = null
var newContext = NewContextToCompleteCommandAsArgument(context);
var commandResults = CompleteCommand(newContext, moduleName);
if (commandResults != null)
result.AddRange(commandResults);
@@ -2788,7 +2809,7 @@ namespace System.Management.Automation
// ps1 files and directories. We only complete the files with .ps1 extension for Get-Command, because the -Syntax
// may only works on files with .ps1 extension
var ps1Extension = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { StringLiterals.PowerShellScriptFileExtension };
var moduleFilesResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, false, ps1Extension));
var moduleFilesResults = new List<CompletionResult>(CompleteFilename(context, /* containerOnly: */ false, ps1Extension));
if (moduleFilesResults.Count > 0)
result.AddRange(moduleFilesResults);
}
@@ -2800,7 +2821,7 @@ namespace System.Management.Automation
RemoveLastNullCompletionResult(result);
var modules = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var moduleResults = CompleteModuleName(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, true);
var moduleResults = CompleteModuleName(context, loadedModulesOnly: true);
if (moduleResults != null)
{
foreach (CompletionResult moduleResult in moduleResults)
@@ -2813,7 +2834,7 @@ namespace System.Management.Automation
}
}
moduleResults = CompleteModuleName(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, false);
moduleResults = CompleteModuleName(context, loadedModulesOnly: false);
if (moduleResults != null)
{
foreach (CompletionResult moduleResult in moduleResults)
@@ -2830,28 +2851,31 @@ namespace System.Management.Automation
}
}
private static void NativeCompletionGetHelpCommand(string commandName, string paramName, bool isHelpRelated, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionGetHelpCommand(CompletionContext context, string paramName, bool isHelpRelated, List<CompletionResult> result)
{
if (!string.IsNullOrEmpty(paramName) && paramName.Equals("Name", StringComparison.OrdinalIgnoreCase))
{
RemoveLastNullCompletionResult(result);
// Available commands
// For argument completion, we don't want to complete against pseudo commands that only work in the script workflow.
// The way to avoid that is to pass in a CompletionContext with RelatedAst = null
const CommandTypes commandTypes = CommandTypes.Cmdlet | CommandTypes.Function | CommandTypes.Alias | CommandTypes.ExternalScript | CommandTypes.Workflow | CommandTypes.Configuration;
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, null, commandTypes);
var newContext = NewContextToCompleteCommandAsArgument(context);
var commandResults = CompleteCommand(newContext, /* moduleName: */ null, commandTypes);
if (commandResults != null)
result.AddRange(commandResults);
// ps1 files and directories
var ps1Extension = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { StringLiterals.PowerShellScriptFileExtension };
var fileResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, false, ps1Extension));
var fileResults = new List<CompletionResult>(CompleteFilename(context, /* containerOnly: */ false, ps1Extension));
if (fileResults.Count > 0)
result.AddRange(fileResults);
if (isHelpRelated)
{
// Available topics
var helpTopicResults = CompleteHelpTopics(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext });
var helpTopicResults = CompleteHelpTopics(context);
if (helpTopicResults != null)
result.AddRange(helpTopicResults);
}
@@ -2860,13 +2884,13 @@ namespace System.Management.Automation
}
}
private static void NativeCompletionEventLogCommands(string logName, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionEventLogCommands(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (!string.IsNullOrEmpty(paramName) && paramName.Equals("LogName", StringComparison.OrdinalIgnoreCase))
{
RemoveLastNullCompletionResult(result);
logName = logName ?? string.Empty;
var logName = context.WordToComplete ?? string.Empty;
var quote = HandleDoubleAndSingleQuote(ref logName);
if (!logName.EndsWith("*", StringComparison.Ordinal))
@@ -2911,12 +2935,12 @@ namespace System.Management.Automation
}
}
private static void NativeCompletionJobCommands(string wordToComplete, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionJobCommands(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName))
return;
wordToComplete = wordToComplete ?? string.Empty;
var wordToComplete = context.WordToComplete ?? string.Empty;
var quote = HandleDoubleAndSingleQuote(ref wordToComplete);
if (!wordToComplete.EndsWith("*", StringComparison.Ordinal))
@@ -2997,12 +3021,12 @@ namespace System.Management.Automation
}
}
private static void NativeCompletionScheduledJobCommands(string wordToComplete, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionScheduledJobCommands(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName))
return;
wordToComplete = wordToComplete ?? string.Empty;
var wordToComplete = context.WordToComplete ?? string.Empty;
var quote = HandleDoubleAndSingleQuote(ref wordToComplete);
if (!wordToComplete.EndsWith("*", StringComparison.Ordinal))
@@ -3071,7 +3095,7 @@ namespace System.Management.Automation
}
}
private static void NativeCompletionModuleCommands(string assemblyOrModuleName, string paramName, bool loadedModulesOnly, bool isImportModule, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionModuleCommands(CompletionContext context, string paramName, bool loadedModulesOnly, bool isImportModule, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName))
{
@@ -3093,10 +3117,11 @@ namespace System.Management.Automation
StringLiterals.PowerShellCmdletizationFileExtension,
StringLiterals.WorkflowFileExtension
};
var moduleFilesResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = assemblyOrModuleName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, false, moduleExtensions));
var moduleFilesResults = new List<CompletionResult>(CompleteFilename(context, /* containerOnly: */ false, moduleExtensions));
if (moduleFilesResults.Count > 0)
result.AddRange(moduleFilesResults);
var assemblyOrModuleName = context.WordToComplete;
if (assemblyOrModuleName.IndexOfAny(Utils.Separators.DirectoryOrDrive) != -1)
{
// The partial input is a path, then we don't iterate modules under $ENV:PSModulePath
@@ -3104,7 +3129,7 @@ namespace System.Management.Automation
}
}
var moduleResults = CompleteModuleName(new CompletionContext { WordToComplete = assemblyOrModuleName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, loadedModulesOnly);
var moduleResults = CompleteModuleName(context, loadedModulesOnly);
if (moduleResults != null && moduleResults.Count > 0)
result.AddRange(moduleResults);
@@ -3115,7 +3140,7 @@ namespace System.Management.Automation
RemoveLastNullCompletionResult(result);
var moduleExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".dll" };
var moduleFilesResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = assemblyOrModuleName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, false, moduleExtensions));
var moduleFilesResults = new List<CompletionResult>(CompleteFilename(context, /* containerOnly: */ false, moduleExtensions));
if (moduleFilesResults.Count > 0)
result.AddRange(moduleFilesResults);
@@ -3123,12 +3148,12 @@ namespace System.Management.Automation
}
}
private static void NativeCompletionProcessCommands(string wordToComplete, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionProcessCommands(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName))
return;
wordToComplete = wordToComplete ?? string.Empty;
var wordToComplete = context.WordToComplete ?? string.Empty;
var quote = HandleDoubleAndSingleQuote(ref wordToComplete);
if (!wordToComplete.EndsWith("*", StringComparison.Ordinal))
@@ -3204,7 +3229,7 @@ namespace System.Management.Automation
}
}
private static void NativeCompletionProviderCommands(string providerName, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionProviderCommands(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName) || !paramName.Equals("PSProvider", StringComparison.OrdinalIgnoreCase))
{
@@ -3213,7 +3238,7 @@ namespace System.Management.Automation
RemoveLastNullCompletionResult(result);
providerName = providerName ?? string.Empty;
var providerName = context.WordToComplete ?? string.Empty;
var quote = HandleDoubleAndSingleQuote(ref providerName);
@@ -3251,14 +3276,14 @@ namespace System.Management.Automation
result.Add(CompletionResult.Null);
}
private static void NativeCompletionDriveCommands(string wordToComplete, string psProvider, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionDriveCommands(CompletionContext context, string psProvider, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName) || !paramName.Equals("Name", StringComparison.OrdinalIgnoreCase))
return;
RemoveLastNullCompletionResult(result);
wordToComplete = wordToComplete ?? string.Empty;
var wordToComplete = context.WordToComplete ?? string.Empty;
var quote = HandleDoubleAndSingleQuote(ref wordToComplete);
if (!wordToComplete.EndsWith("*", StringComparison.Ordinal))
@@ -3300,12 +3325,12 @@ namespace System.Management.Automation
result.Add(CompletionResult.Null);
}
private static void NativeCompletionServiceCommands(string wordToComplete, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionServiceCommands(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName))
return;
wordToComplete = wordToComplete ?? string.Empty;
var wordToComplete = context.WordToComplete ?? string.Empty;
var quote = HandleDoubleAndSingleQuote(ref wordToComplete);
if (!wordToComplete.EndsWith("*", StringComparison.Ordinal))
@@ -3383,7 +3408,7 @@ namespace System.Management.Automation
}
}
private static void NativeCompletionVariableCommands(string variableName, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionVariableCommands(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName) || !paramName.Equals("Name", StringComparison.OrdinalIgnoreCase))
{
@@ -3392,7 +3417,7 @@ namespace System.Management.Automation
RemoveLastNullCompletionResult(result);
variableName = variableName ?? string.Empty;
var variableName = context.WordToComplete ?? string.Empty;
var quote = HandleDoubleAndSingleQuote(ref variableName);
if (!variableName.EndsWith("*", StringComparison.Ordinal))
{
@@ -3437,7 +3462,7 @@ namespace System.Management.Automation
result.Add(CompletionResult.Null);
}
private static void NativeCompletionAliasCommands(string commandName, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionAliasCommands(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName) ||
(!paramName.Equals("Definition", StringComparison.OrdinalIgnoreCase) &&
@@ -3451,7 +3476,7 @@ namespace System.Management.Automation
var powerShellExecutionHelper = context.Helper;
if (paramName.Equals("Name", StringComparison.OrdinalIgnoreCase))
{
commandName = commandName ?? string.Empty;
var commandName = context.WordToComplete ?? string.Empty;
var quote = HandleDoubleAndSingleQuote(ref commandName);
if (!commandName.EndsWith("*", StringComparison.Ordinal))
@@ -3489,13 +3514,16 @@ namespace System.Management.Automation
{
// Complete for the parameter Definition
// Available commands
// For argument completion, we don't want to complete against pseudo commands that only work in the script workflow.
// The way to avoid that is to pass in a CompletionContext with RelatedAst = null
const CommandTypes commandTypes = CommandTypes.Cmdlet | CommandTypes.Function | CommandTypes.ExternalScript | CommandTypes.Workflow | CommandTypes.Configuration;
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = powerShellExecutionHelper, ExecutionContext = context.ExecutionContext }, null, commandTypes);
var newContext = NewContextToCompleteCommandAsArgument(context);
var commandResults = CompleteCommand(newContext, /* moduleName: */ null, commandTypes);
if (commandResults != null && commandResults.Count > 0)
result.AddRange(commandResults);
// The parameter Definition takes a file
var fileResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = commandName, Helper = powerShellExecutionHelper, ExecutionContext = context.ExecutionContext }));
var fileResults = new List<CompletionResult>(CompleteFilename(context));
if (fileResults.Count > 0)
result.AddRange(fileResults);
}
@@ -3503,7 +3531,7 @@ namespace System.Management.Automation
result.Add(CompletionResult.Null);
}
private static void NativeCompletionTraceSourceCommands(string traceSourceName, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionTraceSourceCommands(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName) || !paramName.Equals("Name", StringComparison.OrdinalIgnoreCase))
{
@@ -3512,7 +3540,7 @@ namespace System.Management.Automation
RemoveLastNullCompletionResult(result);
traceSourceName = traceSourceName ?? string.Empty;
var traceSourceName = context.WordToComplete ?? string.Empty;
var quote = HandleDoubleAndSingleQuote(ref traceSourceName);
if (!traceSourceName.EndsWith("*", StringComparison.Ordinal))
@@ -3550,7 +3578,7 @@ namespace System.Management.Automation
result.Add(CompletionResult.Null);
}
private static void NativeCompletionSetLocationCommand(string dirName, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionSetLocationCommand(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName) ||
(!paramName.Equals("Path", StringComparison.OrdinalIgnoreCase) &&
@@ -3561,7 +3589,7 @@ namespace System.Management.Automation
RemoveLastNullCompletionResult(result);
context.WordToComplete = dirName ?? string.Empty;
context.WordToComplete = context.WordToComplete ?? string.Empty;
var clearLiteralPath = false;
if (paramName.Equals("LiteralPath", StringComparison.OrdinalIgnoreCase))
{
@@ -3570,7 +3598,7 @@ namespace System.Management.Automation
try
{
var fileNameResults = CompleteFilename(context, true, null);
var fileNameResults = CompleteFilename(context, containerOnly: true, extension: null);
if (fileNameResults != null)
result.AddRange(fileNameResults);
}
@@ -3586,11 +3614,10 @@ namespace System.Management.Automation
/// <summary>
/// Provides completion results for NewItemCommand
/// </summary>
/// <param name="itemTypeToComplete">The item provided by user for completion.</param>
/// <param name="context">Completion context.</param>
/// <param name="paramName">Name of the parameter whose value needs completion.</param>
/// <param name="result">List of completion suggestions.</param>
/// <param name="context">Completion context.</param>
private static void NativeCompletionNewItemCommand(string itemTypeToComplete, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionNewItemCommand(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName))
{
@@ -3613,9 +3640,9 @@ namespace System.Management.Automation
{
if (paramName.Equals("ItemType", StringComparison.OrdinalIgnoreCase))
{
if (!String.IsNullOrEmpty(itemTypeToComplete))
if (!String.IsNullOrEmpty(context.WordToComplete))
{
WildcardPattern patternEvaluator = WildcardPattern.Get(itemTypeToComplete + "*", WildcardOptions.IgnoreCase);
WildcardPattern patternEvaluator = WildcardPattern.Get(context.WordToComplete + "*", WildcardOptions.IgnoreCase);
if (patternEvaluator.IsMatch("file"))
{
@@ -3652,7 +3679,7 @@ namespace System.Management.Automation
}
}
private static void NativeCompletionCopyMoveItemCommand(string pathName, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionCopyMoveItemCommand(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName))
{
@@ -3661,14 +3688,14 @@ namespace System.Management.Automation
if (paramName.Equals("LiteralPath", StringComparison.OrdinalIgnoreCase) || paramName.Equals("Path", StringComparison.OrdinalIgnoreCase))
{
NativeCompletionPathArgument(pathName, paramName, result, context);
NativeCompletionPathArgument(context, paramName, result);
}
else if (paramName.Equals("Destination", StringComparison.OrdinalIgnoreCase))
{
// The parameter Destination for Move-Item and Copy-Item takes literal path
RemoveLastNullCompletionResult(result);
context.WordToComplete = pathName ?? string.Empty;
context.WordToComplete = context.WordToComplete ?? string.Empty;
var clearLiteralPath = TurnOnLiteralPathOption(context);
try
@@ -3687,7 +3714,7 @@ namespace System.Management.Automation
}
}
private static void NativeCompletionPathArgument(string pathName, string paramName, List<CompletionResult> result, CompletionContext context)
private static void NativeCompletionPathArgument(CompletionContext context, string paramName, List<CompletionResult> result)
{
if (string.IsNullOrEmpty(paramName) ||
(!paramName.Equals("LiteralPath", StringComparison.OrdinalIgnoreCase) &&
@@ -3699,7 +3726,7 @@ namespace System.Management.Automation
RemoveLastNullCompletionResult(result);
context.WordToComplete = pathName ?? string.Empty;
context.WordToComplete = context.WordToComplete ?? string.Empty;
var clearLiteralPath = false;
if (paramName.Equals("LiteralPath", StringComparison.OrdinalIgnoreCase))
{
@@ -3721,7 +3748,7 @@ namespace System.Management.Automation
result.Add(CompletionResult.Null);
}
private static void NativeCompletionMemberName(string wordToComplete, List<CompletionResult> result, CommandAst commandAst, CompletionContext context)
private static void NativeCompletionMemberName(CompletionContext context, List<CompletionResult> result, CommandAst commandAst)
{
// Command is something like where-object/foreach-object/format-list/etc. where there is a parameter that is a property name
// and we want member names based on the input object, which is either the parameter InputObject, or comes from the pipeline.
@@ -3757,7 +3784,7 @@ namespace System.Management.Automation
prevType = AstTypeInference.InferTypeOf(pipelineAst.PipelineElements[i - 1], context.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval);
}
CompleteMemberByInferredType(context, prevType, result, wordToComplete + "*", filter: IsPropertyMember, isStatic: false);
CompleteMemberByInferredType(context, prevType, result, context.WordToComplete + "*", filter: IsPropertyMember, isStatic: false);
result.Add(CompletionResult.Null);
}
@@ -4034,12 +4061,13 @@ namespace System.Management.Automation
}
var helper = new PowerShellExecutionHelper(PowerShell.Create(RunspaceMode.CurrentRunspace));
return CompleteFilename(new CompletionContext { WordToComplete = fileName, Helper = helper, ExecutionContext = helper.CurrentPowerShell.GetContextFromTLS() });
var executionContext = helper.CurrentPowerShell.Runspace.ExecutionContext;
return CompleteFilename(new CompletionContext { WordToComplete = fileName, Helper = helper, ExecutionContext = executionContext });
}
internal static IEnumerable<CompletionResult> CompleteFilename(CompletionContext context)
{
return CompleteFilename(context, false, null);
return CompleteFilename(context, containerOnly: false, extension: null);
}
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")]
@@ -4483,7 +4511,8 @@ namespace System.Management.Automation
}
var helper = new PowerShellExecutionHelper(PowerShell.Create(RunspaceMode.CurrentRunspace));
return CompleteVariable(new CompletionContext { WordToComplete = variableName, Helper = helper, ExecutionContext = helper.CurrentPowerShell.GetContextFromTLS() });
var executionContext = helper.CurrentPowerShell.Runspace.ExecutionContext;
return CompleteVariable(new CompletionContext { WordToComplete = variableName, Helper = helper, ExecutionContext = executionContext });
}
private static readonly string[] s_variableScopes = new string[] { "Global:", "Local:", "Script:", "Private:" };
@@ -5860,7 +5889,8 @@ namespace System.Management.Automation
: PowerShell.Create(RunspaceMode.CurrentRunspace);
var helper = new PowerShellExecutionHelper(powershell);
return CompleteType(new CompletionContext { WordToComplete = typeName, Helper = helper, ExecutionContext = helper.CurrentPowerShell.GetContextFromTLS() });
var executionContext = helper.CurrentPowerShell.Runspace.ExecutionContext;
return CompleteType(new CompletionContext { WordToComplete = typeName, Helper = helper, ExecutionContext = executionContext });
}
internal static List<CompletionResult> CompleteType(CompletionContext context, string prefix = "", string suffix = "")