Skip to content

Commit

Permalink
Add completion of modules by their shortname (PowerShell#20330)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinGC94 authored Dec 28, 2024
1 parent b74e708 commit 8cdb728
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -423,16 +423,34 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun

internal static List<CompletionResult> CompleteModuleName(CompletionContext context, bool loadedModulesOnly, bool skipEditionCheck = false)
{
var moduleName = context.WordToComplete ?? string.Empty;
var wordToComplete = context.WordToComplete ?? string.Empty;
var result = new List<CompletionResult>();
var quote = HandleDoubleAndSingleQuote(ref moduleName);
var quote = HandleDoubleAndSingleQuote(ref wordToComplete);

if (!moduleName.EndsWith('*'))
// Indicates if we should search for modules where the last part of the name matches the input text
// eg: Host<Tab> finds Microsoft.PowerShell.Host
// If the user has entered a manual wildcard, or a module name that contains a "." we assume they only want results that matches the input exactly.
bool shortNameSearch = wordToComplete.Length > 0 && !WildcardPattern.ContainsWildcardCharacters(wordToComplete) && !wordToComplete.Contains('.');

if (!wordToComplete.EndsWith('*'))
{
wordToComplete += "*";
}

string[] moduleNames;
WildcardPattern shortNamePattern;
if (shortNameSearch)
{
moduleNames = new string[] { wordToComplete, "*." + wordToComplete };
shortNamePattern = new WildcardPattern(wordToComplete, WildcardOptions.IgnoreCase);
}
else
{
moduleName += "*";
moduleNames = new string[] { wordToComplete };
shortNamePattern = null;
}

var powershell = context.Helper.AddCommandWithPreferenceSetting("Get-Module", typeof(GetModuleCommand)).AddParameter("Name", moduleName);
var powershell = context.Helper.AddCommandWithPreferenceSetting("Get-Module", typeof(GetModuleCommand)).AddParameter("Name", moduleNames);
if (!loadedModulesOnly)
{
powershell.AddParameter("ListAvailable", true);
Expand All @@ -444,18 +462,26 @@ internal static List<CompletionResult> CompleteModuleName(CompletionContext cont
}
}

Exception exceptionThrown;
var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
Collection<PSObject> psObjects = context.Helper.ExecuteCurrentPowerShell(out _);

if (psObjects != null)
{
foreach (dynamic moduleInfo in psObjects)
foreach (PSObject item in psObjects)
{
var completionText = moduleInfo.Name.ToString();
var moduleInfo = (PSModuleInfo)item.BaseObject;
var completionText = moduleInfo.Name;
var listItemText = completionText;
var toolTip = "Description: " + moduleInfo.Description.ToString() + "\r\nModuleType: "
if (shortNameSearch
&& completionText.Contains('.')
&& !shortNamePattern.IsMatch(completionText.Substring(completionText.LastIndexOf('.') + 1))
&& !shortNamePattern.IsMatch(completionText))
{
continue;
}

var toolTip = "Description: " + moduleInfo.Description + "\r\nModuleType: "
+ moduleInfo.ModuleType.ToString() + "\r\nPath: "
+ moduleInfo.Path.ToString();
+ moduleInfo.Path;

if (CompletionRequiresQuotes(completionText, false))
{
Expand Down
5 changes: 5 additions & 0 deletions test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ Describe "TabCompletion" -Tags CI {
$res | Should -BeExactly 'Test-AbbreviatedFunctionExpansion'
}

It 'Should complete module by shortname' {
$res = TabExpansion2 -inputScript 'Get-Module -ListAvailable -Name Host'
$res.CompletionMatches[0].CompletionText | Should -BeExactly 'Microsoft.PowerShell.Host'
}

It 'Should complete native exe' -Skip:(!$IsWindows) {
$res = TabExpansion2 -inputScript 'notep' -cursorColumn 'notep'.Length
$res.CompletionMatches[0].CompletionText | Should -BeExactly 'notepad.exe'
Expand Down

0 comments on commit 8cdb728

Please sign in to comment.