mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 09:46:54 +02:00
Still a WIP, but here's the deets so far: ## No more throwing canceled tokens Throwing exceptions is expensive and since we essentially cancel tokens anytime someone is typing beyond the debounce, we could be throwing exceptions a ton during search. Since we don't care about those past executions, now they just `return`. ## Reduced number of apps returned in search While users can specify how many apps (no limit, 1, 5), if they specify no limit, we hard limit it at 10. For a few reasons, fuzzy search gets _really_ fuzzy sometimes and gives answers that users would think is just plain wrong and they make the response list longer than it needs to be. ## Fuzzy search: still fuzzy, but faster Replaced `StringMatcher` class with `FuzzyStringMatcher`. `FuzzyStringMatcher` is a C# port by @zadjii-msft of the Rust port by @lhecker for [microsoft/edit](https://github.com/microsoft/edit), which I believe originally came from [VS Code](https://github.com/microsoft/vscode). It's a whole fuzzy rabbit hole. But it's faster than the `StringMatcher` class it replaced. ## Fallbacks, you need to fall back "In the beginning, fallbacks were created. This had made many people very angry and has been widely regarded as a bad move." Hitchhiker's Guide to the Galaxy jokes aside, fallbacks are one cause of slower search results. A few modifications have been made to get them out of the way without reverting their ability to do things dynamically. 1. Fallbacks are no longer scored and will always* appear at the bottom of the search results 2. In updating their search text, we now use a cancellation token to stop processing previous searches when a new keypress is recorded. ## * But Calculator & Run are special So, remember when I said that all fallbacks will not be ranked and always display at the bottom of the results? Surprise, some will be ranked and displayed based on that score. Specifically, Calculator and Run are fallbacks that are whitelisted from the restrictions mentioned above. They will continue to act as they do today. We do have the ability to add future fallbacks to that whitelist as well. --- ## Current preview Updated: 2025-09-24 https://github.com/user-attachments/assets/c74c9a8e-e438-4101-840b-1408d2acaefd --- Closes #39763 Closes #39239 Closes #39948 Closes #38594 Closes #40330
90 lines
2.6 KiB
C#
90 lines
2.6 KiB
C#
// Copyright (c) Microsoft Corporation
|
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
// See the LICENSE file in the project root for more information.
|
|
using Microsoft.CommandPalette.Extensions.Toolkit;
|
|
|
|
namespace Microsoft.CmdPal.Ext.TimeDate.Helpers;
|
|
|
|
internal sealed class AvailableResult
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the time/date value
|
|
/// </summary>
|
|
internal string Value { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the text used for the subtitle and as search term
|
|
/// </summary>
|
|
internal string Label { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets an alternative search tag that will be evaluated if label doesn't match. For example we like to show the era on searches for 'year' too.
|
|
/// </summary>
|
|
internal string AlternativeSearchTag { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating the type of result
|
|
/// </summary>
|
|
internal ResultIconType IconType { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value to show additional error details
|
|
/// </summary>
|
|
internal string ErrorDetails { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Returns the path to the icon
|
|
/// </summary>
|
|
/// <param name="theme">Theme</param>
|
|
/// <returns>Path</returns>
|
|
public IconInfo GetIconInfo()
|
|
{
|
|
return IconType switch
|
|
{
|
|
ResultIconType.Time => Icons.TimeIcon,
|
|
ResultIconType.Date => Icons.CalendarIcon,
|
|
ResultIconType.DateTime => Icons.TimeDateIcon,
|
|
ResultIconType.Error => Icons.ErrorIcon,
|
|
_ => null,
|
|
};
|
|
}
|
|
|
|
public ListItem ToListItem()
|
|
{
|
|
return new ListItem(new CopyTextCommand(this.Value))
|
|
{
|
|
Title = this.Value,
|
|
Subtitle = this.Label,
|
|
Icon = this.GetIconInfo(),
|
|
Details = string.IsNullOrEmpty(this.ErrorDetails) ? null : new Details() { Body = this.ErrorDetails },
|
|
};
|
|
}
|
|
|
|
public int Score(string query, string label, string tags)
|
|
{
|
|
// Get match for label (or for tags if label score is <1)
|
|
var score = FuzzyStringMatcher.ScoreFuzzy(query, label);
|
|
if (score < 1)
|
|
{
|
|
foreach (var t in tags.Split(";"))
|
|
{
|
|
var tagScore = FuzzyStringMatcher.ScoreFuzzy(query, t.Trim()) / 2;
|
|
if (tagScore > score)
|
|
{
|
|
score = tagScore / 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
return score;
|
|
}
|
|
}
|
|
|
|
public enum ResultIconType
|
|
{
|
|
Time,
|
|
Date,
|
|
DateTime,
|
|
Error,
|
|
}
|