diff --git a/.github/actions/spell-check/allow/code.txt b/.github/actions/spell-check/allow/code.txt index d312ae7d54..2ef0425846 100644 --- a/.github/actions/spell-check/allow/code.txt +++ b/.github/actions/spell-check/allow/code.txt @@ -288,3 +288,6 @@ CACHEWRITE MRUCMPPROC MRUINFO REGSTR + +# Misc Win32 APIs and PInvokes +INVOKEIDLIST \ No newline at end of file diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/ExecuteActionCommand.cs b/src/modules/cmdpal/Microsoft.CmdPal.Common/Commands/ExecuteActionCommand.cs similarity index 89% rename from src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/ExecuteActionCommand.cs rename to src/modules/cmdpal/Microsoft.CmdPal.Common/Commands/ExecuteActionCommand.cs index 2a3c895e9b..bf523d5792 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/ExecuteActionCommand.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/Commands/ExecuteActionCommand.cs @@ -9,11 +9,11 @@ using Windows.AI.Actions.Hosting; namespace Microsoft.CmdPal.Ext.Indexer.Commands; -internal sealed partial class ExecuteActionCommand : InvokableCommand +public sealed partial class ExecuteActionCommand : InvokableCommand { private readonly ActionInstance actionInstance; - internal ExecuteActionCommand(ActionInstance actionInstance) + public ExecuteActionCommand(ActionInstance actionInstance) { this.actionInstance = actionInstance; this.Name = actionInstance.DisplayInfo.Description; diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/OpenInConsoleCommand.cs b/src/modules/cmdpal/Microsoft.CmdPal.Common/Commands/OpenInConsoleCommand.cs similarity index 61% rename from src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/OpenInConsoleCommand.cs rename to src/modules/cmdpal/Microsoft.CmdPal.Common/Commands/OpenInConsoleCommand.cs index cd9c5ce94b..37b82422d0 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/OpenInConsoleCommand.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/Commands/OpenInConsoleCommand.cs @@ -6,28 +6,29 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; using ManagedCommon; -using Microsoft.CmdPal.Ext.Indexer.Data; -using Microsoft.CmdPal.Ext.Indexer.Properties; +using Microsoft.CmdPal.Common.Properties; using Microsoft.CommandPalette.Extensions.Toolkit; -namespace Microsoft.CmdPal.Ext.Indexer.Commands; +namespace Microsoft.CmdPal.Common.Commands; -internal sealed partial class OpenInConsoleCommand : InvokableCommand +public partial class OpenInConsoleCommand : InvokableCommand { - private readonly IndexerItem _item; + internal static IconInfo OpenInConsoleIcon { get; } = new("\uE756"); - internal OpenInConsoleCommand(IndexerItem item) + private readonly string _path; + + public OpenInConsoleCommand(string fullPath) { - this._item = item; + this._path = fullPath; this.Name = Resources.Indexer_Command_OpenPathInConsole; - this.Icon = new IconInfo("\uE756"); + this.Icon = OpenInConsoleIcon; } public override CommandResult Invoke() { using (var process = new Process()) { - process.StartInfo.WorkingDirectory = Path.GetDirectoryName(_item.FullPath); + process.StartInfo.WorkingDirectory = Path.GetDirectoryName(_path); process.StartInfo.FileName = "cmd.exe"; try @@ -36,10 +37,10 @@ internal sealed partial class OpenInConsoleCommand : InvokableCommand } catch (Win32Exception ex) { - Logger.LogError($"Unable to open {_item.FullPath}", ex); + Logger.LogError($"Unable to open '{_path}'", ex); } } - return CommandResult.GoHome(); + return CommandResult.Dismiss(); } } diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/OpenPropertiesCommand.cs b/src/modules/cmdpal/Microsoft.CmdPal.Common/Commands/OpenPropertiesCommand.cs similarity index 70% rename from src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/OpenPropertiesCommand.cs rename to src/modules/cmdpal/Microsoft.CmdPal.Common/Commands/OpenPropertiesCommand.cs index d07bbdca80..b4833dc913 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/OpenPropertiesCommand.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/Commands/OpenPropertiesCommand.cs @@ -6,17 +6,17 @@ using System; using System.Runtime.InteropServices; using ManagedCommon; using ManagedCsWin32; -using Microsoft.CmdPal.Ext.Indexer.Data; -using Microsoft.CmdPal.Ext.Indexer.Indexer.Utils; -using Microsoft.CmdPal.Ext.Indexer.Properties; +using Microsoft.CmdPal.Common.Properties; using Microsoft.CommandPalette.Extensions.Toolkit; using Windows.Win32.UI.WindowsAndMessaging; -namespace Microsoft.CmdPal.Ext.Indexer.Commands; +namespace Microsoft.CmdPal.Common.Commands; -internal sealed partial class OpenPropertiesCommand : InvokableCommand +public partial class OpenPropertiesCommand : InvokableCommand { - private readonly IndexerItem _item; + internal static IconInfo OpenPropertiesIcon { get; } = new("\uE90F"); + + private readonly string _path; private static unsafe bool ShowFileProperties(string filename) { @@ -31,7 +31,7 @@ internal sealed partial class OpenPropertiesCommand : InvokableCommand LpVerb = propertiesPtr, LpFile = filenamePtr, Show = (int)SHOW_WINDOW_CMD.SW_SHOW, - FMask = NativeHelpers.SEEMASKINVOKEIDLIST, + FMask = global::Windows.Win32.PInvoke.SEE_MASK_INVOKEIDLIST, }; return Shell32.ShellExecuteEx(ref info); @@ -43,24 +43,24 @@ internal sealed partial class OpenPropertiesCommand : InvokableCommand } } - internal OpenPropertiesCommand(IndexerItem item) + public OpenPropertiesCommand(string fullPath) { - this._item = item; + this._path = fullPath; this.Name = Resources.Indexer_Command_OpenProperties; - this.Icon = new IconInfo("\uE90F"); + this.Icon = OpenPropertiesIcon; } public override CommandResult Invoke() { try { - ShowFileProperties(_item.FullPath); + ShowFileProperties(_path); } catch (Exception ex) { Logger.LogError("Error showing file properties: ", ex); } - return CommandResult.GoHome(); + return CommandResult.Dismiss(); } } diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/OpenWithCommand.cs b/src/modules/cmdpal/Microsoft.CmdPal.Common/Commands/OpenWithCommand.cs similarity index 70% rename from src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/OpenWithCommand.cs rename to src/modules/cmdpal/Microsoft.CmdPal.Common/Commands/OpenWithCommand.cs index 2c1875d3d7..33bd83a20c 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/OpenWithCommand.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/Commands/OpenWithCommand.cs @@ -4,17 +4,17 @@ using System.Runtime.InteropServices; using ManagedCsWin32; -using Microsoft.CmdPal.Ext.Indexer.Data; -using Microsoft.CmdPal.Ext.Indexer.Indexer.Utils; -using Microsoft.CmdPal.Ext.Indexer.Properties; +using Microsoft.CmdPal.Common.Properties; using Microsoft.CommandPalette.Extensions.Toolkit; using Windows.Win32.UI.WindowsAndMessaging; -namespace Microsoft.CmdPal.Ext.Indexer.Commands; +namespace Microsoft.CmdPal.Common.Commands; -internal sealed partial class OpenWithCommand : InvokableCommand +public partial class OpenWithCommand : InvokableCommand { - private readonly IndexerItem _item; + internal static IconInfo OpenWithIcon { get; } = new("\uE7AC"); + + private readonly string _path; private static unsafe bool OpenWith(string filename) { @@ -29,7 +29,7 @@ internal sealed partial class OpenWithCommand : InvokableCommand LpVerb = verbPtr, LpFile = filenamePtr, Show = (int)SHOW_WINDOW_CMD.SW_SHOWNORMAL, - FMask = NativeHelpers.SEEMASKINVOKEIDLIST, + FMask = global::Windows.Win32.PInvoke.SEE_MASK_INVOKEIDLIST, }; return Shell32.ShellExecuteEx(ref info); @@ -41,16 +41,16 @@ internal sealed partial class OpenWithCommand : InvokableCommand } } - internal OpenWithCommand(IndexerItem item) + public OpenWithCommand(string fullPath) { - this._item = item; + this._path = fullPath; this.Name = Resources.Indexer_Command_OpenWith; - this.Icon = new IconInfo("\uE7AC"); + this.Icon = OpenWithIcon; } public override CommandResult Invoke() { - OpenWith(_item.FullPath); + OpenWith(_path); return CommandResult.GoHome(); } diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Common/Microsoft.CmdPal.Common.csproj b/src/modules/cmdpal/Microsoft.CmdPal.Common/Microsoft.CmdPal.Common.csproj index 0112da1b0b..27509d0e5b 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.Common/Microsoft.CmdPal.Common.csproj +++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/Microsoft.CmdPal.Common.csproj @@ -28,7 +28,24 @@ + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Common/NativeMethods.txt b/src/modules/cmdpal/Microsoft.CmdPal.Common/NativeMethods.txt index 996bbd7153..61e89b68c4 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.Common/NativeMethods.txt +++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/NativeMethods.txt @@ -9,3 +9,7 @@ GetWindowRect GetMonitorInfo SetWindowPos MonitorFromWindow + +SHOW_WINDOW_CMD +ShellExecuteEx +SEE_MASK_INVOKEIDLIST \ No newline at end of file diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.Designer.cs b/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..c2f81dd683 --- /dev/null +++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.Designer.cs @@ -0,0 +1,99 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.CmdPal.Common.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.CmdPal.Common.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Open path in console. + /// + internal static string Indexer_Command_OpenPathInConsole { + get { + return ResourceManager.GetString("Indexer_Command_OpenPathInConsole", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Properties. + /// + internal static string Indexer_Command_OpenProperties { + get { + return ResourceManager.GetString("Indexer_Command_OpenProperties", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Open with. + /// + internal static string Indexer_Command_OpenWith { + get { + return ResourceManager.GetString("Indexer_Command_OpenWith", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Show in folder. + /// + internal static string Indexer_Command_ShowInFolder { + get { + return ResourceManager.GetString("Indexer_Command_ShowInFolder", resourceCulture); + } + } + } +} diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.resx b/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.resx new file mode 100644 index 0000000000..14e62fb4c2 --- /dev/null +++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Open path in console + + + Properties + + + Open with + + + Show in folder + + \ No newline at end of file diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Programs/UWPApplication.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Programs/UWPApplication.cs index c5270b355c..5c689545bd 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Programs/UWPApplication.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Programs/UWPApplication.cs @@ -10,7 +10,6 @@ using System.Xml; using ManagedCommon; using Microsoft.CmdPal.Ext.Apps.Commands; using Microsoft.CmdPal.Ext.Apps.Properties; -using Microsoft.CmdPal.Ext.Apps.State; using Microsoft.CmdPal.Ext.Apps.Utils; using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions.Toolkit; @@ -96,7 +95,7 @@ public class UWPApplication : IProgram commands.Add( new CommandContextItem( - new CopyPathCommand(Location)) + new Commands.CopyPathCommand(Location)) { RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.C), }); diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Programs/Win32Program.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Programs/Win32Program.cs index d8bebcd9a4..74819d87c7 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Programs/Win32Program.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Programs/Win32Program.cs @@ -5,21 +5,15 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.ComponentModel.Design; -using System.Diagnostics; -using System.Globalization; using System.IO; using System.IO.Abstractions; using System.Linq; -using System.Reflection; using System.Security; using System.Text.RegularExpressions; using System.Threading.Tasks; -using System.Windows.Input; using ManagedCommon; using Microsoft.CmdPal.Ext.Apps.Commands; using Microsoft.CmdPal.Ext.Apps.Properties; -using Microsoft.CmdPal.Ext.Apps.State; using Microsoft.CmdPal.Ext.Apps.Utils; using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions.Toolkit; @@ -190,7 +184,7 @@ public class Win32Program : IProgram public List GetCommands() { - List commands = new List(); + List commands = []; if (AppType != ApplicationType.InternetShortcutApplication && AppType != ApplicationType.Folder && AppType != ApplicationType.GenericFile) { @@ -208,7 +202,7 @@ public class Win32Program : IProgram } commands.Add(new CommandContextItem( - new CopyPathCommand(FullPath)) + new Commands.CopyPathCommand(FullPath)) { RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.C), }); diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/CopyPathCommand.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/CopyPathCommand.cs deleted file mode 100644 index 77338e5d45..0000000000 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/CopyPathCommand.cs +++ /dev/null @@ -1,34 +0,0 @@ -// 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.Ext.Indexer.Data; -using Microsoft.CmdPal.Ext.Indexer.Properties; -using Microsoft.CommandPalette.Extensions.Toolkit; - -namespace Microsoft.CmdPal.Ext.Indexer.Commands; - -internal sealed partial class CopyPathCommand : InvokableCommand -{ - private readonly IndexerItem _item; - - internal CopyPathCommand(IndexerItem item) - { - this._item = item; - this.Name = Resources.Indexer_Command_CopyPath; - this.Icon = new IconInfo("\uE8c8"); - } - - public override CommandResult Invoke() - { - try - { - ClipboardHelper.SetText(_item.FullPath); - } - catch - { - } - - return CommandResult.KeepOpen(); - } -} diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/OpenFileCommand.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/OpenFileCommand.cs deleted file mode 100644 index 9d48c64376..0000000000 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/OpenFileCommand.cs +++ /dev/null @@ -1,44 +0,0 @@ -// 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 ManagedCommon; -using Microsoft.CmdPal.Ext.Indexer.Data; -using Microsoft.CmdPal.Ext.Indexer.Properties; -using Microsoft.CommandPalette.Extensions.Toolkit; - -namespace Microsoft.CmdPal.Ext.Indexer.Commands; - -internal sealed partial class OpenFileCommand : InvokableCommand -{ - private readonly IndexerItem _item; - - internal OpenFileCommand(IndexerItem item) - { - this._item = item; - this.Name = Resources.Indexer_Command_OpenFile; - this.Icon = Icons.OpenFileIcon; - } - - public override CommandResult Invoke() - { - using (var process = new Process()) - { - process.StartInfo.FileName = _item.FullPath; - process.StartInfo.UseShellExecute = true; - - try - { - process.Start(); - } - catch (Win32Exception ex) - { - Logger.LogError($"Unable to open {_item.FullPath}", ex); - } - } - - return CommandResult.GoHome(); - } -} diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Data/IndexerItem.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Data/IndexerItem.cs index 5b65cc9ef8..00222149f9 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Data/IndexerItem.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Data/IndexerItem.cs @@ -12,6 +12,16 @@ internal sealed class IndexerItem internal string FileName { get; init; } + internal IndexerItem() + { + } + + internal IndexerItem(string fullPath) + { + FullPath = fullPath; + FileName = Path.GetFileName(fullPath); + } + internal bool IsDirectory() { if (!Path.Exists(FullPath)) diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Data/IndexerListItem.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Data/IndexerListItem.cs index cd56f1c624..6cf0165e57 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Data/IndexerListItem.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Data/IndexerListItem.cs @@ -3,10 +3,11 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using Microsoft.CmdPal.Ext.Indexer.Commands; +using System.IO; +using System.Linq; +using Microsoft.CmdPal.Common.Commands; using Microsoft.CmdPal.Ext.Indexer.Pages; using Microsoft.CmdPal.Ext.Indexer.Properties; -using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions.Toolkit; using Windows.Foundation.Metadata; @@ -28,51 +29,79 @@ internal sealed partial class IndexerListItem : ListItem public IndexerListItem( IndexerItem indexerItem, IncludeBrowseCommand browseByDefault = IncludeBrowseCommand.Include) - : base(new OpenFileCommand(indexerItem)) + : base() { FilePath = indexerItem.FullPath; Title = indexerItem.FileName; Subtitle = indexerItem.FullPath; - List context = []; - if (indexerItem.IsDirectory()) + + var commands = FileCommands(indexerItem.FullPath, browseByDefault); + if (commands.Any()) { - var directoryPage = new DirectoryPage(indexerItem.FullPath); + Command = commands.First().Command; + MoreCommands = commands.Skip(1).ToArray(); + } + } + + public static IEnumerable FileCommands(string fullPath) + { + return FileCommands(fullPath, IncludeBrowseCommand.Include); + } + + internal static IEnumerable FileCommands( + string fullPath, + IncludeBrowseCommand browseByDefault = IncludeBrowseCommand.Include) + { + List commands = []; + if (!Path.Exists(fullPath)) + { + return commands; + } + + // detect whether it is a directory or file + var attr = File.GetAttributes(fullPath); + var isDir = (attr & FileAttributes.Directory) == FileAttributes.Directory; + + var openCommand = new OpenFileCommand(fullPath) { Name = Resources.Indexer_Command_OpenFile }; + if (isDir) + { + var directoryPage = new DirectoryPage(fullPath); if (browseByDefault == IncludeBrowseCommand.AsDefault) { - // Swap the open file command into the context menu - context.Add(new CommandContextItem(Command)); - Command = directoryPage; + // AsDefault: browse dir first, then open in explorer + commands.Add(new CommandContextItem(directoryPage)); + commands.Add(new CommandContextItem(openCommand)); } else if (browseByDefault == IncludeBrowseCommand.Include) { - context.Add(new CommandContextItem(directoryPage)); + // AsDefault: open in explorer first, then browse + commands.Add(new CommandContextItem(openCommand)); + commands.Add(new CommandContextItem(directoryPage)); + } + else if (browseByDefault == IncludeBrowseCommand.Exclude) + { + // AsDefault: Just open in explorer + commands.Add(new CommandContextItem(openCommand)); } } - IContextItem[] moreCommands = [ - ..context, - new CommandContextItem(new OpenWithCommand(indexerItem))]; + commands.Add(new CommandContextItem(new OpenWithCommand(fullPath))); + commands.Add(new CommandContextItem(new ShowFileInFolderCommand(fullPath) { Name = Resources.Indexer_Command_ShowInFolder })); + commands.Add(new CommandContextItem(new CopyPathCommand(fullPath) { Name = Resources.Indexer_Command_CopyPath })); + commands.Add(new CommandContextItem(new OpenInConsoleCommand(fullPath))); + commands.Add(new CommandContextItem(new OpenPropertiesCommand(fullPath))); if (IsActionsFeatureEnabled && ApiInformation.IsApiContractPresent("Windows.AI.Actions.ActionsContract", 4)) { - var actionsListContextItem = new ActionsListContextItem(indexerItem.FullPath); + var actionsListContextItem = new ActionsListContextItem(fullPath); if (actionsListContextItem.AnyActions()) { - moreCommands = [ - .. moreCommands, - actionsListContextItem - ]; + commands.Add(actionsListContextItem); } } - MoreCommands = [ - .. moreCommands, - new CommandContextItem(new ShowFileInFolderCommand(indexerItem.FullPath) { Name = Resources.Indexer_Command_ShowInFolder }), - new CommandContextItem(new CopyPathCommand(indexerItem)), - new CommandContextItem(new OpenInConsoleCommand(indexerItem)), - new CommandContextItem(new OpenPropertiesCommand(indexerItem)), - ]; + return commands; } } diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/FallbackOpenFileItem.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/FallbackOpenFileItem.cs index 88c4f77cc2..7da8702f1e 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/FallbackOpenFileItem.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/FallbackOpenFileItem.cs @@ -60,7 +60,7 @@ internal sealed partial class FallbackOpenFileItem : FallbackCommandItem, System if (Path.Exists(query)) { // Exit 1: The query is a direct path to a file. Great! Return it. - var item = new IndexerItem() { FullPath = query, FileName = Path.GetFileName(query) }; + var item = new IndexerItem(fullPath: query); var listItemForUs = new IndexerListItem(item, IncludeBrowseCommand.AsDefault); Command = listItemForUs.Command; MoreCommands = listItemForUs.MoreCommands; diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Microsoft.CmdPal.Ext.Indexer.csproj b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Microsoft.CmdPal.Ext.Indexer.csproj index af8fcff41a..5bf4255308 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Microsoft.CmdPal.Ext.Indexer.csproj +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Microsoft.CmdPal.Ext.Indexer.csproj @@ -10,14 +10,15 @@ - - all - runtime; build; native; contentfiles; analyzers - - - + + all + runtime; build; native; contentfiles; analyzers + + + + - + diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Pages/ExploreListItem.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Pages/ExploreListItem.cs index 501e2b96f3..b440644dd7 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Pages/ExploreListItem.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Pages/ExploreListItem.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using Microsoft.CmdPal.Ext.Indexer.Commands; +using Microsoft.CmdPal.Common.Commands; using Microsoft.CmdPal.Ext.Indexer.Data; using Microsoft.CmdPal.Ext.Indexer.Properties; using Microsoft.CommandPalette.Extensions.Toolkit; @@ -41,16 +41,16 @@ internal sealed partial class ExploreListItem : ListItem } else { - Command = new OpenFileCommand(indexerItem); + Command = new OpenFileCommand(indexerItem.FullPath); } MoreCommands = [ ..context, - new CommandContextItem(new OpenWithCommand(indexerItem)), + new CommandContextItem(new OpenWithCommand(indexerItem.FullPath)), new CommandContextItem(new ShowFileInFolderCommand(indexerItem.FullPath) { Name = Resources.Indexer_Command_ShowInFolder }), - new CommandContextItem(new CopyPathCommand(indexerItem)), - new CommandContextItem(new OpenInConsoleCommand(indexerItem)), - new CommandContextItem(new OpenPropertiesCommand(indexerItem)), + new CommandContextItem(new CopyPathCommand(indexerItem.FullPath)), + new CommandContextItem(new OpenInConsoleCommand(indexerItem.FullPath)), + new CommandContextItem(new OpenPropertiesCommand(indexerItem.FullPath)), ]; } } diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/Microsoft.CmdPal.Ext.Shell.csproj b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/Microsoft.CmdPal.Ext.Shell.csproj index c1792064f9..b1454d826e 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/Microsoft.CmdPal.Ext.Shell.csproj +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/Microsoft.CmdPal.Ext.Shell.csproj @@ -13,6 +13,7 @@ + diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/Pages/RunExeItem.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/Pages/RunExeItem.cs index 679607e312..ea98f2fe47 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/Pages/RunExeItem.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/Pages/RunExeItem.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions.Toolkit; using Windows.Storage.Streams; +using Windows.System; namespace Microsoft.CmdPal.Ext.Shell.Pages; @@ -54,13 +55,13 @@ internal sealed partial class RunExeItem : ListItem { Name = Properties.Resources.cmd_run_as_administrator, Icon = Icons.AdminIcon, - }), + }) { RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.Enter) }, new CommandContextItem( new AnonymousCommand(RunAsOther) { Name = Properties.Resources.cmd_run_as_user, Icon = Icons.UserIcon, - }), + }) { RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.U) }, ]; } diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/Pages/ShellListPage.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/Pages/ShellListPage.cs index c3b5a66bf2..8ecfe091c1 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/Pages/ShellListPage.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/Pages/ShellListPage.cs @@ -26,7 +26,7 @@ internal sealed partial class ShellListPage : DynamicListPage, IDisposable private readonly IRunHistoryService _historyService; - private RunExeItem? _exeItem; + private ListItem? _exeItem; private List _pathItems = []; private ListItem? _uriItem; @@ -319,20 +319,19 @@ internal sealed partial class ShellListPage : DynamicListPage, IDisposable .ToArray(); } - internal static RunExeItem CreateExeItem(string exe, string args, string fullExePath, Action? addToHistory) + internal static ListItem CreateExeItem(string exe, string args, string fullExePath, Action? addToHistory) { // PathToListItem will return a RunExeItem if it can find a executable. // It will ALSO add the file search commands to the RunExeItem. - return PathToListItem(fullExePath, exe, args, addToHistory) as RunExeItem ?? - new RunExeItem(exe, args, fullExePath, addToHistory); + return PathToListItem(fullExePath, exe, args, addToHistory); } private void CreateAndAddExeItems(string exe, string args, string fullExePath) { // If we already have an exe item, and the exe is the same, we can just update it - if (_exeItem != null && _exeItem.FullExePath.Equals(fullExePath, StringComparison.OrdinalIgnoreCase)) + if (_exeItem is RunExeItem exeItem && exeItem.FullExePath.Equals(fullExePath, StringComparison.OrdinalIgnoreCase)) { - _exeItem.UpdateArgs(args); + exeItem.UpdateArgs(args); } else { @@ -345,7 +344,8 @@ internal sealed partial class ShellListPage : DynamicListPage, IDisposable // Is this path an executable? // check all the extensions in PATHEXT var extensions = Environment.GetEnvironmentVariable("PATHEXT")?.Split(';') ?? Array.Empty(); - return extensions.Any(ext => string.Equals(Path.GetExtension(path), ext, StringComparison.OrdinalIgnoreCase)); + var extension = Path.GetExtension(path); + return string.IsNullOrEmpty(extension) || extensions.Any(ext => string.Equals(extension, ext, StringComparison.OrdinalIgnoreCase)); } private async Task CreatePathItemsAsync(string searchPath, string originalPath, CancellationToken cancellationToken) diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/PathListItem.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/PathListItem.cs index 0ecec3cb2d..2e1dd38349 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/PathListItem.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Shell/PathListItem.cs @@ -4,8 +4,10 @@ using System; using System.IO; +using Microsoft.CmdPal.Common.Commands; using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions.Toolkit; +using Windows.System; namespace Microsoft.CmdPal.Ext.Shell; @@ -58,18 +60,15 @@ internal sealed partial class PathListItem : ListItem } TextToSuggest = suggestion; - MoreCommands = [ - new CommandContextItem(new CopyTextCommand(path) { Name = Properties.Resources.copy_path_command_name }) { } - ]; - // TODO: Follow-up during 0.4. Add the indexer commands here. - // MoreCommands = [ - // new CommandContextItem(new OpenWithCommand(indexerItem)), - // new CommandContextItem(new ShowFileInFolderCommand(indexerItem.FullPath) { Name = Resources.Indexer_Command_ShowInFolder }), - // new CommandContextItem(new CopyPathCommand(indexerItem)), - // new CommandContextItem(new OpenInConsoleCommand(indexerItem)), - // new CommandContextItem(new OpenPropertiesCommand(indexerItem)), - // ]; + MoreCommands = [ + new CommandContextItem(new OpenWithCommand(path)), + new CommandContextItem(new ShowFileInFolderCommand(path)) { RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.E) }, + new CommandContextItem(new CopyPathCommand(path) { Name = Properties.Resources.copy_path_command_name }) { RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.C) }, + new CommandContextItem(new OpenInConsoleCommand(path)) { RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.R) }, + new CommandContextItem(new OpenPropertiesCommand(path)), + ]; + _icon = new Lazy(() => { var iconStream = ThumbnailHelper.GetThumbnail(path).Result; diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/CopyPathCommand.cs b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/CopyPathCommand.cs new file mode 100644 index 0000000000..6ace309bd1 --- /dev/null +++ b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/CopyPathCommand.cs @@ -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.CommandPalette.Extensions.Toolkit.Properties; + +namespace Microsoft.CommandPalette.Extensions.Toolkit; + +public partial class CopyPathCommand : InvokableCommand +{ + internal static IconInfo CopyPath { get; } = new("\uE8c8"); // Copy + + private readonly string _path; + + public CommandResult Result { get; set; } = CommandResult.ShowToast(Resources.CopyPathTextCommand_Result); + + public CopyPathCommand(string fullPath) + { + this._path = fullPath; + this.Name = Resources.CopyPathTextCommand_Name; + this.Icon = CopyPath; + } + + public override CommandResult Invoke() + { + try + { + ClipboardHelper.SetText(_path); + } + catch + { + } + + return Result; + } +} diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/CopyTextCommand.cs b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/CopyTextCommand.cs similarity index 100% rename from src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/CopyTextCommand.cs rename to src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/CopyTextCommand.cs diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/NoOpCommand.cs b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/NoOpCommand.cs similarity index 100% rename from src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/NoOpCommand.cs rename to src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/NoOpCommand.cs diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/OpenFileCommand.cs b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/OpenFileCommand.cs new file mode 100644 index 0000000000..fff7950f3d --- /dev/null +++ b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/OpenFileCommand.cs @@ -0,0 +1,44 @@ +// 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; + +namespace Microsoft.CommandPalette.Extensions.Toolkit; + +public partial class OpenFileCommand : InvokableCommand +{ + internal static IconInfo OpenFile { get; } = new("\uE8E5"); // OpenFile + + private readonly string _fullPath; + + public CommandResult Result { get; set; } = CommandResult.Dismiss(); + + public OpenFileCommand(string fullPath) + { + this._fullPath = fullPath; + this.Name = "Open"; + this.Icon = OpenFile; + } + + public override CommandResult Invoke() + { + using (var process = new Process()) + { + process.StartInfo.FileName = _fullPath; + process.StartInfo.UseShellExecute = true; + + try + { + process.Start(); + } + catch (Win32Exception ex) + { + ExtensionHost.LogMessage($"Unable to open {_fullPath}\n{ex}"); + } + } + + return Result; + } +} diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/OpenUrlCommand.cs b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/OpenUrlCommand.cs similarity index 100% rename from src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/OpenUrlCommand.cs rename to src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/OpenUrlCommand.cs diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/ShowFileInFolderCommand.cs b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/ShowFileInFolderCommand.cs similarity index 100% rename from src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/ShowFileInFolderCommand.cs rename to src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Commands/ShowFileInFolderCommand.cs diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/NativeMethods.txt b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/NativeMethods.txt index 942650356e..c48ffb158a 100644 --- a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/NativeMethods.txt +++ b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/NativeMethods.txt @@ -5,4 +5,4 @@ GetPackageFamilyNameFromToken CoRevertToSelf SHGetKnownFolderPath KNOWN_FOLDER_FLAG -GetCurrentPackageId +GetCurrentPackageId \ No newline at end of file diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Properties/Resources.Designer.cs b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Properties/Resources.Designer.cs index 2a3b916127..7289c704fb 100644 --- a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Properties/Resources.Designer.cs +++ b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Properties/Resources.Designer.cs @@ -69,6 +69,24 @@ namespace Microsoft.CommandPalette.Extensions.Toolkit.Properties { } } + /// + /// Looks up a localized string similar to Copy path. + /// + internal static string CopyPathTextCommand_Name { + get { + return ResourceManager.GetString("CopyPathTextCommand_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Copied path to clipboard. + /// + internal static string CopyPathTextCommand_Result { + get { + return ResourceManager.GetString("CopyPathTextCommand_Result", resourceCulture); + } + } + /// /// Looks up a localized string similar to Copied to clipboard. /// diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Properties/Resources.resx b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Properties/Resources.resx index a27390811e..2472519d34 100644 --- a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Properties/Resources.resx +++ b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Properties/Resources.resx @@ -126,6 +126,12 @@ Copied to clipboard + + Copy path + + + Copied path to clipboard + Open