CmdPal: Add context commands for pinning nested commands (#45673)

_targets #45572_

This change allows our contact menu factory to actually create and add
additional context menu commands for pinning commands to the top level.
Now for any command provider built with the latest SDK that return
subcommands with an ID, we will add additional context menu commands
that allows you to pin that command to the top level.

<img width="540" height="181" alt="image"
src="https://github.com/user-attachments/assets/6c2cfe3c-4143-44d1-9308-bfc71db4c842"
/>
<img width="729" height="317" alt="image"
src="https://github.com/user-attachments/assets/4ff75c9f-1f35-4c1e-a03e-6fab5cbab423"
/>

related to https://github.com/microsoft/PowerToys/issues/45191
related to https://github.com/microsoft/PowerToys/issues/45201


This PR notably does not remove pinning from the apps extension. I
thought that made sense to do as a follow-up PR for the sake of
reviewability.

--- 

description from #45676 which was merged into this

Removes the code that the apps provider was using to support pinning
apps to the top level list of commands. Now the all apps provider just
uses the global support for pinning commands to the top level.

This does have the side effect of removing the separation of pinned apps
from unpinned apps on the All Apps page. However, we all pretty much
agree that wasn't a particularly widely used feature, and it's safe to
remove.

With this, we can finally call this issue done 🎉
closes https://github.com/microsoft/PowerToys/issues/45191
This commit is contained in:
Mike Griese
2026-02-26 10:09:17 -06:00
committed by GitHub
parent cdeae7c854
commit 7a0e4ac891
30 changed files with 389 additions and 434 deletions

View File

@@ -166,5 +166,5 @@ public interface IAppHostService
AppExtensionHost GetHostForCommand(object? context, AppExtensionHost? currentHost);
CommandProviderContext GetProviderContextForCommand(object? command, CommandProviderContext? currentContext);
ICommandProviderContext GetProviderContextForCommand(object? command, ICommandProviderContext? currentContext);
}

View File

@@ -22,7 +22,7 @@ public partial class CommandContextItemViewModel : CommandItemViewModel, IContex
public bool HasRequestedShortcut => RequestedShortcut is not null && (RequestedShortcut.Value != nullKeyChord);
public CommandContextItemViewModel(ICommandContextItem contextItem, WeakReference<IPageContext> context)
: base(new(contextItem), context)
: base(new(contextItem), context, contextMenuFactory: null)
{
Model = new(contextItem);
IsContextMenuItem = true;

View File

@@ -103,7 +103,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
public CommandItemViewModel(
ExtensionObject<ICommandItem> item,
WeakReference<IPageContext> errorContext,
IContextMenuFactory? contextMenuFactory = null)
IContextMenuFactory? contextMenuFactory)
: base(errorContext)
{
_commandItemModel = item;
@@ -464,6 +464,30 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
.ForEach(c => c.SafeCleanup());
}
public void RefreshMoreCommands()
{
Task.Run(RefreshMoreCommandsSynchronous);
}
private void RefreshMoreCommandsSynchronous()
{
try
{
BuildAndInitMoreCommands();
UpdateProperty(nameof(MoreCommands));
UpdateProperty(nameof(AllCommands));
UpdateProperty(nameof(SecondaryCommand));
UpdateProperty(nameof(SecondaryCommandName));
UpdateProperty(nameof(HasMoreCommands));
}
catch (Exception ex)
{
// Handle any exceptions that might occur during the refresh process
CoreLogger.LogError("Error refreshing MoreCommands in CommandItemViewModel", ex);
ShowException(ex, _commandItemModel?.Unsafe?.Title);
}
}
protected override void UnsafeCleanup()
{
base.UnsafeCleanup();

View File

@@ -8,7 +8,7 @@ namespace Microsoft.CmdPal.UI.ViewModels;
public partial class CommandPaletteContentPageViewModel : ContentPageViewModel
{
public CommandPaletteContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host, CommandProviderContext providerContext)
public CommandPaletteContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host, ICommandProviderContext providerContext)
: base(model, scheduler, host, providerContext)
{
}

View File

@@ -10,15 +10,15 @@ public class CommandPalettePageViewModelFactory
: IPageViewModelFactoryService
{
private readonly TaskScheduler _scheduler;
private readonly IContextMenuFactory? _contextMenuFactory;
private readonly IContextMenuFactory _contextMenuFactory;
public CommandPalettePageViewModelFactory(TaskScheduler scheduler, IContextMenuFactory? contextMenuFactory)
public CommandPalettePageViewModelFactory(TaskScheduler scheduler, IContextMenuFactory contextMenuFactory)
{
_scheduler = scheduler;
_contextMenuFactory = contextMenuFactory;
}
public PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host, CommandProviderContext providerContext)
public PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host, ICommandProviderContext providerContext)
{
return page switch
{

View File

@@ -4,9 +4,21 @@
namespace Microsoft.CmdPal.UI.ViewModels;
public sealed class CommandProviderContext
public static class CommandProviderContext
{
public required string ProviderId { get; init; }
public static ICommandProviderContext Empty { get; } = new EmptyCommandProviderContext();
public static CommandProviderContext Empty { get; } = new() { ProviderId = "<EMPTY>" };
private sealed class EmptyCommandProviderContext : ICommandProviderContext
{
public string ProviderId => "<EMPTY>";
public bool SupportsPinning => false;
}
}
public interface ICommandProviderContext
{
string ProviderId { get; }
bool SupportsPinning { get; }
}

View File

@@ -13,7 +13,7 @@ using Windows.Foundation;
namespace Microsoft.CmdPal.UI.ViewModels;
public sealed class CommandProviderWrapper
public sealed class CommandProviderWrapper : ICommandProviderContext
{
public bool IsExtension => Extension is not null;
@@ -47,12 +47,17 @@ public sealed class CommandProviderWrapper
public string ProviderId => string.IsNullOrEmpty(Extension?.ExtensionUniqueId) ? Id : Extension.ExtensionUniqueId;
public bool SupportsPinning { get; private set; }
public TopLevelItemPageContext TopLevelPageContext { get; }
public CommandProviderWrapper(ICommandProvider provider, TaskScheduler mainThread)
{
// This ctor is only used for in-proc builtin commands. So the Unsafe!
// calls are pretty dang safe actually.
_commandProvider = new(provider);
_taskScheduler = mainThread;
TopLevelPageContext = new TopLevelItemPageContext(this, _taskScheduler);
// Hook the extension back into us
ExtensionHost = new CommandPaletteHost(provider);
@@ -77,6 +82,7 @@ public sealed class CommandProviderWrapper
{
_taskScheduler = mainThread;
_commandProviderCache = commandProviderCache;
TopLevelPageContext = new TopLevelItemPageContext(this, _taskScheduler);
Extension = extension;
ExtensionHost = new CommandPaletteHost(extension);
@@ -121,7 +127,7 @@ public sealed class CommandProviderWrapper
return settings.GetProviderSettings(this);
}
public async Task LoadTopLevelCommands(IServiceProvider serviceProvider, WeakReference<IPageContext> pageContext)
public async Task LoadTopLevelCommands(IServiceProvider serviceProvider)
{
if (!isValid)
{
@@ -157,8 +163,14 @@ public sealed class CommandProviderWrapper
UnsafePreCacheApiAdditions(two);
}
// Load pinned commands from saved settings
var pinnedCommands = LoadPinnedCommands(model, providerSettings);
ICommandItem[] pinnedCommands = [];
if (model is ICommandProvider4 four)
{
SupportsPinning = true;
// Load pinned commands from saved settings
pinnedCommands = LoadPinnedCommands(four, providerSettings);
}
Id = model.Id;
DisplayName = model.DisplayName;
@@ -177,7 +189,7 @@ public sealed class CommandProviderWrapper
Settings = new(model.Settings, this, _taskScheduler);
// We do need to explicitly initialize commands though
InitializeCommands(commands, fallbacks, pinnedCommands, serviceProvider, pageContext);
InitializeCommands(commands, fallbacks, pinnedCommands, serviceProvider);
Logger.LogDebug($"Loaded commands from {DisplayName} ({ProviderId})");
}
@@ -208,14 +220,20 @@ public sealed class CommandProviderWrapper
}
}
private void InitializeCommands(ICommandItem[] commands, IFallbackCommandItem[] fallbacks, ICommandItem[] pinnedCommands, IServiceProvider serviceProvider, WeakReference<IPageContext> pageContext)
private void InitializeCommands(
ICommandItem[] commands,
IFallbackCommandItem[] fallbacks,
ICommandItem[] pinnedCommands,
IServiceProvider serviceProvider)
{
var settings = serviceProvider.GetService<SettingsModel>()!;
var contextMenuFactory = serviceProvider.GetService<IContextMenuFactory>()!;
var providerSettings = GetProviderSettings(settings);
var ourContext = GetProviderContext();
var pageContext = new WeakReference<IPageContext>(TopLevelPageContext);
var makeAndAdd = (ICommandItem? i, bool fallback) =>
{
CommandItemViewModel commandItemViewModel = new(new(i), pageContext);
CommandItemViewModel commandItemViewModel = new(new(i), pageContext, contextMenuFactory: contextMenuFactory);
TopLevelViewModel topLevelViewModel = new(commandItemViewModel, fallback, ExtensionHost, ourContext, settings, providerSettings, serviceProvider, i);
topLevelViewModel.InitializeProperties();
@@ -244,27 +262,24 @@ public sealed class CommandProviderWrapper
}
}
private ICommandItem[] LoadPinnedCommands(ICommandProvider model, ProviderSettings providerSettings)
private ICommandItem[] LoadPinnedCommands(ICommandProvider4 model, ProviderSettings providerSettings)
{
var pinnedItems = new List<ICommandItem>();
if (model is ICommandProvider4 provider4)
foreach (var pinnedId in providerSettings.PinnedCommandIds)
{
foreach (var pinnedId in providerSettings.PinnedCommandIds)
try
{
try
var commandItem = model.GetCommandItem(pinnedId);
if (commandItem is not null)
{
var commandItem = provider4.GetCommandItem(pinnedId);
if (commandItem is not null)
{
pinnedItems.Add(commandItem);
}
}
catch (Exception e)
{
Logger.LogError($"Failed to load pinned command {pinnedId}: {e.Message}");
pinnedItems.Add(commandItem);
}
}
catch (Exception e)
{
Logger.LogError($"Failed to load pinned command {pinnedId}: {e.Message}");
}
}
return pinnedItems.ToArray();
@@ -298,11 +313,22 @@ public sealed class CommandProviderWrapper
}
}
public CommandProviderContext GetProviderContext()
public void UnpinCommand(string commandId, IServiceProvider serviceProvider)
{
return new() { ProviderId = ProviderId };
var settings = serviceProvider.GetService<SettingsModel>()!;
var providerSettings = GetProviderSettings(settings);
if (providerSettings.PinnedCommandIds.Remove(commandId))
{
SettingsModel.SaveSettings(settings);
// Raise CommandsChanged so the TopLevelCommandManager reloads our commands
this.CommandsChanged?.Invoke(this, new ItemsChangedEventArgs(-1));
}
}
public ICommandProviderContext GetProviderContext() => this;
public override bool Equals(object? obj) => obj is CommandProviderWrapper wrapper && isValid == wrapper.isValid;
public override int GetHashCode() => _commandProvider.GetHashCode();

View File

@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation
// 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.
@@ -11,7 +11,6 @@ using Microsoft.CmdPal.Common.Helpers;
using Microsoft.CmdPal.Common.Text;
using Microsoft.CmdPal.Ext.Apps;
using Microsoft.CmdPal.Ext.Apps.Programs;
using Microsoft.CmdPal.Ext.Apps.State;
using Microsoft.CmdPal.UI.ViewModels.Commands;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Properties;
@@ -409,11 +408,13 @@ public sealed partial class MainListPage : DynamicListPage,
var allNewApps = AllAppsCommandProvider.Page.GetItems().Cast<AppListItem>().ToList();
// We need to remove pinned apps from allNewApps so they don't show twice.
var pinnedApps = PinnedAppsManager.Instance.GetPinnedAppIdentifiers();
// Pinned app command IDs are stored in ProviderSettings.PinnedCommandIds.
_settings.ProviderSettings.TryGetValue(AllAppsCommandProvider.WellKnownId, out var providerSettings);
var pinnedCommandIds = providerSettings?.PinnedCommandIds;
if (pinnedApps.Length > 0)
if (pinnedCommandIds is not null && pinnedCommandIds.Count > 0)
{
newApps = allNewApps.Where(w => pinnedApps.IndexOf(w.AppIdentifier) < 0);
newApps = allNewApps.Where(li => li.Command != null && !pinnedCommandIds.Contains(li.Command.Id));
}
else
{

View File

@@ -47,7 +47,7 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
// Remember - "observable" properties from the model (via PropChanged)
// cannot be marked [ObservableProperty]
public ContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host, CommandProviderContext providerContext)
public ContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host, ICommandProviderContext providerContext)
: base(model, scheduler, host, providerContext)
{
_model = new(model);

View File

@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation
// 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.
@@ -8,6 +8,8 @@ public class GlobalLogPageContext : IPageContext
{
public TaskScheduler Scheduler { get; private init; }
ICommandProviderContext IPageContext.ProviderContext => CommandProviderContext.Empty;
public void ShowException(Exception ex, string? extensionHint)
{ /*do nothing*/
}

View File

@@ -0,0 +1,18 @@
// 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.UI.ViewModels;
public static class Icons
{
public static IconInfo PinIcon => new("\uE718"); // Pin icon
public static IconInfo UnpinIcon => new("\uE77A"); // Unpin icon
public static IconInfo SettingsIcon => new("\uE713"); // Settings icon
public static IconInfo EditIcon => new("\uE70F"); // Edit icon
}

View File

@@ -63,7 +63,7 @@ public partial class ListItemViewModel : CommandItemViewModel
}
}
public ListItemViewModel(IListItem model, WeakReference<IPageContext> context, IContextMenuFactory? contextMenuFactory = null)
public ListItemViewModel(IListItem model, WeakReference<IPageContext> context, IContextMenuFactory contextMenuFactory)
: base(new(model), context, contextMenuFactory)
{
Model = new ExtensionObject<IListItem>(model);

View File

@@ -36,7 +36,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
private readonly ExtensionObject<IListPage> _model;
private readonly Lock _listLock = new();
private readonly IContextMenuFactory? _contextMenuFactory;
private readonly IContextMenuFactory _contextMenuFactory;
private InterlockedBoolean _isLoading;
private bool _isFetching;
@@ -96,12 +96,12 @@ public partial class ListViewModel : PageViewModel, IDisposable
}
}
public ListViewModel(IListPage model, TaskScheduler scheduler, AppExtensionHost host, CommandProviderContext providerContext, IContextMenuFactory? contextMenuFactory)
public ListViewModel(IListPage model, TaskScheduler scheduler, AppExtensionHost host, ICommandProviderContext providerContext, IContextMenuFactory contextMenuFactory)
: base(model, scheduler, host, providerContext)
{
_model = new(model);
_contextMenuFactory = contextMenuFactory;
EmptyContent = new(new(null), PageContext, _contextMenuFactory);
EmptyContent = new(new(null), PageContext, contextMenuFactory: null);
}
private void FiltersPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
@@ -243,7 +243,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
continue;
}
var viewModel = new ListItemViewModel(item, new(this));
var viewModel = new ListItemViewModel(item, new(this), _contextMenuFactory);
// If an item fails to load, silently ignore it.
if (viewModel.SafeFastInit())
@@ -636,7 +636,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
UpdateProperty(nameof(SearchText));
UpdateProperty(nameof(InitialSearchText));
EmptyContent = new(new(model.EmptyContent), PageContext);
EmptyContent = new(new(model.EmptyContent), PageContext, _contextMenuFactory);
EmptyContent.SlowInitializeProperties();
Filters?.PropertyChanged -= FiltersPropertyChanged;
@@ -732,7 +732,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
SearchText = model.SearchText;
break;
case nameof(EmptyContent):
EmptyContent = new(new(model.EmptyContent), PageContext);
EmptyContent = new(new(model.EmptyContent), PageContext, contextMenuFactory: null);
EmptyContent.SlowInitializeProperties();
break;
case nameof(Filters):
@@ -806,7 +806,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
base.UnsafeCleanup();
EmptyContent?.SafeCleanup();
EmptyContent = new(new(null), PageContext); // necessary?
EmptyContent = new(new(null), PageContext, contextMenuFactory: null); // necessary?
_cancellationTokenSource?.Cancel();
filterCancellationTokenSource?.Cancel();

View File

@@ -0,0 +1,9 @@
// 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.
namespace Microsoft.CmdPal.UI.ViewModels.Messages;
public record UnpinCommandItemMessage(string ProviderId, string CommandId)
{
}

View File

@@ -76,9 +76,9 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
public IconInfoViewModel Icon { get; protected set; }
public CommandProviderContext ProviderContext { get; protected set; }
public ICommandProviderContext ProviderContext { get; protected set; }
public PageViewModel(IPage? model, TaskScheduler scheduler, AppExtensionHost extensionHost, CommandProviderContext providerContext)
public PageViewModel(IPage? model, TaskScheduler scheduler, AppExtensionHost extensionHost, ICommandProviderContext providerContext)
: base(scheduler)
{
InitializeSelfAsPageContext();
@@ -267,6 +267,8 @@ public interface IPageContext
void ShowException(Exception ex, string? extensionHint = null);
TaskScheduler Scheduler { get; }
ICommandProviderContext ProviderContext { get; }
}
public interface IPageViewModelFactoryService
@@ -278,5 +280,5 @@ public interface IPageViewModelFactoryService
/// <param name="nested">Indicates whether the page is not the top-level page.</param>
/// <param name="host">The command palette host that will host the page (for status messages)</param>
/// <returns>A new instance of the page view model.</returns>
PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host, CommandProviderContext providerContext);
PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host, ICommandProviderContext providerContext);
}

View File

@@ -22,7 +22,7 @@ namespace Microsoft.CmdPal.UI.ViewModels;
public partial class TopLevelCommandManager : ObservableObject,
IRecipient<ReloadCommandsMessage>,
IRecipient<PinCommandItemMessage>,
IPageContext,
IRecipient<UnpinCommandItemMessage>,
IDisposable
{
private readonly IServiceProvider _serviceProvider;
@@ -34,8 +34,6 @@ public partial class TopLevelCommandManager : ObservableObject,
private readonly Lock _commandProvidersLock = new();
private readonly SupersedingAsyncGate _reloadCommandsGate;
TaskScheduler IPageContext.Scheduler => _taskScheduler;
public TopLevelCommandManager(IServiceProvider serviceProvider, ICommandProviderCache commandProviderCache)
{
_serviceProvider = serviceProvider;
@@ -43,6 +41,7 @@ public partial class TopLevelCommandManager : ObservableObject,
_taskScheduler = _serviceProvider.GetService<TaskScheduler>()!;
WeakReferenceMessenger.Default.Register<ReloadCommandsMessage>(this);
WeakReferenceMessenger.Default.Register<PinCommandItemMessage>(this);
WeakReferenceMessenger.Default.Register<UnpinCommandItemMessage>(this);
_reloadCommandsGate = new(ReloadAllCommandsAsyncCore);
}
@@ -103,9 +102,7 @@ public partial class TopLevelCommandManager : ObservableObject,
// May be called from a background thread
private async Task<IEnumerable<TopLevelViewModel>> LoadTopLevelCommandsFromProvider(CommandProviderWrapper commandProvider)
{
WeakReference<IPageContext> weakSelf = new(this);
await commandProvider.LoadTopLevelCommands(_serviceProvider, weakSelf);
await commandProvider.LoadTopLevelCommands(_serviceProvider);
var commands = await Task.Factory.StartNew(
() =>
@@ -152,8 +149,7 @@ public partial class TopLevelCommandManager : ObservableObject,
/// <returns>an awaitable task</returns>
private async Task UpdateCommandsForProvider(CommandProviderWrapper sender, IItemsChangedEventArgs args)
{
WeakReference<IPageContext> weakSelf = new(this);
await sender.LoadTopLevelCommands(_serviceProvider, weakSelf);
await sender.LoadTopLevelCommands(_serviceProvider);
List<TopLevelViewModel> newItems = [.. sender.TopLevelItems];
foreach (var i in sender.FallbackItems)
@@ -421,7 +417,13 @@ public partial class TopLevelCommandManager : ObservableObject,
wrapper?.PinCommand(message.CommandId, _serviceProvider);
}
private CommandProviderWrapper? LookupProvider(string providerId)
public void Receive(UnpinCommandItemMessage message)
{
var wrapper = LookupProvider(message.ProviderId);
wrapper?.UnpinCommand(message.CommandId, _serviceProvider);
}
public CommandProviderWrapper? LookupProvider(string providerId)
{
lock (_commandProvidersLock)
{
@@ -430,12 +432,6 @@ public partial class TopLevelCommandManager : ObservableObject,
}
}
void IPageContext.ShowException(Exception ex, string? extensionHint)
{
var message = DiagnosticsHelper.BuildExceptionMessage(ex, extensionHint ?? "TopLevelCommandManager");
CommandPaletteHost.Instance.Log(message);
}
internal bool IsProviderActive(string id)
{
lock (_commandProvidersLock)

View File

@@ -0,0 +1,36 @@
// 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.Common.Helpers;
namespace Microsoft.CmdPal.UI.ViewModels;
/// <summary>
/// Used as the PageContext for top-level items. Top level items are displayed
/// on the MainListPage, which _we_ own. We need to have a placeholder page
/// context for each provider that still connects those top-level items to the
/// CommandProvider they came from.
/// </summary>
public partial class TopLevelItemPageContext : IPageContext
{
public TaskScheduler Scheduler { get; private set; }
public ICommandProviderContext ProviderContext { get; private set; }
TaskScheduler IPageContext.Scheduler => Scheduler;
ICommandProviderContext IPageContext.ProviderContext => ProviderContext;
internal TopLevelItemPageContext(CommandProviderWrapper provider, TaskScheduler scheduler)
{
ProviderContext = provider.GetProviderContext();
Scheduler = scheduler;
}
public void ShowException(Exception ex, string? extensionHint = null)
{
var message = DiagnosticsHelper.BuildExceptionMessage(ex, extensionHint ?? $"TopLevelItemPageContext({ProviderContext.ProviderId})");
CommandPaletteHost.Instance.Log(message);
}
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation
// 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.
@@ -26,7 +26,7 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx
private readonly IServiceProvider _serviceProvider;
private readonly CommandItemViewModel _commandItemViewModel;
public CommandProviderContext ProviderContext { get; private set; }
public ICommandProviderContext ProviderContext { get; private set; }
private string IdFromModel => IsFallback && !string.IsNullOrWhiteSpace(_fallbackId) ? _fallbackId : _commandItemViewModel.Command.Id;
@@ -189,7 +189,7 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx
CommandItemViewModel item,
bool isFallback,
CommandPaletteHost extensionHost,
CommandProviderContext commandProviderContext,
ICommandProviderContext commandProviderContext,
SettingsModel settings,
ProviderSettings providerSettings,
IServiceProvider serviceProvider,