From b9de59ce64e8e4be1acae256e4d9ed21e7d841d1 Mon Sep 17 00:00:00 2001 From: Kai Tao <69313318+vanzue@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:04:03 +0800 Subject: [PATCH] Cmdpal: Peek command in indexer (#44581) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary of the Pull Request Add a peek command, so we could quickly view the files found by indexer I’m aware that wiring the Peek command directly into the indexer extension is fairly PowerToys-specific. I’m open to suggestions if we think this should instead be handled via a more general extension / plugin mechanism; if a broader framework is planned, I’m happy to wait and revisit this once that structure is in place. ## PR Checklist - [ ] Closes: #43517 - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx ## Detailed Description of the Pull Request / Additional comments ## Validation Steps Performed image --- .../Assets/Peek.png | Bin 0 -> 3122 bytes .../Commands/PeekFileCommand.cs | 73 ++++++++++++++++++ .../Data/IndexerListItem.cs | 8 ++ .../ext/Microsoft.CmdPal.Ext.Indexer/Icons.cs | 2 + .../Microsoft.CmdPal.Ext.Indexer/KeyChords.cs | 4 + .../Microsoft.CmdPal.Ext.Indexer.csproj | 3 + .../Properties/Resources.Designer.cs | 27 +++++++ .../Properties/Resources.resx | 9 +++ 8 files changed, 126 insertions(+) create mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Assets/Peek.png create mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/PeekFileCommand.cs diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Assets/Peek.png b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Assets/Peek.png new file mode 100644 index 0000000000000000000000000000000000000000..3beeccaf1775d0d28bf61303cf90b17cc053f61f GIT binary patch literal 3122 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 literal 0 HcmV?d00001 diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/PeekFileCommand.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/PeekFileCommand.cs new file mode 100644 index 0000000000..808daa567f --- /dev/null +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Commands/PeekFileCommand.cs @@ -0,0 +1,73 @@ +// 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; +using System.IO; +using ManagedCommon; +using Microsoft.CmdPal.Ext.Indexer.Properties; +using Microsoft.CommandPalette.Extensions.Toolkit; + +namespace Microsoft.CmdPal.Ext.Indexer.Commands; + +/// +/// Command to preview a file using PowerToys Peek. +/// +public sealed partial class PeekFileCommand : InvokableCommand +{ + private const string PeekExecutable = @"WinUI3Apps\PowerToys.Peek.UI.exe"; + + private static readonly Lazy _peekPath = new(GetPeekExecutablePath); + + private readonly string _fullPath; + + public PeekFileCommand(string fullPath) + { + _fullPath = fullPath; + Name = Resources.Indexer_Command_Peek; + Icon = Icons.PeekIcon; + } + + /// + /// Gets a value indicating whether Peek is available on this system. + /// + public static bool IsPeekAvailable => !string.IsNullOrEmpty(_peekPath.Value); + + public override CommandResult Invoke() + { + var peekExe = _peekPath.Value; + if (string.IsNullOrEmpty(peekExe)) + { + return CommandResult.ShowToast(Resources.Indexer_Command_Peek_NotAvailable); + } + + try + { + using var process = new Process(); + process.StartInfo.FileName = peekExe; + process.StartInfo.Arguments = $"\"{_fullPath}\""; + process.StartInfo.UseShellExecute = false; + process.Start(); + } + catch (Exception ex) + { + ExtensionHost.LogMessage($"Unable to launch Peek for {_fullPath}\n{ex}"); + return CommandResult.ShowToast(Resources.Indexer_Command_Peek_Failed); + } + + return CommandResult.Dismiss(); + } + + private static string GetPeekExecutablePath() + { + var installPath = PowerToysPathResolver.GetPowerToysInstallPath(); + if (string.IsNullOrEmpty(installPath)) + { + return string.Empty; + } + + var peekPath = Path.Combine(installPath, PeekExecutable); + return File.Exists(peekPath) ? peekPath : string.Empty; + } +} 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 51a30ddc86..54d2744abd 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 @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.CmdPal.Core.Common.Commands; +using Microsoft.CmdPal.Ext.Indexer.Commands; using Microsoft.CmdPal.Ext.Indexer.Helpers; using Microsoft.CmdPal.Ext.Indexer.Pages; using Microsoft.CmdPal.Ext.Indexer.Properties; @@ -96,6 +97,13 @@ internal sealed partial class IndexerListItem : ListItem } commands.Add(new CommandContextItem(new OpenWithCommand(fullPath))); + + // Add Peek command if available (only for files, not directories) + if (!isDir && PeekFileCommand.IsPeekAvailable) + { + commands.Add(new CommandContextItem(new PeekFileCommand(fullPath)) { RequestedShortcut = KeyChords.Peek }); + } + commands.Add(new CommandContextItem(new ShowFileInFolderCommand(fullPath) { Name = Resources.Indexer_Command_ShowInFolder }) { RequestedShortcut = KeyChords.OpenFileLocation }); commands.Add(new CommandContextItem(new CopyPathCommand(fullPath) { Name = Resources.Indexer_Command_CopyPath }) { RequestedShortcut = KeyChords.CopyFilePath }); commands.Add(new CommandContextItem(new OpenInConsoleCommand(fullPath)) { RequestedShortcut = KeyChords.OpenInConsole }); diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Icons.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Icons.cs index bd9759514c..1e92d9f323 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Icons.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Icons.cs @@ -23,4 +23,6 @@ internal static class Icons internal static IconInfo FilesIcon { get; } = new("\uF571"); // PrintAllPages internal static IconInfo FilterIcon { get; } = new("\uE71C"); // Filter + + internal static IconInfo PeekIcon { get; } = IconHelpers.FromRelativePath("Assets\\Peek.png"); } diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/KeyChords.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/KeyChords.cs index c0fd69d0f2..aa44696a7b 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/KeyChords.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/KeyChords.cs @@ -4,6 +4,8 @@ using Microsoft.CmdPal.Core.Common.Helpers; using Microsoft.CommandPalette.Extensions; +using Microsoft.CommandPalette.Extensions.Toolkit; +using Windows.System; namespace Microsoft.CmdPal.Ext.Indexer; @@ -14,4 +16,6 @@ internal static class KeyChords internal static KeyChord CopyFilePath { get; } = WellKnownKeyChords.CopyFilePath; internal static KeyChord OpenInConsole { get; } = WellKnownKeyChords.OpenInConsole; + + internal static KeyChord Peek { get; } = KeyChordHelpers.FromModifiers(ctrl: true, vkey: (int)VirtualKey.Space); } 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 6b3b304825..2c40afd19c 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 @@ -42,6 +42,9 @@ PreserveNewest + + PreserveNewest + diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Properties/Resources.Designer.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Properties/Resources.Designer.cs index 4394cd6697..469c5faf61 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Properties/Resources.Designer.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Properties/Resources.Designer.cs @@ -132,6 +132,33 @@ namespace Microsoft.CmdPal.Ext.Indexer.Properties { } } + /// + /// Looks up a localized string similar to Peek preview. + /// + internal static string Indexer_Command_Peek { + get { + return ResourceManager.GetString("Indexer_Command_Peek", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to launch Peek. + /// + internal static string Indexer_Command_Peek_Failed { + get { + return ResourceManager.GetString("Indexer_Command_Peek_Failed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PowerToys Peek is not available. + /// + internal static string Indexer_Command_Peek_NotAvailable { + get { + return ResourceManager.GetString("Indexer_Command_Peek_NotAvailable", resourceCulture); + } + } + /// /// Looks up a localized string similar to Search all files. /// diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Properties/Resources.resx b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Properties/Resources.resx index 9ea1c4563e..8f5f760137 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Properties/Resources.resx +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Indexer/Properties/Resources.resx @@ -202,4 +202,13 @@ You can try searching all files on this PC or adjust your indexing settings. Files + + Peek preview + + + PowerToys Peek is not available + + + Failed to launch Peek + \ No newline at end of file