From f013e101b001fe4111cb7f2fba0f8741a42e36c7 Mon Sep 17 00:00:00 2001 From: MartinGC94 Date: Fri, 22 Sep 2023 18:56:01 +0200 Subject: [PATCH 1/3] Add completion of modules by their shortname --- .../CommandCompletion/CompletionCompleters.cs | 51 ++++++++++++++----- .../TabCompletion/TabCompletion.Tests.ps1 | 5 ++ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index e2220750606..49d6074aaef 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -423,16 +423,34 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun internal static List CompleteModuleName(CompletionContext context, bool loadedModulesOnly, bool skipEditionCheck = false) { - var moduleName = context.WordToComplete ?? string.Empty; + var wordToComplete = context.WordToComplete ?? string.Empty; var result = new List(); - 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 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) { - moduleName += "*"; + moduleNames = new string[] { wordToComplete, "*." + wordToComplete }; + shortNamePattern = new WildcardPattern(wordToComplete, WildcardOptions.IgnoreCase); + } + else + { + 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); @@ -444,18 +462,25 @@ internal static List CompleteModuleName(CompletionContext cont } } - Exception exceptionThrown; - var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown); + var psObjects = context.Helper.ExecuteCurrentPowerShell(out _); if (psObjects != null) { - foreach (dynamic moduleInfo in psObjects) + foreach (PSObject item in psObjects) { - var completionText = moduleInfo.Name.ToString(); - var listItemText = completionText; - var toolTip = "Description: " + moduleInfo.Description.ToString() + "\r\nModuleType: " + var moduleInfo = (PSModuleInfo)item.BaseObject; + var completionText = moduleInfo.Name; + 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)) { @@ -469,7 +494,7 @@ internal static List CompleteModuleName(CompletionContext cont completionText = quote + completionText + quote; } - result.Add(new CompletionResult(completionText, listItemText, CompletionResultType.ParameterValue, toolTip)); + result.Add(new CompletionResult(completionText, completionText, CompletionResultType.ParameterValue, toolTip)); } } diff --git a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 index a6d957f3587..6d7f4039829 100644 --- a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 +++ b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 @@ -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' From 7f4d56174284000a6214c4af01966a763445167b Mon Sep 17 00:00:00 2001 From: MartinGC94 Date: Fri, 29 Sep 2023 18:14:38 +0200 Subject: [PATCH 2/3] Revert listItemText change. --- .../engine/CommandCompletion/CompletionCompleters.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 49d6074aaef..edbdf3e416d 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -470,6 +470,7 @@ internal static List CompleteModuleName(CompletionContext cont { var moduleInfo = (PSModuleInfo)item.BaseObject; var completionText = moduleInfo.Name; + var listItemText = completionText; if (shortNameSearch && completionText.Contains('.') && !shortNamePattern.IsMatch(completionText.Substring(completionText.LastIndexOf('.') + 1)) @@ -494,7 +495,7 @@ internal static List CompleteModuleName(CompletionContext cont completionText = quote + completionText + quote; } - result.Add(new CompletionResult(completionText, completionText, CompletionResultType.ParameterValue, toolTip)); + result.Add(new CompletionResult(completionText, listItemText, CompletionResultType.ParameterValue, toolTip)); } } From bf2d856beb53fae8d3dc71cc409a8528c84d7ad2 Mon Sep 17 00:00:00 2001 From: MartinGC94 <42123497+MartinGC94@users.noreply.github.com> Date: Thu, 5 Dec 2024 06:02:22 +0100 Subject: [PATCH 3/3] Update src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs Co-authored-by: Ilya --- .../engine/CommandCompletion/CompletionCompleters.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 15e7cce5df7..3176b7c8659 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -462,7 +462,7 @@ internal static List CompleteModuleName(CompletionContext cont } } - var psObjects = context.Helper.ExecuteCurrentPowerShell(out _); + Collection psObjects = context.Helper.ExecuteCurrentPowerShell(out _); if (psObjects != null) {