[CmdPal > Ext] Use empty content for WindowWalker, Windows Settings and Windows Search (#40722)

<!-- 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 improves the behavior of CmdPal on empty or wrong search query
for the following exts:
- Window Walker
- Windows Settings
- Windows Search (indexer)

### Window Walker
<img width="795" height="482" alt="image"
src="https://github.com/user-attachments/assets/352a122d-2b8f-45be-bf49-6a56f6ca0848"
/>

### Windows Settings - Empty query
<img width="796" height="485" alt="image"
src="https://github.com/user-attachments/assets/12f193b3-22c5-45d8-89c0-bba5740da62b"
/>

### Windows Settings - No search match
<img width="855" height="483" alt="image"
src="https://github.com/user-attachments/assets/e521f63d-65ae-4b93-992d-2bb0a11edaa7"
/>

### Windows search (indexer)
<img width="796" height="483" alt="image"
src="https://github.com/user-attachments/assets/c2e6a218-de2b-4657-a9e7-9def26c9258e"
/>



<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] **Closes:** #40614 , #38293 , #40565
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Mike Griese <migrie@microsoft.com>
This commit is contained in:
Heiko 2025-08-18 18:22:26 +02:00 committed by GitHub
parent 6acb793184
commit 65b752b3ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 141 additions and 26 deletions

View File

@ -21,6 +21,8 @@ internal sealed partial class IndexerPage : DynamicListPage, IDisposable
private string initialQuery = string.Empty;
private bool _isEmptyQuery = true;
public IndexerPage()
{
Id = "com.microsoft.indexer.fileSearch";
@ -43,15 +45,19 @@ internal sealed partial class IndexerPage : DynamicListPage, IDisposable
disposeSearchEngine = false;
}
public override ICommandItem EmptyContent => GetEmptyContent();
public override void UpdateSearchText(string oldSearch, string newSearch)
{
if (oldSearch != newSearch && newSearch != initialQuery)
{
_ = Task.Run(() =>
{
_isEmptyQuery = string.IsNullOrWhiteSpace(newSearch);
Query(newSearch);
LoadMore();
initialQuery = string.Empty;
OnPropertyChanged(nameof(EmptyContent));
initialQuery = null;
});
}
}
@ -68,6 +74,16 @@ internal sealed partial class IndexerPage : DynamicListPage, IDisposable
RaiseItemsChanged(_indexerListItems.Count);
}
private CommandItem GetEmptyContent()
{
return new CommandItem(new NoOpCommand())
{
Icon = Icon,
Title = _isEmptyQuery ? Resources.Indexer_Subtitle : Resources.Indexer_NoResultsMessage,
Subtitle = Resources.Indexer_NoResultsMessageTip,
};
}
private void Query(string query)
{
++_queryCookie;

View File

@ -61,7 +61,7 @@ namespace Microsoft.CmdPal.Ext.Indexer.Properties {
}
/// <summary>
/// Looks up a localized string similar to Actions.
/// Looks up a localized string similar to Actions....
/// </summary>
internal static string Indexer_Command_Actions {
get {
@ -177,6 +177,24 @@ namespace Microsoft.CmdPal.Ext.Indexer.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to No items found.
/// </summary>
internal static string Indexer_NoResultsMessage {
get {
return ResourceManager.GetString("Indexer_NoResultsMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Tip: Improve your search result using filters like in Windows Explorer. (For example: type:directory).
/// </summary>
internal static string Indexer_NoResultsMessageTip {
get {
return ResourceManager.GetString("Indexer_NoResultsMessageTip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Search for files and folders....
/// </summary>

View File

@ -180,4 +180,10 @@
<data name="Indexer_fallback_searchPage_title" xml:space="preserve">
<value>Search for "{0}" in files</value>
</data>
<data name="Indexer_NoResultsMessage" xml:space="preserve">
<value>No items found</value>
</data>
<data name="Indexer_NoResultsMessageTip" xml:space="preserve">
<value>Tip: Refine your search using filters, just like in File Explorer (e.g., type:directory).</value>
</data>
</root>

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.CmdPal.Ext.WindowWalker.Components;
using Microsoft.CmdPal.Ext.WindowWalker.Properties;
using Microsoft.CommandPalette.Extensions;
@ -23,6 +24,13 @@ internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposabl
Name = Resources.windowwalker_name;
Id = "com.microsoft.cmdpal.windowwalker";
PlaceholderText = Resources.windowwalker_PlaceholderText;
EmptyContent = new CommandItem(new NoOpCommand())
{
Icon = Icon,
Title = Resources.window_walker_top_level_command_title,
Subtitle = Resources.windowwalker_NoResultsMessage,
};
}
public override void UpdateSearchText(string oldSearch, string newSearch) =>

View File

@ -142,7 +142,7 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Properties {
}
/// <summary>
/// Looks up a localized string similar to You are going to end the following process:.
/// Looks up a localized string similar to The following process will be ended:.
/// </summary>
public static string windowwalker_KillMessage {
get {
@ -186,6 +186,15 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to No open windows found.
/// </summary>
public static string windowwalker_NoResultsMessage {
get {
return ResourceManager.GetString("windowwalker_NoResultsMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Not Responding.
/// </summary>

View File

@ -232,4 +232,7 @@
<data name="windowwalker_PlaceholderText" xml:space="preserve">
<value>Search open windows...</value>
</data>
<data name="windowwalker_NoResultsMessage" xml:space="preserve">
<value>No open windows found</value>
</data>
</root>

View File

@ -19,7 +19,7 @@ internal sealed class WindowsSetting
Name = string.Empty;
Command = string.Empty;
Type = string.Empty;
ShowAsFirstResult = false;
AppHomepageScore = 0;
}
/// <summary>
@ -65,9 +65,9 @@ internal sealed class WindowsSetting
public uint? DeprecatedInBuild { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to use a higher score as normal for this setting to show it as one of the first results.
/// Gets or sets the score for entries if they are a settings app (homepage). If the score is higher 0 they are shown on empty query.
/// </summary>
public bool ShowAsFirstResult { get; set; }
public int AppHomepageScore { get; set; }
/// <summary>
/// Gets or sets the value with the generated area path as string.

View File

@ -23,6 +23,13 @@ internal sealed partial class WindowsSettingsListPage : DynamicListPage
Name = Resources.settings_title;
Id = "com.microsoft.cmdpal.windowsSettings";
_windowsSettings = windowsSettings;
EmptyContent = new CommandItem(new NoOpCommand())
{
Icon = Icon,
Title = Resources.settings_subtitle,
Subtitle = Resources.PluginNoResultsMessage + "\n\n" + Resources.PluginNoResultsMessageHelp,
};
}
public WindowsSettingsListPage(Classes.WindowsSettings windowsSettings, string query)
@ -38,11 +45,21 @@ internal sealed partial class WindowsSettingsListPage : DynamicListPage
return new List<ListItem>(0);
}
var filteredList = _windowsSettings.Settings
.Select(setting => ScoringHelper.SearchScoringPredicate(query, setting))
.Where(scoredSetting => scoredSetting.Score > 0)
.OrderByDescending(scoredSetting => scoredSetting.Score)
.Select(scoredSetting => scoredSetting.Setting);
var filteredList = _windowsSettings.Settings;
if (!string.IsNullOrEmpty(query))
{
filteredList = filteredList
.Select(setting => ScoringHelper.SearchScoringPredicate(query, setting))
.Where(scoredSetting => scoredSetting.Score > 0)
.OrderByDescending(scoredSetting => scoredSetting.Score)
.Select(scoredSetting => scoredSetting.Setting);
}
else
{
filteredList = filteredList
.Where(s => s.AppHomepageScore > 0)
.OrderByDescending(s => s.AppHomepageScore);
}
var newList = ResultHelper.GetResultList(filteredList);
return newList;

View File

@ -322,7 +322,7 @@ namespace Microsoft.CmdPal.Ext.WindowsSettings.Properties {
}
/// <summary>
/// Looks up a localized string similar to System settings.
/// Looks up a localized string similar to Settings app.
/// </summary>
internal static string AppSettingsApp {
get {
@ -3049,7 +3049,7 @@ namespace Microsoft.CmdPal.Ext.WindowsSettings.Properties {
}
/// <summary>
/// Looks up a localized string similar to Control Panel (Application homepage).
/// Looks up a localized string similar to Open Control Panel.
/// </summary>
internal static string OpenControlPanel {
get {
@ -3058,7 +3058,16 @@ namespace Microsoft.CmdPal.Ext.WindowsSettings.Properties {
}
/// <summary>
/// Looks up a localized string similar to Open Settings.
/// Looks up a localized string similar to Open Microsoft Management Console.
/// </summary>
internal static string OpenMMC {
get {
return ResourceManager.GetString("OpenMMC", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open.
/// </summary>
internal static string OpenSettings {
get {
@ -3067,7 +3076,7 @@ namespace Microsoft.CmdPal.Ext.WindowsSettings.Properties {
}
/// <summary>
/// Looks up a localized string similar to Settings (Application homepage).
/// Looks up a localized string similar to Open Settings app.
/// </summary>
internal static string OpenSettingsApp {
get {
@ -3345,6 +3354,24 @@ namespace Microsoft.CmdPal.Ext.WindowsSettings.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to No settings found.
/// </summary>
internal static string PluginNoResultsMessage {
get {
return ResourceManager.GetString("PluginNoResultsMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Tip: Use &apos;:&apos; to search for setting categories (e.g., Update:), and &gt; to search by setting path (e.g., Settings app&gt;Apps)..
/// </summary>
internal static string PluginNoResultsMessageHelp {
get {
return ResourceManager.GetString("PluginNoResultsMessageHelp", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Windows settings.
/// </summary>

View File

@ -228,7 +228,7 @@
<comment>Area Apps</comment>
</data>
<data name="AppSettingsApp" xml:space="preserve">
<value>System settings</value>
<value>Settings app</value>
<comment>Type of the setting is a "Modern Windows settings". We use the same term as used in start menu search at the moment. </comment>
</data>
<data name="AppsForWebsites" xml:space="preserve">
@ -1319,11 +1319,11 @@
<value>On-Screen</value>
</data>
<data name="OpenControlPanel" xml:space="preserve">
<value>Control Panel (Application homepage)</value>
<value>Open Control Panel</value>
<comment>'Control Panel' is here the name of the legacy settings app.</comment>
</data>
<data name="OpenSettingsApp" xml:space="preserve">
<value>Settings (Application homepage)</value>
<value>Open Settings app</value>
<comment>'Settings' is here the name of the modern settings app.</comment>
</data>
<data name="Os" xml:space="preserve">
@ -2080,7 +2080,8 @@
<comment>Mean zooming of things via a magnifier</comment>
</data>
<data name="OpenSettings" xml:space="preserve">
<value>Open Settings</value>
<value>Open</value>
<comment>Open 'the setting' in Settings app, Control Panel or MMC.</comment>
</data>
<data name="WindowsSettingsProvider_DisplayName" xml:space="preserve">
<value>Windows Settings</value>
@ -2097,4 +2098,13 @@
<data name="settings_fallback_subtitle" xml:space="preserve">
<value>Search Windows settings for this device</value>
</data>
<data name="PluginNoResultsMessageHelp" xml:space="preserve">
<value>Tip: Use ':' to search for setting categories (e.g., Update:), and &gt; to search by setting path (e.g., Settings app&gt;Apps).</value>
</data>
<data name="PluginNoResultsMessage" xml:space="preserve">
<value>No settings found</value>
</data>
<data name="OpenMMC" xml:space="preserve">
<value>Open Microsoft Management Console</value>
</data>
</root>

View File

@ -6,13 +6,13 @@
"Type": "AppSettingsApp",
"AltNames": [ "SettingsApp", "AppSettingsApp" ],
"Command": "ms-settings:",
"ShowAsFirstResult": true
"AppHomepageScore": 30
},
{
"Name": "OpenControlPanel",
"Type": "AppControlPanel",
"Command": "control.exe",
"ShowAsFirstResult": true
"AppHomepageScore": 20
},
{
"Name": "AccessWorkOrSchool",
@ -1834,11 +1834,11 @@
"Command": "ms-settings-connectabledevices:devicediscovery"
},
{
"Name": "AppMMC",
"Name": "OpenMMC",
"Type": "AppMMC",
"AltNames": [ "MMC_mmcexe" ],
"Command": "mmc.exe",
"ShowAsFirstResult" : true
"AppHomepageScore" : 10
},
{
"Name": "AuthorizationManager",

View File

@ -62,9 +62,10 @@
"minimum": 0,
"maximum": 4294967295
},
"ShowAsFirstResult": {
"description": "Use a higher score as normal for this setting to show it as one of the first results.",
"type": "boolean"
"AppHomepageScore": {
"description": "Order score for the result if it is a settings app (homepage). Use a score > 0.",
"type": "integer",
"minimum": 1
}
}
}