Files
PowerToys/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/ProviderSettings.cs
Mike Griese 0f87b61dad CmdPal: Load pinned command items from anywhere (#45566)
This doesn't actually have a UX to expose this yet - we need to stack a
couple of PRs up to get to that.

But this adds plumbing such that we can now stash away a command ID, and
retrieve it later as a top-level command. Kinda like pinning for apps,
but for _anything_.

It works off of a new command provider interface `ICommandProvider4`,
which lets us look up Command**Item**s by ID. If we see a command ID
stored in that command provider's settings, we will try to look it up,
and then load it from the command provider.

e.g.

```json
    "com.microsoft.cmdpal.builtin.system": {
      "IsEnabled": true,
      "FallbackCommands": {
        "com.microsoft.cmdpal.builtin.system.fallback": {
          "IsEnabled": true,
          "IncludeInGlobalResults": true
        }
      },
      "PinnedCommandIds": [
        "com.microsoft.cmdpal.builtin.system.lock",
        "com.microsoft.cmdpal.builtin.system.restart_shell"
      ]
    },
```
will get us
<img width="840" height="197" alt="image"
src="https://github.com/user-attachments/assets/9ed19003-8361-4318-8dc9-055414456a51"
/>

Then it's just a matter of plumbing the command provider ID through the
layers, so that the command item knows who it is from. We'll need that
later for actually wiring this to the command's context menu.

related to #45191 
related to #45201
2026-02-19 16:20:05 -06:00

68 lines
2.0 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 System.Text.Json.Serialization;
namespace Microsoft.CmdPal.UI.ViewModels;
public class ProviderSettings
{
// List of built-in fallbacks that should not have global results enabled by default
private readonly string[] _excludedBuiltInFallbacks = [
"com.microsoft.cmdpal.builtin.indexer.fallback",
"com.microsoft.cmdpal.builtin.calculator.fallback",
];
public bool IsEnabled { get; set; } = true;
public Dictionary<string, FallbackSettings> FallbackCommands { get; set; } = new();
public List<string> PinnedCommandIds { get; set; } = [];
[JsonIgnore]
public string ProviderDisplayName { get; set; } = string.Empty;
[JsonIgnore]
public string ProviderId { get; private set; } = string.Empty;
[JsonIgnore]
public bool IsBuiltin { get; private set; }
public ProviderSettings(CommandProviderWrapper wrapper)
{
Connect(wrapper);
}
[JsonConstructor]
public ProviderSettings(bool isEnabled)
{
IsEnabled = isEnabled;
}
public void Connect(CommandProviderWrapper wrapper)
{
ProviderId = wrapper.ProviderId;
IsBuiltin = wrapper.Extension is null;
ProviderDisplayName = wrapper.DisplayName;
if (wrapper.FallbackItems.Length > 0)
{
foreach (var fallback in wrapper.FallbackItems)
{
if (!FallbackCommands.ContainsKey(fallback.Id))
{
var enableGlobalResults = IsBuiltin && !_excludedBuiltInFallbacks.Contains(fallback.Id);
FallbackCommands[fallback.Id] = new FallbackSettings(enableGlobalResults);
}
}
}
if (string.IsNullOrEmpty(ProviderId))
{
throw new InvalidDataException("Did you add a built-in command and forget to set the Id? Make sure you do that!");
}
}
}