diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/de.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/de.xaml
index 58bcf7beaf..f5e936d41f 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/de.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/de.xaml
@@ -38,5 +38,6 @@
Win32-Anwendung
Weblink-Anwendung
Web-Anwendung
+ Run command
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/en.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/en.xaml
index 2caa14067c..0beec6253c 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/en.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/en.xaml
@@ -49,4 +49,5 @@
Win32 application
Internet shortcut application
Web application
+ Run command
\ No newline at end of file
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/ja.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/ja.xaml
index 364dc4e9b2..50941e1b92 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/ja.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/ja.xaml
@@ -39,5 +39,6 @@
Win32 application
Internet shortcut application
Web application
+ Run command
\ No newline at end of file
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/pl.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/pl.xaml
index b739a1d551..37e0ef298d 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/pl.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/pl.xaml
@@ -38,5 +38,6 @@
Win32 application
Internet shortcut application
Web application
+ Run command
\ No newline at end of file
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/tr.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/tr.xaml
index e659da4876..a6ddbd3c08 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/tr.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/tr.xaml
@@ -40,5 +40,6 @@
Win32 application
Internet shortcut application
Web application
+ Run command
\ No newline at end of file
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-cn.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-cn.xaml
index 83acbe6148..dd99ae570e 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-cn.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-cn.xaml
@@ -40,5 +40,6 @@
Win32 application
Internet shortcut application
Web application
+ Run command
\ No newline at end of file
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-tw.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-tw.xaml
index c424b7347a..60b136f2e7 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-tw.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-tw.xaml
@@ -38,4 +38,6 @@
Win32 application
Internet shortcut application
Web application
+ Run command
+
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/Win32.cs b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/Win32.cs
index bfbc1438cd..d7c0c12e99 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/Win32.cs
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/Win32.cs
@@ -48,7 +48,8 @@ namespace Microsoft.Plugin.Program.Programs
{
WEB_APPLICATION = 0,
INTERNET_SHORTCUT_APPLICATION = 1,
- WIN32_APPLICATION = 2
+ WIN32_APPLICATION = 2,
+ RUN_COMMAND = 3
}
private int Score(string query)
@@ -116,12 +117,27 @@ namespace Microsoft.Plugin.Program.Programs
{
return api.GetTranslation("powertoys_run_plugin_program_web_application");
}
+ else if(AppType == (uint)ApplicationTypes.RUN_COMMAND)
+ {
+ return api.GetTranslation("powertoys_run_plugin_program_run_command");
+ }
else
{
return String.Empty;
}
}
+ public bool QueryEqualsNameForRunCommands(string query)
+ {
+ if (AppType == (uint)ApplicationTypes.RUN_COMMAND
+ && !query.Equals(Name, StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
public Result Result(string query, IPublicAPI api)
{
var score = Score(query);
@@ -144,6 +160,12 @@ namespace Microsoft.Plugin.Program.Programs
}
}
+ // NOTE: This is to display run commands only when there is an exact match, like in start menu
+ if(!QueryEqualsNameForRunCommands(query))
+ {
+ return null;
+ }
+
var result = new Result
{
SubTitle = SetSubtitle(AppType, api),
@@ -431,7 +453,7 @@ namespace Microsoft.Plugin.Program.Programs
}
}
- private static IEnumerable ProgramPaths(string directory, string[] suffixes)
+ private static IEnumerable ProgramPaths(string directory, string[] suffixes, bool recursiveSearch = true)
{
if (!Directory.Exists(directory))
{
@@ -468,6 +490,12 @@ namespace Microsoft.Plugin.Program.Programs
try
{
+ // If the search is set to be non-recursive, then do not enqueue the child directories.
+ if(!recursiveSearch)
+ {
+ continue;
+ }
+
foreach (var childDirectory in Directory.EnumerateDirectories(currentDirectory, "*", SearchOption.TopDirectoryOnly))
{
folderQueue.Enqueue(childDirectory);
@@ -518,6 +546,45 @@ namespace Microsoft.Plugin.Program.Programs
return programs1.Concat(programs2).Concat(programs3);
}
+
+ // Function to obtain the list of applications, the locations of which have been added to the env variable PATH
+ private static ParallelQuery PathEnvironmentPrograms(string[] suffixes)
+ {
+
+ // To get all the locations stored in the PATH env variable
+ var pathEnvVariable = Environment.GetEnvironmentVariable("PATH");
+ string[] searchPaths = pathEnvVariable.Split(Path.PathSeparator);
+ IEnumerable toFilterAllPaths = new List();
+ bool isRecursiveSearch = true;
+
+ foreach(string path in searchPaths)
+ {
+ if(path.Length > 0)
+ {
+ // to expand any environment variables present in the path
+ string directory = Environment.ExpandEnvironmentVariables(path);
+ var paths = ProgramPaths(directory, suffixes, !isRecursiveSearch);
+ toFilterAllPaths = toFilterAllPaths.Concat(paths);
+ }
+ }
+
+ var allPaths = toFilterAllPaths
+ .Distinct()
+ .ToArray();
+
+ var programs1 = allPaths.AsParallel().Where(p => Extension(p).Equals(ShortcutExtension, StringComparison.OrdinalIgnoreCase)).Select(LnkProgram);
+ var programs2 = allPaths.AsParallel().Where(p => Extension(p).Equals(ApplicationReferenceExtension, StringComparison.OrdinalIgnoreCase)).Select(Win32Program);
+ var programs3 = allPaths.AsParallel().Where(p => Extension(p).Equals(InternetShortcutExtension, StringComparison.OrdinalIgnoreCase)).Select(InternetShortcutProgram);
+ var programs4 = allPaths.AsParallel().Where(p => Extension(p).Equals(ExeExtension, StringComparison.OrdinalIgnoreCase)).Select(ExeProgram);
+
+ var allPrograms = programs1.Concat(programs2).Where(p => p.Valid)
+ .Concat(programs3).Where(p => p.Valid)
+ .Concat(programs4).Where(p => p.Valid)
+ .Select( p => { p.AppType = (uint)ApplicationTypes.RUN_COMMAND; return p; });
+
+ return allPrograms;
+ }
+
private static ParallelQuery IndexPath(string[] suffixes, List IndexLocation)
{
var disabledProgramsList = Main._settings.DisabledProgramSources;
@@ -650,8 +717,8 @@ namespace Microsoft.Plugin.Program.Programs
&& !string.IsNullOrEmpty(app1.ExecutableName) && !string.IsNullOrEmpty(app2.ExecutableName)
&& !string.IsNullOrEmpty(app1.FullPath) && !string.IsNullOrEmpty(app2.FullPath))
{
- return app1.Name.Equals(app2.Name, StringComparison.OrdinalIgnoreCase)
- && app1.ExecutableName.Equals(app2.ExecutableName, StringComparison.OrdinalIgnoreCase)
+ return app1.Name.Equals(app2.Name, StringComparison.OrdinalIgnoreCase)
+ && app1.ExecutableName.Equals(app2.ExecutableName, StringComparison.OrdinalIgnoreCase)
&& app1.FullPath.Equals(app2.FullPath, StringComparison.OrdinalIgnoreCase);
}
return false;
@@ -676,7 +743,7 @@ namespace Microsoft.Plugin.Program.Programs
// Deduplication code
public static Func, Win32[]> DeduplicatePrograms = (programs) =>
{
- var uniqueExePrograms = programs.Where(x => !string.IsNullOrEmpty(x.LnkResolvedPath) || Extension(x.FullPath) != ExeExtension);
+ var uniqueExePrograms = programs.Where(x => !(string.IsNullOrEmpty(x.LnkResolvedPath) && (Extension(x.FullPath) == ExeExtension) && !(x.AppType == (uint)ApplicationTypes.RUN_COMMAND)));
var uniquePrograms = uniqueExePrograms.Distinct(new removeDuplicatesComparer());
return uniquePrograms.ToArray();
};
@@ -702,6 +769,12 @@ namespace Microsoft.Plugin.Program.Programs
programs = programs.Concat(startMenu);
}
+ if (settings.EnablePathEnvironmentVariableSource)
+ {
+ var appPathEnvironment = PathEnvironmentPrograms(settings.ProgramSuffixes);
+ programs = programs.Concat(appPathEnvironment);
+ }
+
if (settings.EnableDesktopSource)
{
var desktop = DesktopPrograms(settings.ProgramSuffixes);
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Settings.cs b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Settings.cs
index 79b9a9d32a..cbb3156d4e 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Settings.cs
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Settings.cs
@@ -17,6 +17,8 @@ namespace Microsoft.Plugin.Program
public bool EnableRegistrySource { get; set; } = true;
+ public bool EnablePathEnvironmentVariableSource { get; set; } = true;
+
internal const char SuffixSeparator = ';';
///
diff --git a/src/modules/launcher/Wox.Test/Plugins/ProgramPluginTest.cs b/src/modules/launcher/Wox.Test/Plugins/ProgramPluginTest.cs
index 9cdec9566e..983325a957 100644
--- a/src/modules/launcher/Wox.Test/Plugins/ProgramPluginTest.cs
+++ b/src/modules/launcher/Wox.Test/Plugins/ProgramPluginTest.cs
@@ -126,6 +126,24 @@ namespace Wox.Test.Plugins
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\test proxy.lnk"
};
+ Win32 cmd_run_command = new Win32
+ {
+ Name = "cmd",
+ ExecutableName = "cmd.exe",
+ FullPath = "c:\\windows\\system32\\cmd.exe",
+ LnkResolvedPath = null,
+ AppType = 3 // Run command
+ };
+
+ Win32 cmder_run_command = new Win32
+ {
+ Name = "Cmder",
+ ExecutableName = "Cmder.exe",
+ FullPath = "c:\\tools\\cmder\\cmder.exe",
+ LnkResolvedPath = null,
+ AppType = 3 // Run command
+ };
+
Win32 dummy_internetShortcut_app = new Win32
{
Name = "Shop Titans",
@@ -293,5 +311,27 @@ namespace Wox.Test.Plugins
// unreachable code
return true;
}
+
+ [TestCase("Command Prompt")]
+ [TestCase("cmd")]
+ [TestCase("cmd.exe")]
+ [TestCase("ignoreQueryText")]
+ public void Win32Applications_ShouldNotBeFiltered_WhenFilteringRunCommands(string query)
+ {
+ // Even if there is an exact match in the name or exe name, win32 applications should never be filtered
+ Assert.IsTrue(command_prompt.QueryEqualsNameForRunCommands(query));
+ }
+
+ [TestCase("cmd")]
+ [TestCase("Cmd")]
+ [TestCase("CMD")]
+ public void RunCommands_ShouldNotBeFiltered_OnExactMatch(string query)
+ {
+ // Partial matches should be filtered as cmd is not equal to cmder
+ Assert.IsFalse(cmder_run_command.QueryEqualsNameForRunCommands(query));
+
+ // the query matches the name (cmd) and is therefore not filtered (case-insensitive)
+ Assert.IsTrue(cmd_run_command.QueryEqualsNameForRunCommands(query));
+ }
}
}