From 4f3f7d649f1548362e12471b81c753ef0289ebe4 Mon Sep 17 00:00:00 2001 From: Michael Jolley Date: Fri, 6 Jun 2025 12:47:54 -0500 Subject: [PATCH] CmdPal: Improving order of results from settings search (#39525) The search results when finding settings with `$` was sorted alphabetically. Updated this behavior to sort them based on relevance to the query. Original search results with query provided in issue: ![image](https://github.com/user-attachments/assets/7ffd41bc-42d4-46fe-925e-aed7d7d04f3f) New search results with query provided in original issue: ![Image](https://github.com/user-attachments/assets/ab47fc25-9b90-4cc7-b476-253b23cee6f9) Example of results when giving a query that matches many, but is also an exact match. ![Image](https://github.com/user-attachments/assets/59982f41-d27c-4582-9b01-9a5683a26819) Closes #38615 --- .../Pages/WindowsSettingsListPage.cs | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowsSettings/Pages/WindowsSettingsListPage.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowsSettings/Pages/WindowsSettingsListPage.cs index 994db10445..3f5a6c6217 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowsSettings/Pages/WindowsSettingsListPage.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowsSettings/Pages/WindowsSettingsListPage.cs @@ -31,57 +31,81 @@ internal sealed partial class WindowsSettingsListPage : DynamicListPage } var filteredList = _windowsSettings.Settings - .Where(Predicate) - .OrderBy(found => found.Name); + .Select(SearchScoringPredicate) + .Where(scoredSetting => scoredSetting.Score > 0) + .OrderByDescending(scoredSetting => scoredSetting.Score) + .Select(scoredSetting => scoredSetting.Setting); var newList = ResultHelper.GetResultList(filteredList, query); return newList; - bool Predicate(WindowsSetting found) + // Rank settings by how they matched the search query. Order is: + // 1. Exact Name (10 points) + // 2. Name Starts With (8 points) + // 3. Name (5 points) + // 4. Area (4 points) + // 5. AltName (2 points) + // 6. Settings path (1 point) + (WindowsSetting Setting, int Score) SearchScoringPredicate(WindowsSetting setting) { if (string.IsNullOrWhiteSpace(query)) { // If no search string is entered skip query comparison. - return true; + return (setting, 0); } - if (found.Name.Contains(query, StringComparison.CurrentCultureIgnoreCase)) + if (string.Equals(setting.Name, query, StringComparison.OrdinalIgnoreCase)) { - return true; + return (setting, 10); } - if (!(found.Areas is null)) + if (setting.Name.StartsWith(query, StringComparison.CurrentCultureIgnoreCase)) { - foreach (var area in found.Areas) + return (setting, 8); + } + + if (setting.Name.Contains(query, StringComparison.CurrentCultureIgnoreCase)) + { + return (setting, 5); + } + + if (!(setting.Areas is null)) + { + foreach (var area in setting.Areas) { // Search for areas on normal queries. if (area.Contains(query, StringComparison.CurrentCultureIgnoreCase)) { - return true; + return (setting, 4); } // Search for Area only on queries with action char. if (area.Contains(query.Replace(":", string.Empty), StringComparison.CurrentCultureIgnoreCase) && query.EndsWith(":", StringComparison.CurrentCultureIgnoreCase)) { - return true; + return (setting, 4); } } } - if (!(found.AltNames is null)) + if (!(setting.AltNames is null)) { - foreach (var altName in found.AltNames) + foreach (var altName in setting.AltNames) { if (altName.Contains(query, StringComparison.CurrentCultureIgnoreCase)) { - return true; + return (setting, 2); } } } // Search by key char '>' for app name and settings path - return query.Contains('>') ? ResultHelper.FilterBySettingsPath(found, query) : false; + if (query.Contains('>') && ResultHelper.FilterBySettingsPath(setting, query)) + { + return (setting, 1); + } + + return (setting, 0); } }