Skip to content

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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.Commands;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;

Expand All @@ -18,8 +19,7 @@ public sealed partial class BuiltInsCommandProvider : CommandProvider
private readonly FallbackReloadItem _fallbackReloadItem = new();
private readonly FallbackLogItem _fallbackLogItem = new();
private readonly NewExtensionPage _newExtension = new();

private readonly IRootPageService _rootPageService;
private readonly GoHomeDockCommand _goHomeDockCommand = new();

public override ICommandItem[] TopLevelCommands() =>
[
Expand All @@ -41,22 +41,16 @@ public override IFallbackCommandItem[] FallbackCommands() =>
_fallbackLogItem,
];

public BuiltInsCommandProvider(IRootPageService rootPageService)
public BuiltInsCommandProvider()
{
Id = "com.microsoft.cmdpal.builtin.core";
DisplayName = Properties.Resources.builtin_display_name;
Icon = IconHelpers.FromRelativePath("Assets\\Square44x44Logo.altform-unplated_targetsize-256.png");

_rootPageService = rootPageService;
}

public override ICommandItem[]? GetDockBands()
{
var rootPage = _rootPageService.GetRootPage();
List<ICommandItem> bandItems = new();
bandItems.Add(new WrappedDockItem(rootPage, Properties.Resources.builtin_command_palette_title));

return bandItems.ToArray();
return [new WrappedDockItem(_goHomeDockCommand, Properties.Resources.builtin_command_palette_title)];
}

public override void InitializeWithHost(IExtensionHost host) => BuiltinsExtensionHost.Instance.Initialize(host);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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;
using Microsoft.CommandPalette.Extensions.Toolkit;

namespace Microsoft.CmdPal.UI.ViewModels.Commands;

/// <summary>
/// A lightweight command used as a dock band item that navigates the user
/// back to the Command Palette home page when invoked.
/// </summary>
internal sealed partial class GoHomeDockCommand : InvokableCommand
{
public GoHomeDockCommand()
{
Name = Properties.Resources.builtin_command_palette_title;
Icon = IconHelpers.FromRelativePath("Assets\\Square44x44Logo.altform-unplated_targetsize-256.png");
}

public override ICommandResult Invoke() => CommandResult.GoHome();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.CmdPal.Common.WinGet.Models;
using Microsoft.CmdPal.Common.WinGet.Services;
using Microsoft.CmdPal.UI.ViewModels.Properties;
using Microsoft.CmdPal.UI.ViewModels.Services;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;

Expand Down Expand Up @@ -50,7 +51,7 @@ private static readonly CompositeFormat LabelGalleryExtensionsFound
"Failed to check WinGet package status");

private readonly IExtensionGalleryService _galleryService;
private readonly IExtensionService _extensionService;
private readonly IEnumerable<IExtensionService> _extensionServices;
private readonly ILogger<ExtensionGalleryViewModel> _logger;
private readonly ExtensionGalleryItemViewModelFactory _galleryExtensionViewModelFactory;
private readonly IWinGetPackageManagerService? _winGetPackageManagerService;
Expand Down Expand Up @@ -162,7 +163,7 @@ public string ItemCounterText

public ExtensionGalleryViewModel(
IExtensionGalleryService galleryService,
IExtensionService extensionService,
IEnumerable<IExtensionService> extensionServices,
ILogger<ExtensionGalleryViewModel> logger,
ExtensionGalleryItemViewModelFactory galleryExtensionViewModelFactory,
IWinGetPackageManagerService? winGetPackageManagerService = null,
Expand All @@ -171,7 +172,7 @@ public ExtensionGalleryViewModel(
TaskScheduler? uiScheduler = null)
{
_galleryService = galleryService;
_extensionService = extensionService;
_extensionServices = extensionServices;
_logger = logger;
_galleryExtensionViewModelFactory = galleryExtensionViewModelFactory;
_winGetPackageManagerService = winGetPackageManagerService;
Expand Down Expand Up @@ -347,17 +348,23 @@ private async Task CheckInstalledAsync(
List<ExtensionGalleryItemViewModel> snapshot;
try
{
var installedExtensions = refreshInstalledExtensions
? await RunInBackgroundAsync(
() => _extensionService.RefreshInstalledExtensionsAsync(includeDisabledExtensions: true),
cancellationToken)
: await RunInBackgroundAsync(
() => _extensionService.GetInstalledExtensionsAsync(includeDisabledExtensions: true),
cancellationToken);
var allInstalledExtensions = new List<Common.Services.IExtensionWrapper>();
foreach (var service in _extensionServices)
{
var extensions = refreshInstalledExtensions
? await RunInBackgroundAsync(
() => service.RefreshInstalledExtensionsAsync(includeDisabledExtensions: true),
cancellationToken)
: await RunInBackgroundAsync(
() => service.GetInstalledExtensionsAsync(includeDisabledExtensions: true),
cancellationToken);
allInstalledExtensions.AddRange(extensions);
}

cancellationToken.ThrowIfCancellationRequested();

var installedPfns = new HashSet<string>(
installedExtensions
allInstalledExtensions
.Select(e => e.PackageFamilyName)
.Where(pfn => !string.IsNullOrEmpty(pfn)),
StringComparer.OrdinalIgnoreCase);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// 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.Services;
using Microsoft.CommandPalette.Extensions;
using Windows.Foundation;

namespace Microsoft.CmdPal.UI.ViewModels.Services;

/// <summary>
/// Extension service that manages in-process built-in command providers
/// registered in the DI container as <see cref="ICommandProvider"/>.
/// </summary>
public sealed class BuiltInExtensionService : IExtensionService
{
private readonly IEnumerable<ICommandProvider> _commandProviders;
private readonly TaskScheduler _taskScheduler;
private readonly List<IExtensionWrapper> _wrappers = [];

#pragma warning disable CS0067 // Events are required by the interface but not raised by this implementation
public event TypedEventHandler<IExtensionService, IEnumerable<CommandProviderWrapper>>? OnProviderAdded;

public event TypedEventHandler<IExtensionService, IEnumerable<CommandProviderWrapper>>? OnProviderRemoved;
#pragma warning restore CS0067

public BuiltInExtensionService(IEnumerable<ICommandProvider> commandProviders, TaskScheduler taskScheduler)
{
_commandProviders = commandProviders;
_taskScheduler = taskScheduler;
}

public Task<IEnumerable<CommandProviderWrapper>> LoadProvidersAsync(CancellationToken ct)
{
ct.ThrowIfCancellationRequested();

var wrappers = new List<CommandProviderWrapper>();
foreach (var provider in _commandProviders)
{
wrappers.Add(new CommandProviderWrapper(provider, _taskScheduler));
}

return Task.FromResult<IEnumerable<CommandProviderWrapper>>(wrappers);
}

public Task SignalStopAsync()
{
// Built-in providers are in-proc and don't need explicit stop signaling.
return Task.CompletedTask;
}

public Task<IEnumerable<IExtensionWrapper>> GetInstalledExtensionsAsync(bool includeDisabledExtensions = false)
{
return Task.FromResult<IEnumerable<IExtensionWrapper>>(_wrappers);
}

public Task<IEnumerable<IExtensionWrapper>> RefreshInstalledExtensionsAsync(bool includeDisabledExtensions = false)
{
// Built-in set is fixed at startup; refresh is a no-op.
return GetInstalledExtensionsAsync(includeDisabledExtensions);
}

public IExtensionWrapper? GetInstalledExtension(string extensionUniqueId)
{
return _wrappers.FirstOrDefault(w => w.ExtensionUniqueId == extensionUniqueId);
}

public void EnableExtension(string extensionUniqueId)
{
// TODO: persist enabled state in settings
}

public void DisableExtension(string extensionUniqueId)
{
// TODO: persist disabled state in settings
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// 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.Services;
using Windows.Foundation;

namespace Microsoft.CmdPal.UI.ViewModels.Services;

public interface IExtensionService
{
/// <summary>
/// Loads command providers managed by this service. Returns providers that
/// are immediately ready. Slow or late providers arrive via <see cref="OnProviderAdded"/>.
/// </summary>
/// <param name="ct">Cancellation token owned by the caller to cancel in-flight loading.</param>
/// <returns>Command provider wrappers that are started and ready for command loading.</returns>
Task<IEnumerable<CommandProviderWrapper>> LoadProvidersAsync(CancellationToken ct);

/// <summary>
/// Signals running providers managed by this service to stop/dispose.
/// </summary>
Task SignalStopAsync();

/// <summary>
/// Gets the currently cached installed extensions managed by this service.
/// </summary>
/// <param name="includeDisabledExtensions">True to include disabled extensions in the result.</param>
/// <returns>A sequence of installed extensions from the current in-memory cache.</returns>
Task<IEnumerable<IExtensionWrapper>> GetInstalledExtensionsAsync(bool includeDisabledExtensions = false);

/// <summary>
/// Forces a fresh scan of installed extensions and updates the in-memory cache.
/// </summary>
/// <param name="includeDisabledExtensions">True to include disabled extensions in the result.</param>
/// <returns>A sequence of installed extensions after the cache has been rebuilt.</returns>
Task<IEnumerable<IExtensionWrapper>> RefreshInstalledExtensionsAsync(bool includeDisabledExtensions = false);

/// <summary>
/// Gets a cached installed extension by its unique id.
/// </summary>
/// <param name="extensionUniqueId">The unique id of the extension to look up.</param>
/// <returns>The cached extension if found; otherwise, null.</returns>
IExtensionWrapper? GetInstalledExtension(string extensionUniqueId);

/// <summary>
/// Enables an installed extension by unique id.
/// </summary>
/// <param name="extensionUniqueId">The unique id of the extension to enable.</param>
void EnableExtension(string extensionUniqueId);

/// <summary>
/// Disables an installed extension by unique id.
/// </summary>
/// <param name="extensionUniqueId">The unique id of the extension to disable.</param>
void DisableExtension(string extensionUniqueId);

/// <summary>
/// Raised when one or more providers become available (late start, new package install, etc.).
/// </summary>
event TypedEventHandler<IExtensionService, IEnumerable<CommandProviderWrapper>>? OnProviderAdded;

/// <summary>
/// Raised when one or more providers are removed (package uninstall, etc.).
/// </summary>
event TypedEventHandler<IExtensionService, IEnumerable<CommandProviderWrapper>>? OnProviderRemoved;
}
Loading
Loading