CmdPal: Move core projects into Core/ (#41358)

Couple little things here:

* Makes `Microsoft.CmdPal.Common` a `Core` project
* Moves the `CmdPal.Core` projects into a single `Core/` directory
* Adds the `CoreLogger` which I had stashed in
https://github.com/microsoft/PowerToys/compare/dev/migrie/40113/extension-hosts-try-2...dev/migrie/b/remove-core-managedcommon-dep
a while back
* De-duplicates a bunch of commands that were in both Apps and Common
* moves all the commands into the toolkit, instead of in the Common
project
This commit is contained in:
Mike Griese
2025-09-26 08:05:37 -05:00
committed by GitHub
parent a4d4a9a3d9
commit 2e0fe16128
139 changed files with 477 additions and 640 deletions

View File

@@ -0,0 +1,155 @@
// 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.Diagnostics.CodeAnalysis;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Common.Commands;
public sealed partial class ConfirmableCommand : InvokableCommand
{
private readonly IInvokableCommand? _command;
public Func<bool>? IsConfirmationRequired { get; init; }
public required string ConfirmationTitle { get; init; }
public required string ConfirmationMessage { get; init; }
public required IInvokableCommand Command
{
get => _command!;
init
{
if (_command is INotifyPropChanged oldNotifier)
{
oldNotifier.PropChanged -= InnerCommand_PropChanged;
}
_command = value;
if (_command is INotifyPropChanged notifier)
{
notifier.PropChanged += InnerCommand_PropChanged;
}
OnPropertyChanged(nameof(Name));
OnPropertyChanged(nameof(Id));
OnPropertyChanged(nameof(Icon));
}
}
public override string Name
{
get => (_command as Command)?.Name ?? base.Name;
set
{
if (_command is Command cmd)
{
cmd.Name = value;
}
else
{
base.Name = value;
}
}
}
public override string Id
{
get => (_command as Command)?.Id ?? base.Id;
set
{
var previous = Id;
if (_command is Command cmd)
{
cmd.Id = value;
}
else
{
base.Id = value;
}
if (previous != Id)
{
OnPropertyChanged(nameof(Id));
}
}
}
public override IconInfo Icon
{
get => (_command as Command)?.Icon ?? base.Icon;
set
{
if (_command is Command cmd)
{
cmd.Icon = value;
}
else
{
base.Icon = value;
}
}
}
public ConfirmableCommand()
{
// Allow init-only construction
}
[SetsRequiredMembers]
public ConfirmableCommand(IInvokableCommand command, string confirmationTitle, string confirmationMessage, Func<bool>? isConfirmationRequired = null)
{
ArgumentNullException.ThrowIfNull(command);
ArgumentException.ThrowIfNullOrWhiteSpace(confirmationMessage);
ArgumentNullException.ThrowIfNull(confirmationMessage);
IsConfirmationRequired = isConfirmationRequired;
ConfirmationTitle = confirmationTitle;
ConfirmationMessage = confirmationMessage;
Command = command;
}
private void InnerCommand_PropChanged(object sender, IPropChangedEventArgs args)
{
var property = args.PropertyName;
if (string.IsNullOrEmpty(property) || property == nameof(Name))
{
OnPropertyChanged(nameof(Name));
}
if (string.IsNullOrEmpty(property) || property == nameof(Id))
{
OnPropertyChanged(nameof(Id));
}
if (string.IsNullOrEmpty(property) || property == nameof(Icon))
{
OnPropertyChanged(nameof(Icon));
}
}
public override ICommandResult Invoke()
{
var showConfirmationDialog = IsConfirmationRequired?.Invoke() ?? true;
if (showConfirmationDialog)
{
return CommandResult.Confirm(new ConfirmationArgs
{
Title = ConfirmationTitle,
Description = ConfirmationMessage,
PrimaryCommand = Command,
IsPrimaryCommandCritical = true,
});
}
else
{
return Command.Invoke(this) ?? CommandResult.Dismiss();
}
}
}

View File

@@ -2,6 +2,8 @@
// 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.Globalization;
using System.Text;
using Microsoft.CommandPalette.Extensions.Toolkit.Properties;
namespace Microsoft.CommandPalette.Extensions.Toolkit;
@@ -10,6 +12,8 @@ public partial class CopyPathCommand : InvokableCommand
{
internal static IconInfo CopyPath { get; } = new("\uE8c8"); // Copy
private static readonly CompositeFormat CopyFailedFormat = CompositeFormat.Parse(Resources.copy_failed);
private readonly string _path;
public CommandResult Result { get; set; } = CommandResult.ShowToast(Resources.CopyPathTextCommand_Result);
@@ -27,8 +31,15 @@ public partial class CopyPathCommand : InvokableCommand
{
ClipboardHelper.SetText(_path);
}
catch
catch (Exception ex)
{
ExtensionHost.LogMessage(new LogMessage("Copy failed: " + ex.Message) { State = MessageState.Error });
return CommandResult.ShowToast(
new ToastArgs
{
Message = string.Format(CultureInfo.CurrentCulture, CopyFailedFormat, ex.Message),
Result = CommandResult.KeepOpen(),
});
}
return Result;

View File

@@ -4,6 +4,7 @@
using System.ComponentModel;
using System.Diagnostics;
using Microsoft.CommandPalette.Extensions.Toolkit.Properties;
namespace Microsoft.CommandPalette.Extensions.Toolkit;
@@ -18,7 +19,7 @@ public partial class OpenFileCommand : InvokableCommand
public OpenFileCommand(string fullPath)
{
this._fullPath = fullPath;
this.Name = "Open";
this.Name = Resources.OpenFileCommand_Name;
this.Icon = OpenFile;
}

View File

@@ -0,0 +1,43 @@
// 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.ComponentModel;
using System.Diagnostics;
using Microsoft.CommandPalette.Extensions.Toolkit.Properties;
namespace Microsoft.CommandPalette.Extensions.Toolkit;
public partial class OpenInConsoleCommand : InvokableCommand
{
internal static IconInfo OpenInConsoleIcon { get; } = new("\uE756"); // "CommandPrompt"
private readonly string _path;
public OpenInConsoleCommand(string fullPath)
{
this._path = fullPath;
this.Name = Resources.OpenInConsoleCommand_Name;
this.Icon = OpenInConsoleIcon;
}
public override CommandResult Invoke()
{
using (var process = new Process())
{
process.StartInfo.WorkingDirectory = Path.GetDirectoryName(_path);
process.StartInfo.FileName = "cmd.exe";
try
{
process.Start();
}
catch (Win32Exception ex)
{
ExtensionHost.LogMessage(new LogMessage($"Unable to open '{_path}'\n{ex.Message}\n{ex.StackTrace}") { State = MessageState.Error });
}
}
return CommandResult.Dismiss();
}
}

View File

@@ -0,0 +1,63 @@
// 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.Runtime.InteropServices;
using ManagedCsWin32;
using Microsoft.CommandPalette.Extensions.Toolkit.Properties;
using Windows.Win32.UI.WindowsAndMessaging;
namespace Microsoft.CommandPalette.Extensions.Toolkit;
public partial class OpenPropertiesCommand : InvokableCommand
{
internal static IconInfo OpenPropertiesIcon { get; } = new("\uE90F");
private readonly string _path;
private static unsafe bool ShowFileProperties(string filename)
{
var propertiesPtr = Marshal.StringToHGlobalUni("properties");
var filenamePtr = Marshal.StringToHGlobalUni(filename);
try
{
var info = new Shell32.SHELLEXECUTEINFOW
{
CbSize = (uint)sizeof(Shell32.SHELLEXECUTEINFOW),
LpVerb = propertiesPtr,
LpFile = filenamePtr,
Show = (int)SHOW_WINDOW_CMD.SW_SHOW,
FMask = global::Windows.Win32.PInvoke.SEE_MASK_INVOKEIDLIST,
};
return Shell32.ShellExecuteEx(ref info);
}
finally
{
Marshal.FreeHGlobal(filenamePtr);
Marshal.FreeHGlobal(propertiesPtr);
}
}
public OpenPropertiesCommand(string fullPath)
{
this._path = fullPath;
this.Name = Resources.OpenPropertiesCommand_Name;
this.Icon = OpenPropertiesIcon;
}
public override CommandResult Invoke()
{
try
{
ShowFileProperties(_path);
}
catch (Exception ex)
{
ExtensionHost.LogMessage(new LogMessage($"Error showing file properties '{_path}'\n{ex.Message}\n{ex.StackTrace}") { State = MessageState.Error });
}
return CommandResult.Dismiss();
}
}

View File

@@ -0,0 +1,57 @@
// 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.Runtime.InteropServices;
using ManagedCsWin32;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.CommandPalette.Extensions.Toolkit.Properties;
using Windows.Win32.UI.WindowsAndMessaging;
namespace Microsoft.CmdPal.Core.Common.Commands;
public partial class OpenWithCommand : InvokableCommand
{
internal static IconInfo OpenWithIcon { get; } = new("\uE7AC");
private readonly string _path;
private static unsafe bool OpenWith(string filename)
{
var filenamePtr = Marshal.StringToHGlobalUni(filename);
var verbPtr = Marshal.StringToHGlobalUni("openas");
try
{
var info = new Shell32.SHELLEXECUTEINFOW
{
CbSize = (uint)sizeof(Shell32.SHELLEXECUTEINFOW),
LpVerb = verbPtr,
LpFile = filenamePtr,
Show = (int)SHOW_WINDOW_CMD.SW_SHOWNORMAL,
FMask = global::Windows.Win32.PInvoke.SEE_MASK_INVOKEIDLIST,
};
return Shell32.ShellExecuteEx(ref info);
}
finally
{
Marshal.FreeHGlobal(filenamePtr);
Marshal.FreeHGlobal(verbPtr);
}
}
public OpenWithCommand(string fullPath)
{
this._path = fullPath;
this.Name = Resources.OpenWithCommand_Name;
this.Icon = OpenWithIcon;
}
public override CommandResult Invoke()
{
OpenWith(_path);
return CommandResult.GoHome();
}
}

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 System;
using System.Runtime.InteropServices;
namespace ManagedCsWin32;
internal static partial class Shell32
{
[LibraryImport("SHELL32.dll", EntryPoint = "ShellExecuteExW", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool ShellExecuteEx(ref SHELLEXECUTEINFOW lpExecInfo);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SHELLEXECUTEINFOW
{
public uint CbSize;
public uint FMask;
public IntPtr Hwnd;
public IntPtr LpVerb;
public IntPtr LpFile;
public IntPtr LpParameters;
public IntPtr LpDirectory;
public int Show;
public IntPtr HInstApp;
public IntPtr LpIDList;
public IntPtr LpClass;
public IntPtr HkeyClass;
public uint DwHotKey;
public IntPtr HIconOrMonitor;
public IntPtr Process;
}
}

View File

@@ -5,4 +5,7 @@ GetPackageFamilyNameFromToken
CoRevertToSelf
SHGetKnownFolderPath
KNOWN_FOLDER_FLAG
GetCurrentPackageId
GetCurrentPackageId
SHOW_WINDOW_CMD
SEE_MASK_INVOKEIDLIST

View File

@@ -69,6 +69,15 @@ namespace Microsoft.CommandPalette.Extensions.Toolkit.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Copy failed ({0}). Please try again..
/// </summary>
internal static string copy_failed {
get {
return ResourceManager.GetString("copy_failed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Copy path.
/// </summary>
@@ -105,6 +114,33 @@ namespace Microsoft.CommandPalette.Extensions.Toolkit.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Open.
/// </summary>
internal static string OpenFileCommand_Name {
get {
return ResourceManager.GetString("OpenFileCommand_Name", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open path in console.
/// </summary>
internal static string OpenInConsoleCommand_Name {
get {
return ResourceManager.GetString("OpenInConsoleCommand_Name", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Properties.
/// </summary>
internal static string OpenPropertiesCommand_Name {
get {
return ResourceManager.GetString("OpenPropertiesCommand_Name", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open.
/// </summary>
@@ -114,6 +150,24 @@ namespace Microsoft.CommandPalette.Extensions.Toolkit.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Open with.
/// </summary>
internal static string OpenWithCommand_Name {
get {
return ResourceManager.GetString("OpenWithCommand_Name", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open.
/// </summary>
internal static string Page_Name {
get {
return ResourceManager.GetString("Page_Name", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Settings.
/// </summary>

View File

@@ -141,4 +141,20 @@
<data name="ShowFileInFolderCommand_ShowInFolder" xml:space="preserve">
<value>Show in folder</value>
</data>
<data name="OpenInConsoleCommand_Name" xml:space="preserve">
<value>Open path in console</value>
</data>
<data name="OpenPropertiesCommand_Name" xml:space="preserve">
<value>Properties</value>
</data>
<data name="OpenFileCommand_Name" xml:space="preserve">
<value>Open</value>
</data>
<data name="OpenWithCommand_Name" xml:space="preserve">
<value>Open with</value>
</data>
<data name="copy_failed" xml:space="preserve">
<value>Copy failed ({0}). Please try again.</value>
<comment>{0} is the error message</comment>
</data>
</root>