CmdPal: Fallback ranking and global results (#43549)

> [!IMPORTANT]
> For extension developers, this release includes a new required `string
Id` property for `FallbackCommandItem`. While your existing extensions
will continue to work, without this `Id` being set, your fallbacks will
not display and will not be rankable.
> Before this is released, you will want to prepare your extension
fallbacks.
> 
> As an example, we are naming our built-in extensions as:
> - Calculator extension provider Id:
`com.microsoft.cmdpal.builtin.calculator`
> - Calculator extension fallback:
`com.microsoft.cmdpal.builtin.calculator.fallback`
> 
> While the content of the Id isn't important, what is important is that
it is unique to your extension and fallback to avoid conflicting with
other extensions.

Now the good stuff:

## What the heck does it do!?

### The backstory

In PowerToys 0.95, we released performance improvements to Command
Palette. One of the many ways we improved its speed is by no longer
ranking fallback commands with other "top level" commands. Instead, all
fallbacks would surface at the bottom of the results and be listed in
the order they were registered with Command Palette. But this was only a
temporary solution until the work included in this pull request was
ready.

In reality, not all fallbacks were treated equally. We marked the
calculator and run fallbacks as "special." Special fallbacks **were**
ranked like top-level commands and allowed to surface to the top of the
results.

### The new "hotness"

This PR brings the power of fallback management back to the people. In
the Command Palette settings, you, dear user, can specify what order you
want fallbacks to display in at the bottom of the results. This keeps
those fallbacks unranked by Command Palette but displays them in an
order that makes sense for you. But keep in mind, these will still live
at the bottom of search results.

But alas, we have also heard your cries that you'd like _some_ fallbacks
to be ranked by Command Palette and surface to the top of the results.
So, this PR allows you to mark any fallback as "special" by choosing to
include them in the global results. Special (Global) fallbacks are
treated like "top level" commands and appear in the search result based
on their title & description.

### Screenshots/video

<img width="1005" height="611" alt="image"
src="https://github.com/user-attachments/assets/8ba5d861-f887-47ed-8552-ba78937322d2"
/>

<img width="1501" height="973" alt="image"
src="https://github.com/user-attachments/assets/9edb7675-8084-4f14-8bdc-72d7d06d500e"
/>

<img width="706" height="744" alt="image"
src="https://github.com/user-attachments/assets/81ae0252-b87d-4172-a5ea-4d3102134baf"
/>

<img width="666" height="786" alt="image"
src="https://github.com/user-attachments/assets/acb76acf-531d-4e60-bb44-d1edeec77dce"
/>


### GitHub issue maintenance details

Closes #38312
Closes #38288
Closes #42524
Closes #41024
Closes #40351
Closes #41696
Closes #40193

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Jiří Polášek <me@jiripolasek.com>
This commit is contained in:
Michael Jolley
2025-12-22 17:08:15 -06:00
committed by GitHub
parent 8682d0f54d
commit f1e045751a
41 changed files with 738 additions and 192 deletions

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="Microsoft.CmdPal.UI.Controls.FallbackRanker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cmdpalUI="using:Microsoft.CmdPal.UI"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
xmlns:coreViewModels="using:Microsoft.CmdPal.Core.ViewModels"
xmlns:cpcontrols="using:Microsoft.CmdPal.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:helpers="using:Microsoft.CmdPal.UI.Helpers"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="using:Microsoft.CmdPal.UI.ViewModels"
mc:Ignorable="d">
<Grid>
<ListView
Padding="12,0,24,0"
AllowDrop="True"
CanDragItems="True"
CanReorderItems="True"
DragItemsCompleted="ListView_DragItemsCompleted"
ItemsSource="{x:Bind viewModel.FallbackRankings, Mode=OneWay}"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate x:DataType="viewModels:FallbackSettingsViewModel">
<Grid Padding="4,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Viewbox Grid.Column="1" Height="18">
<PathIcon Data="M15.5 17C16.3284 17 17 17.6716 17 18.5C17 19.3284 16.3284 20 15.5 20C14.6716 20 14 19.3284 14 18.5C14 17.6716 14.6716 17 15.5 17ZM8.5 17C9.32843 17 10 17.6716 10 18.5C10 19.3284 9.32843 20 8.5 20C7.67157 20 7 19.3284 7 18.5C7 17.6716 7.67157 17 8.5 17ZM15.5 10C16.3284 10 17 10.6716 17 11.5C17 12.3284 16.3284 13 15.5 13C14.6716 13 14 12.3284 14 11.5C14 10.6716 14.6716 10 15.5 10ZM8.5 10C9.32843 10 10 10.6716 10 11.5C10 12.3284 9.32843 13 8.5 13C7.67157 13 7 12.3284 7 11.5C7 10.6716 7.67157 10 8.5 10ZM15.5 3C16.3284 3 17 3.67157 17 4.5C17 5.32843 16.3284 6 15.5 6C14.6716 6 14 5.32843 14 4.5C14 3.67157 14.6716 3 15.5 3ZM8.5 3C9.32843 3 10 3.67157 10 4.5C10 5.32843 9.32843 6 8.5 6C7.67157 6 7 5.32843 7 4.5C7 3.67157 7.67157 3 8.5 3Z" Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</Viewbox>
<controls:SettingsCard
Width="560"
MinHeight="0"
Padding="8"
Background="Transparent"
BorderThickness="0"
Header="{x:Bind DisplayName}"
ToolTipService.ToolTip="{x:Bind Id}">
<controls:SettingsCard.HeaderIcon>
<cpcontrols:ContentIcon>
<cpcontrols:ContentIcon.Content>
<cpcontrols:IconBox
Width="16"
Height="16"
AutomationProperties.AccessibilityView="Raw"
SourceKey="{x:Bind Icon, Mode=OneWay}"
SourceRequested="{x:Bind helpers:IconCacheProvider.SourceRequested}" />
</cpcontrols:ContentIcon.Content>
</cpcontrols:ContentIcon>
</controls:SettingsCard.HeaderIcon>
</controls:SettingsCard>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<!-- Customize Size of Item Container from ListView -->
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Spacing="0" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style BasedOn="{StaticResource DefaultListViewItemStyle}" TargetType="ListViewItem">
<Setter Property="Margin" Value="0" />
<Setter Property="Padding" Value="4" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
</UserControl>

View File

@@ -0,0 +1,31 @@
// 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.CmdPal.UI.ViewModels;
using Microsoft.CmdPal.UI.ViewModels.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml.Controls;
namespace Microsoft.CmdPal.UI.Controls;
public sealed partial class FallbackRanker : UserControl
{
private readonly TaskScheduler _mainTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
private SettingsViewModel? viewModel;
public FallbackRanker()
{
this.InitializeComponent();
var settings = App.Current.Services.GetService<SettingsModel>()!;
var topLevelCommandManager = App.Current.Services.GetService<TopLevelCommandManager>()!;
var themeService = App.Current.Services.GetService<IThemeService>()!;
viewModel = new SettingsViewModel(settings, topLevelCommandManager, _mainTaskScheduler, themeService);
}
private void ListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
{
viewModel?.ApplyFallbackSort();
}
}

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="Microsoft.CmdPal.UI.Controls.FallbackRankerDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cpcontrols="using:Microsoft.CmdPal.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<ContentDialog
x:Name="FallbackRankerContentDialog"
Width="420"
MinWidth="420"
PrimaryButtonText="OK">
<ContentDialog.Title>
<TextBlock x:Uid="ManageFallbackRank" />
</ContentDialog.Title>
<ContentDialog.Resources>
<x:Double x:Key="ContentDialogMaxWidth">800</x:Double>
</ContentDialog.Resources>
<Grid Width="560" MinWidth="420">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
x:Uid="ManageFallbackOrderDialogDescription"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap" />
<Rectangle
Grid.Row="1"
Height="1"
Margin="0,16,0,16"
HorizontalAlignment="Stretch"
Fill="{ThemeResource DividerStrokeColorDefaultBrush}" />
<cpcontrols:FallbackRanker
x:Name="FallbackRanker"
Grid.Row="2"
Margin="-24,0,-24,0" />
</Grid>
</ContentDialog>
</UserControl>

View File

@@ -0,0 +1,33 @@
// 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 System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Windows.Foundation;
using Windows.Foundation.Collections;
namespace Microsoft.CmdPal.UI.Controls;
public sealed partial class FallbackRankerDialog : UserControl
{
public FallbackRankerDialog()
{
InitializeComponent();
}
public IAsyncOperation<ContentDialogResult> ShowAsync()
{
return FallbackRankerContentDialog!.ShowAsync()!;
}
}