CmdPal: Add settings to hide non-apps from results (#45741)

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR adds new options to the All Apps built-in extension:

- Also include non-app shortcuts from the Start menu
  - Enabled by default
- Also include non-app shortcuts from the desktop
  - Disabled by default

The default states reflect that Start menu shortcuts are largely curated
by installers, and the Start menu itself typically does not surface
non-app items. Desktop shortcuts, on the other hand, are more likely to
be created by the user.

<img width="812" height="499" alt="image"
src="https://github.com/user-attachments/assets/de6c4723-0b52-4606-98fa-469364f5648e"
/>
This commit is contained in:
Jiří Polášek
2026-02-27 21:35:49 +01:00
committed by GitHub
parent f2788f2e09
commit 12fac01ee1
6 changed files with 115 additions and 31 deletions

View File

@@ -62,6 +62,10 @@ public class AllAppsSettings : JsonSettingsManager, ISettingsInterface
public bool EnablePathEnvironmentVariableSource => _enablePathEnvironmentVariableSource.Value;
public bool IncludeNonAppsOnDesktop => _includeNonAppsOnDesktop.Value;
public bool IncludeNonAppsInStartMenu => _includeNonAppsInStartMenu.Value;
private readonly ChoiceSetSetting _searchResultLimitSource = new(
Namespaced(nameof(SearchResultLimit)),
Resources.limit_fallback_results_source,
@@ -121,6 +125,18 @@ public class AllAppsSettings : JsonSettingsManager, ISettingsInterface
string.Empty,
false); // this one is very VERY noisy
private readonly ToggleSetting _includeNonAppsOnDesktop = new(
Namespaced(nameof(IncludeNonAppsOnDesktop)),
Resources.include_non_apps_on_desktop,
string.Empty,
false);
private readonly ToggleSetting _includeNonAppsInStartMenu = new(
Namespaced(nameof(IncludeNonAppsInStartMenu)),
Resources.include_non_apps_in_start_menu,
string.Empty,
true);
public double MinScoreThreshold { get; set; } = 0.75;
internal const char SuffixSeparator = ';';
@@ -139,7 +155,9 @@ public class AllAppsSettings : JsonSettingsManager, ISettingsInterface
FilePath = SettingsJsonPath();
Settings.Add(_enableStartMenuSource);
Settings.Add(_includeNonAppsInStartMenu);
Settings.Add(_enableDesktopSource);
Settings.Add(_includeNonAppsOnDesktop);
Settings.Add(_enableRegistrySource);
Settings.Add(_enablePathEnvironmentVariableSource);
Settings.Add(_searchResultLimitSource);

View File

@@ -19,4 +19,8 @@ public interface ISettingsInterface
public List<string> ProgramSuffixes { get; }
public List<string> RunCommandSuffixes { get; }
public bool IncludeNonAppsOnDesktop { get; }
public bool IncludeNonAppsInStartMenu { get; }
}

View File

@@ -409,9 +409,37 @@ public class Win32Program : IProgram
program.Description = info.FileDescription;
}
}
if (program.AppType is ApplicationType.GenericFile or ApplicationType.Folder)
{
var includeNonAppsOnDesktop = AllAppsSettings.Instance.IncludeNonAppsOnDesktop;
var includeNonAppsInStartMenu = AllAppsSettings.Instance.IncludeNonAppsInStartMenu;
var lnk = program.LnkFilePath;
if (!string.IsNullOrEmpty(lnk))
{
var isDesktop = StartsWithFolder(lnk, Environment.SpecialFolder.Desktop) ||
StartsWithFolder(lnk, Environment.SpecialFolder.CommonDesktopDirectory);
var isStartMenu = StartsWithFolder(lnk, Environment.SpecialFolder.StartMenu) ||
StartsWithFolder(lnk, Environment.SpecialFolder.CommonStartMenu);
if ((isDesktop && !includeNonAppsOnDesktop) || (isStartMenu && !includeNonAppsInStartMenu))
{
program.Enabled = false;
}
}
}
}
return program;
static bool StartsWithFolder(string path, Environment.SpecialFolder folder)
{
var folderPath = Environment.GetFolderPath(folder, Environment.SpecialFolderOption.DoNotVerify);
return !string.IsNullOrEmpty(folderPath)
&& path.StartsWith(folderPath, StringComparison.OrdinalIgnoreCase);
}
}
catch (System.IO.FileLoadException e)
{

View File

@@ -106,7 +106,7 @@ namespace Microsoft.CmdPal.Ext.Apps.Properties {
}
/// <summary>
/// Looks up a localized string similar to Include apps registered in the Registry.
/// Looks up a localized string similar to Include apps registered in the Windows Registry.
/// </summary>
internal static string enable_registry_source {
get {
@@ -115,7 +115,7 @@ namespace Microsoft.CmdPal.Ext.Apps.Properties {
}
/// <summary>
/// Looks up a localized string similar to Include apps found in the Start Menu.
/// Looks up a localized string similar to Include apps found in the Start menu.
/// </summary>
internal static string enable_start_menu_source {
get {
@@ -141,6 +141,24 @@ namespace Microsoft.CmdPal.Ext.Apps.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Also include non-app shortcuts from the Start menu.
/// </summary>
internal static string include_non_apps_in_start_menu {
get {
return ResourceManager.GetString("include_non_apps_in_start_menu", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Also include non-app shortcuts from the desktop.
/// </summary>
internal static string include_non_apps_on_desktop {
get {
return ResourceManager.GetString("include_non_apps_on_desktop", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Installed apps.
/// </summary>

View File

@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
@@ -170,13 +170,13 @@
<value>Run as different user</value>
</data>
<data name="enable_start_menu_source" xml:space="preserve">
<value>Include apps found in the Start Menu</value>
<value>Include apps found in the Start menu</value>
</data>
<data name="enable_desktop_source" xml:space="preserve">
<value>Include apps found on the desktop</value>
</data>
<data name="enable_registry_source" xml:space="preserve">
<value>Include apps registered in the Registry</value>
<value>Include apps registered in the Windows Registry</value>
</data>
<data name="enable_path_environment_variable_source" xml:space="preserve">
<value>Include apps anywhere on the %PATH%</value>
@@ -238,4 +238,10 @@
<value>Default ({0})</value>
<comment>default option; {0} = number of items</comment>
</data>
<data name="include_non_apps_on_desktop" xml:space="preserve">
<value>Also include non-app shortcuts from the desktop</value>
</data>
<data name="include_non_apps_in_start_menu" xml:space="preserve">
<value>Also include non-app shortcuts from the Start menu</value>
</data>
</root>