Fix about_* topic help issues and a few tab completion regressions (#4014)

This commit is contained in:
Aditya Patwardhan 2017-06-18 18:27:34 -07:00 committed by Dongbo Wang
parent b4973fc920
commit 2ae5d071ce
4 changed files with 52 additions and 45 deletions

View File

@ -76,7 +76,7 @@ namespace System.Management.Automation
}
var helper = new PowerShellExecutionHelper(PowerShell.Create(RunspaceMode.CurrentRunspace));
return CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = helper }, moduleName, commandTypes);
return CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = helper, ExecutionContext = helper.CurrentPowerShell.GetContextFromTLS() }, moduleName, commandTypes);
}
internal static List<CompletionResult> CompleteCommand(CompletionContext context)
@ -1325,7 +1325,7 @@ 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 });
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = context.WordToComplete, Helper = context.Helper, ExecutionContext = context.ExecutionContext });
if (commandResults != null)
result.AddRange(commandResults);
}
@ -2088,7 +2088,7 @@ 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 });
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = context.WordToComplete, Helper = context.Helper, ExecutionContext = context.ExecutionContext });
if (commandResults != null)
result.AddRange(commandResults);
}
@ -2778,7 +2778,7 @@ namespace System.Management.Automation
RemoveLastNullCompletionResult(result);
// Available commands
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = context.Helper }, moduleName);
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, moduleName);
if (commandResults != null)
result.AddRange(commandResults);
@ -2788,7 +2788,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 }, false, ps1Extension));
var moduleFilesResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, false, ps1Extension));
if (moduleFilesResults.Count > 0)
result.AddRange(moduleFilesResults);
}
@ -2800,7 +2800,7 @@ namespace System.Management.Automation
RemoveLastNullCompletionResult(result);
var modules = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var moduleResults = CompleteModuleName(new CompletionContext { WordToComplete = commandName, Helper = context.Helper }, true);
var moduleResults = CompleteModuleName(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, true);
if (moduleResults != null)
{
foreach (CompletionResult moduleResult in moduleResults)
@ -2813,7 +2813,7 @@ namespace System.Management.Automation
}
}
moduleResults = CompleteModuleName(new CompletionContext { WordToComplete = commandName, Helper = context.Helper }, false);
moduleResults = CompleteModuleName(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, false);
if (moduleResults != null)
{
foreach (CompletionResult moduleResult in moduleResults)
@ -2838,20 +2838,20 @@ namespace System.Management.Automation
// Available commands
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 }, null, commandTypes);
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, 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 }, false, ps1Extension));
var fileResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, false, ps1Extension));
if (fileResults.Count > 0)
result.AddRange(fileResults);
if (isHelpRelated)
{
// Available topics
var helpTopicResults = CompleteHelpTopics(new CompletionContext { WordToComplete = commandName, Helper = context.Helper });
var helpTopicResults = CompleteHelpTopics(new CompletionContext { WordToComplete = commandName, Helper = context.Helper, ExecutionContext = context.ExecutionContext });
if (helpTopicResults != null)
result.AddRange(helpTopicResults);
}
@ -3093,7 +3093,7 @@ namespace System.Management.Automation
StringLiterals.PowerShellCmdletizationFileExtension,
StringLiterals.WorkflowFileExtension
};
var moduleFilesResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = assemblyOrModuleName, Helper = context.Helper }, false, moduleExtensions));
var moduleFilesResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = assemblyOrModuleName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, false, moduleExtensions));
if (moduleFilesResults.Count > 0)
result.AddRange(moduleFilesResults);
@ -3104,7 +3104,7 @@ namespace System.Management.Automation
}
}
var moduleResults = CompleteModuleName(new CompletionContext { WordToComplete = assemblyOrModuleName, Helper = context.Helper }, loadedModulesOnly);
var moduleResults = CompleteModuleName(new CompletionContext { WordToComplete = assemblyOrModuleName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, loadedModulesOnly);
if (moduleResults != null && moduleResults.Count > 0)
result.AddRange(moduleResults);
@ -3115,7 +3115,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 }, false, moduleExtensions));
var moduleFilesResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = assemblyOrModuleName, Helper = context.Helper, ExecutionContext = context.ExecutionContext }, false, moduleExtensions));
if (moduleFilesResults.Count > 0)
result.AddRange(moduleFilesResults);
@ -3490,12 +3490,12 @@ namespace System.Management.Automation
// Complete for the parameter Definition
// Available commands
const CommandTypes commandTypes = CommandTypes.Cmdlet | CommandTypes.Function | CommandTypes.ExternalScript | CommandTypes.Workflow | CommandTypes.Configuration;
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = powerShellExecutionHelper }, null, commandTypes);
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = powerShellExecutionHelper, ExecutionContext = context.ExecutionContext }, 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 }));
var fileResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = commandName, Helper = powerShellExecutionHelper, ExecutionContext = context.ExecutionContext }));
if (fileResults.Count > 0)
result.AddRange(fileResults);
}
@ -3597,8 +3597,7 @@ namespace System.Management.Automation
return;
}
var powershell = context.Helper.CurrentPowerShell;
var executionContext = powershell.GetContextFromTLS();
var executionContext = context.ExecutionContext;
var boundArgs = GetBoundArgumentsAsHashtable(context);
var providedPath = boundArgs["Path"] as string ?? executionContext.SessionState.Path.CurrentLocation.Path;
@ -4035,7 +4034,7 @@ namespace System.Management.Automation
}
var helper = new PowerShellExecutionHelper(PowerShell.Create(RunspaceMode.CurrentRunspace));
return CompleteFilename(new CompletionContext { WordToComplete = fileName, Helper = helper });
return CompleteFilename(new CompletionContext { WordToComplete = fileName, Helper = helper, ExecutionContext = helper.CurrentPowerShell.GetContextFromTLS() });
}
internal static IEnumerable<CompletionResult> CompleteFilename(CompletionContext context)
@ -4484,7 +4483,7 @@ namespace System.Management.Automation
}
var helper = new PowerShellExecutionHelper(PowerShell.Create(RunspaceMode.CurrentRunspace));
return CompleteVariable(new CompletionContext { WordToComplete = variableName, Helper = helper });
return CompleteVariable(new CompletionContext { WordToComplete = variableName, Helper = helper, ExecutionContext = helper.CurrentPowerShell.GetContextFromTLS() });
}
private static readonly string[] s_variableScopes = new string[] { "Global:", "Local:", "Script:", "Private:" };
@ -5861,7 +5860,7 @@ namespace System.Management.Automation
: PowerShell.Create(RunspaceMode.CurrentRunspace);
var helper = new PowerShellExecutionHelper(powershell);
return CompleteType(new CompletionContext { WordToComplete = typeName, Helper = helper });
return CompleteType(new CompletionContext { WordToComplete = typeName, Helper = helper, ExecutionContext = helper.CurrentPowerShell.GetContextFromTLS() });
}
internal static List<CompletionResult> CompleteType(CompletionContext context, string prefix = "", string suffix = "")
@ -5952,14 +5951,22 @@ namespace System.Management.Automation
internal static List<CompletionResult> CompleteHelpTopics(CompletionContext context)
{
var results = new List<CompletionResult>();
var dirPath = Utils.GetApplicationBase(Utils.DefaultPowerShellShellID) + "\\" + CultureInfo.CurrentCulture.Name;
var dirPath = Utils.GetApplicationBase(Utils.DefaultPowerShellShellID) + Path.DirectorySeparatorChar + CultureInfo.CurrentCulture.Name;
var wordToComplete = context.WordToComplete + "*";
var topicPattern = WildcardPattern.Get("about_*.help.txt", WildcardOptions.IgnoreCase);
string[] files = null;
List<string> files = new List<string>();
try
{
files = Directory.GetFiles(dirPath, wordToComplete);
var wildcardPattern = WildcardPattern.Get(wordToComplete, WildcardOptions.IgnoreCase);
foreach(var file in Directory.GetFiles(dirPath))
{
if(wildcardPattern.IsMatch(Path.GetFileName(file)))
{
files.Add(file);
}
}
}
catch (Exception)
{

View File

@ -283,7 +283,7 @@ namespace System.Management.Automation
}
// step 3: locate the file in the default PowerShell installation directory.
string defaultPSPath = GetMshDefaultInstallationPath();
string defaultPSPath = Utils.GetApplicationBase(Utils.DefaultPowerShellShellID);
if (defaultPSPath != null &&
!result.Contains(defaultPSPath) &&
Directory.Exists(defaultPSPath))
@ -294,27 +294,6 @@ namespace System.Management.Automation
return result;
}
/// <summary>
/// Helper method which returns the default monad installation path based on ShellID
/// registry key.
/// </summary>
/// <returns>string representing path.</returns>
/// <remarks>
/// If ShellID is not defined or Path property is not defined returns null.
/// </remarks>
private static string GetMshDefaultInstallationPath()
{
string returnValue = CommandDiscovery.GetShellPathFromRegistry(Utils.DefaultPowerShellShellID);
if (returnValue != null)
{
returnValue = Path.GetDirectoryName(returnValue);
}
// returnValue can be null.
return returnValue;
}
#endregion
#region Static API's

View File

@ -103,6 +103,21 @@ Describe "TabCompletion" -Tags CI {
$res.CompletionMatches[0].CompletionText | Should Be 'namespace'
}
It 'Should complete about help topic' {
$aboutHelpPath = Join-Path $PSHOME (Get-Culture).Name
## If help content does not exist, tab completion will not work. So update it first.
if(-not (Test-Path (Join-Path $aboutHelpPath "about_Splatting.help.txt")))
{
Update-Help -Force -ErrorAction SilentlyContinue
}
$res = TabExpansion2 -inputScript 'get-help about_spla' -cursorColumn 'get-help about_spla'.Length
$res.CompletionMatches.Count | Should Be 1
$res.CompletionMatches[0].CompletionText | Should BeExactly 'about_Splatting'
}
Context NativeCommand {
BeforeAll {
$nativeCommand = (Get-Command -CommandType Application -TotalCount 1).Name

View File

@ -200,6 +200,12 @@ Describe "Validate about_help.txt under culture specific folder works" -Tags @('
$help.count | Should Be 1
$help | Should BeExactly "Hello"
}
It "Get-Help for about_Variable should return only one help object" {
$help = Get-Help about_Variables
$help.count | Should Be 1
}
}
Describe "Get-Help should find help info within help files" -Tags @('CI', 'RequireAdminOnWindows') {