From 1ce41a01dccfb8dfea70436ca266f213a3fa3d35 Mon Sep 17 00:00:00 2001 From: ferrariofilippo Date: Thu, 23 Feb 2023 23:11:27 +0100 Subject: [PATCH 01/16] Open in terminal Rich Command --- .../Actions/Global/OpenTerminalAction.cs | 32 +++++++++++++++ .../Actions/Global/OpenTerminalAsAdmin.cs | 41 +++++++++++++++++++ src/Files.App/Commands/CommandCodes.cs | 2 + .../Commands/Manager/CommandManager.cs | 4 ++ .../Commands/Manager/ICommandManager.cs | 2 + src/Files.App/Strings/en-US/Resources.resw | 6 +++ src/Files.App/Views/BaseShellPage.cs | 15 ++++--- 7 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 src/Files.App/Actions/Global/OpenTerminalAction.cs create mode 100644 src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs diff --git a/src/Files.App/Actions/Global/OpenTerminalAction.cs b/src/Files.App/Actions/Global/OpenTerminalAction.cs new file mode 100644 index 000000000000..9701ae1d3cd6 --- /dev/null +++ b/src/Files.App/Actions/Global/OpenTerminalAction.cs @@ -0,0 +1,32 @@ +using Files.App.Commands; +using Files.App.Extensions; +using System.Diagnostics; +using System.Threading.Tasks; +using Windows.System; + +namespace Files.App.Actions +{ + internal class OpenTerminalAction : IAction + { + public string Label { get; } = "OpenTerminal".GetLocalizedResource(); + + public HotKey HotKey { get; } = new((VirtualKey)192, VirtualKeyModifiers.Control); + + public RichGlyph Glyph { get; } = new RichGlyph("\uE756"); + + public string Path { get; set; } = string.Empty; + + public Task ExecuteAsync() + { + var terminalStartInfo = new ProcessStartInfo() + { + FileName = "wt.exe", + Arguments = $"-d {Path}" + }; + + App.Window.DispatcherQueue.TryEnqueue(() => Process.Start(terminalStartInfo)); + + return Task.CompletedTask; + } + } +} diff --git a/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs b/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs new file mode 100644 index 000000000000..0221a57992e4 --- /dev/null +++ b/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs @@ -0,0 +1,41 @@ +using Files.App.Commands; +using Files.App.Extensions; +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Windows.System; + +namespace Files.App.Actions +{ + internal class OpenTerminalAsAdminAction : IAction + { + public string Label { get; } = "OpenTerminalAsAdmin".GetLocalizedResource(); + + public HotKey HotKey { get; } = new((VirtualKey)192, VirtualKeyModifiers.Control | VirtualKeyModifiers.Shift); + + public RichGlyph Glyph { get; } = new RichGlyph("\uE756"); + + public string Path { get; set; } = string.Empty; + + public Task ExecuteAsync() + { + var terminalStartInfo = new ProcessStartInfo() + { + FileName = "wt.exe", + Arguments = $"-d {Path}", + Verb = "runas", + UseShellExecute = true + }; + + try + { + App.Window.DispatcherQueue.TryEnqueue(() => Process.Start(terminalStartInfo)); + } + catch (OperationCanceledException) + { + } + + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/src/Files.App/Commands/CommandCodes.cs b/src/Files.App/Commands/CommandCodes.cs index 8ee5391bac9a..81ea0937bf01 100644 --- a/src/Files.App/Commands/CommandCodes.cs +++ b/src/Files.App/Commands/CommandCodes.cs @@ -6,6 +6,8 @@ public enum CommandCodes // global OpenHelp, + OpenTerminal, + OpenTerminalAsAdmin, ToggleFullScreen, // show diff --git a/src/Files.App/Commands/Manager/CommandManager.cs b/src/Files.App/Commands/Manager/CommandManager.cs index f32cb93854bc..13e65c9a31c8 100644 --- a/src/Files.App/Commands/Manager/CommandManager.cs +++ b/src/Files.App/Commands/Manager/CommandManager.cs @@ -28,6 +28,8 @@ internal class CommandManager : ICommandManager public IRichCommand None => commands[CommandCodes.None]; public IRichCommand OpenHelp => commands[CommandCodes.OpenHelp]; + public IRichCommand OpenTerminal => commands[CommandCodes.OpenTerminal]; + public IRichCommand OpenTerminalAsAdmin => commands[CommandCodes.OpenTerminalAsAdmin]; public IRichCommand ToggleFullScreen => commands[CommandCodes.ToggleFullScreen]; public IRichCommand ToggleShowHiddenItems => commands[CommandCodes.ToggleShowHiddenItems]; public IRichCommand ToggleShowFileExtensions => commands[CommandCodes.ToggleShowFileExtensions]; @@ -52,6 +54,8 @@ public CommandManager() private static IDictionary CreateActions() => new Dictionary { [CommandCodes.OpenHelp] = new OpenHelpAction(), + [CommandCodes.OpenTerminal] = new OpenTerminalAction(), + [CommandCodes.OpenTerminalAsAdmin] = new OpenTerminalAsAdminAction(), [CommandCodes.ToggleFullScreen] = new ToggleFullScreenAction(), [CommandCodes.ToggleShowHiddenItems] = new ToggleShowHiddenItemsAction(), [CommandCodes.ToggleShowFileExtensions] = new ToggleShowFileExtensionsAction(), diff --git a/src/Files.App/Commands/Manager/ICommandManager.cs b/src/Files.App/Commands/Manager/ICommandManager.cs index 0705227f453f..f2bc4ea649a8 100644 --- a/src/Files.App/Commands/Manager/ICommandManager.cs +++ b/src/Files.App/Commands/Manager/ICommandManager.cs @@ -13,6 +13,8 @@ public interface ICommandManager : IEnumerable IRichCommand None { get; } IRichCommand OpenHelp { get; } + IRichCommand OpenTerminal { get; } + IRichCommand OpenTerminalAsAdmin { get; } IRichCommand ToggleFullScreen { get; } IRichCommand ToggleShowHiddenItems { get; } diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw index 1d229b43c92f..1061e42e61c0 100644 --- a/src/Files.App/Strings/en-US/Resources.resw +++ b/src/Files.App/Strings/en-US/Resources.resw @@ -2976,4 +2976,10 @@ Apply this action to all conflicting items + + Open in terminal + + + Open in terminal as admin + \ No newline at end of file diff --git a/src/Files.App/Views/BaseShellPage.cs b/src/Files.App/Views/BaseShellPage.cs index 25ba82fe264c..9f11f2319c51 100644 --- a/src/Files.App/Views/BaseShellPage.cs +++ b/src/Files.App/Views/BaseShellPage.cs @@ -1,6 +1,7 @@ using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.WinUI; +using Files.App.Commands; using Files.App.DataModels; using Files.App.EventArguments; using Files.App.Extensions; @@ -54,6 +55,8 @@ public abstract class BaseShellPage : Page, IShellPage, INotifyPropertyChanged protected readonly IUpdateService updateSettingsService = Ioc.Default.GetRequiredService(); + protected readonly ICommandManager commands = Ioc.Default.GetRequiredService(); + public ToolbarViewModel ToolbarViewModel { get; } = new ToolbarViewModel(); public IBaseLayout SlimContentPage => ContentPage; @@ -284,14 +287,10 @@ protected void ShellPage_PreviewKeyDown(object sender, KeyRoutedEventArgs args) if (SlimContentPage?.SelectedItem?.PrimaryItemAttribute == StorageItemTypes.Folder) path = SlimContentPage.SelectedItem.ItemPath; - var terminalStartInfo = new ProcessStartInfo() - { - FileName = "wt.exe", - Arguments = $"-d {path}", - Verb = shift ? "runas" : "", - UseShellExecute = true - }; - DispatcherQueue.TryEnqueue(() => Process.Start(terminalStartInfo)); + if (shift) + commands.OpenTerminalAsAdmin. Execute(path); + else + commands.OpenTerminal.Execute(path); args.Handled = true; From 299a6d26d05931c055a3733f229022cfa2fd57d2 Mon Sep 17 00:00:00 2001 From: ferrariofilippo Date: Mon, 27 Feb 2023 18:30:40 +0100 Subject: [PATCH 02/16] Selected Path support & Removed duplicate code --- .../Actions/Global/OpenTerminalAction.cs | 47 +++++++++++++++---- .../Actions/Global/OpenTerminalAsAdmin.cs | 33 ++++--------- src/Files.App/Views/BaseShellPage.cs | 9 +--- 3 files changed, 49 insertions(+), 40 deletions(-) diff --git a/src/Files.App/Actions/Global/OpenTerminalAction.cs b/src/Files.App/Actions/Global/OpenTerminalAction.cs index 9701ae1d3cd6..6ec77d4db578 100644 --- a/src/Files.App/Actions/Global/OpenTerminalAction.cs +++ b/src/Files.App/Actions/Global/OpenTerminalAction.cs @@ -1,32 +1,61 @@ -using Files.App.Commands; +using CommunityToolkit.Mvvm.DependencyInjection; +using Files.App.Commands; +using Files.App.Contexts; using Files.App.Extensions; +using System; using System.Diagnostics; using System.Threading.Tasks; +using Windows.Storage; using Windows.System; namespace Files.App.Actions { internal class OpenTerminalAction : IAction { + private readonly IContentPageContext context = Ioc.Default.GetRequiredService(); + public string Label { get; } = "OpenTerminal".GetLocalizedResource(); - public HotKey HotKey { get; } = new((VirtualKey)192, VirtualKeyModifiers.Control); + public virtual HotKey HotKey { get; } = new((VirtualKey)192, VirtualKeyModifiers.Control); public RichGlyph Glyph { get; } = new RichGlyph("\uE756"); - public string Path { get; set; } = string.Empty; - public Task ExecuteAsync() { - var terminalStartInfo = new ProcessStartInfo() + var terminalStartInfo = GetProcessStartInfo(); + if (terminalStartInfo is not null) + { + try + { + App.Window.DispatcherQueue.TryEnqueue(() => Process.Start(terminalStartInfo)); + } + catch (OperationCanceledException) + { + } + } + + return Task.CompletedTask; + } + + protected virtual ProcessStartInfo? GetProcessStartInfo() + { + var path = GetPath(); + if (path == string.Empty) + return null; + + return new() { FileName = "wt.exe", - Arguments = $"-d {Path}" + Arguments = $"-d {path}" }; + } - App.Window.DispatcherQueue.TryEnqueue(() => Process.Start(terminalStartInfo)); - - return Task.CompletedTask; + protected string GetPath() + { + // Return folder path if there is a folder selected, otherwise the current directory. + return context.ShellPage?.SlimContentPage?.SelectedItem?.PrimaryItemAttribute is StorageItemTypes.Folder + ? context.ShellPage.SlimContentPage.SelectedItem.ItemPath + : context.ShellPage?.FilesystemViewModel.WorkingDirectory ?? string.Empty; } } } diff --git a/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs b/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs index 0221a57992e4..ccec070e8655 100644 --- a/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs +++ b/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs @@ -1,41 +1,26 @@ using Files.App.Commands; using Files.App.Extensions; -using System; using System.Diagnostics; -using System.Threading.Tasks; using Windows.System; namespace Files.App.Actions { - internal class OpenTerminalAsAdminAction : IAction + internal class OpenTerminalAsAdminAction : OpenTerminalAction { - public string Label { get; } = "OpenTerminalAsAdmin".GetLocalizedResource(); + public new string Label { get; } = "OpenTerminalAsAdmin".GetLocalizedResource(); - public HotKey HotKey { get; } = new((VirtualKey)192, VirtualKeyModifiers.Control | VirtualKeyModifiers.Shift); + public override HotKey HotKey { get; } = new((VirtualKey)192, VirtualKeyModifiers.Control | VirtualKeyModifiers.Shift); - public RichGlyph Glyph { get; } = new RichGlyph("\uE756"); - - public string Path { get; set; } = string.Empty; - - public Task ExecuteAsync() + protected override ProcessStartInfo? GetProcessStartInfo() { - var terminalStartInfo = new ProcessStartInfo() + var startInfo = base.GetProcessStartInfo(); + if (startInfo is not null) { - FileName = "wt.exe", - Arguments = $"-d {Path}", - Verb = "runas", - UseShellExecute = true - }; - - try - { - App.Window.DispatcherQueue.TryEnqueue(() => Process.Start(terminalStartInfo)); - } - catch (OperationCanceledException) - { + startInfo.Verb = "runas"; + startInfo.UseShellExecute = true; } - return Task.CompletedTask; + return startInfo; } } } \ No newline at end of file diff --git a/src/Files.App/Views/BaseShellPage.cs b/src/Files.App/Views/BaseShellPage.cs index 8bdb645facc7..ddd391568648 100644 --- a/src/Files.App/Views/BaseShellPage.cs +++ b/src/Files.App/Views/BaseShellPage.cs @@ -287,15 +287,10 @@ protected void ShellPage_PreviewKeyDown(object sender, KeyRoutedEventArgs args) // Ctrl + ` (accent key), open terminal case (true, _, false, true, (VirtualKey)192): - // Check if there is a folder selected, if not use the current directory. - string path = FilesystemViewModel.WorkingDirectory; - if (SlimContentPage?.SelectedItem?.PrimaryItemAttribute == StorageItemTypes.Folder) - path = SlimContentPage.SelectedItem.ItemPath; - if (shift) - commands.OpenTerminalAsAdmin. Execute(path); + commands.OpenTerminalAsAdmin.ExecuteAsync(); else - commands.OpenTerminal.Execute(path); + commands.OpenTerminal.ExecuteAsync(); args.Handled = true; From 178ca4fd8c5f3083ec3ad5761f99bc34af4ef488 Mon Sep 17 00:00:00 2001 From: ferrariofilippo Date: Mon, 27 Feb 2023 18:32:26 +0100 Subject: [PATCH 03/16] Unnecessary using --- src/Files.App/Views/BaseShellPage.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Files.App/Views/BaseShellPage.cs b/src/Files.App/Views/BaseShellPage.cs index ddd391568648..e1fc85cefa58 100644 --- a/src/Files.App/Views/BaseShellPage.cs +++ b/src/Files.App/Views/BaseShellPage.cs @@ -28,12 +28,10 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; -using Windows.Storage; using Windows.System; using Windows.UI.Core; using SortDirection = Files.Shared.Enums.SortDirection; From c3a6296fa4b0c5be755e638d6a62f8ccd2f2d3b1 Mon Sep 17 00:00:00 2001 From: Yair <39923744+yaira2@users.noreply.github.com> Date: Tue, 28 Feb 2023 21:28:13 -0500 Subject: [PATCH 04/16] Update src/Files.App/Strings/en-US/Resources.resw --- src/Files.App/Strings/en-US/Resources.resw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw index eb6175e7c231..8b22e6f55ed2 100644 --- a/src/Files.App/Strings/en-US/Resources.resw +++ b/src/Files.App/Strings/en-US/Resources.resw @@ -2605,7 +2605,7 @@ Open in terminal - Open in terminal as admin + Open in terminal as administrator Save From ee12b9c7e40d1925ca450aea77adc47eaa30d881 Mon Sep 17 00:00:00 2001 From: ferrariofilippo Date: Sat, 4 Mar 2023 22:09:04 +0100 Subject: [PATCH 05/16] Build Error --- src/Files.App/Views/BaseShellPage.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Files.App/Views/BaseShellPage.cs b/src/Files.App/Views/BaseShellPage.cs index 69803bc7a7d9..0a18a412b001 100644 --- a/src/Files.App/Views/BaseShellPage.cs +++ b/src/Files.App/Views/BaseShellPage.cs @@ -30,7 +30,6 @@ using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; -using System.Security.Policy; using System.Threading; using System.Threading.Tasks; using Windows.System; @@ -62,7 +61,6 @@ public abstract class BaseShellPage : Page, IShellPage, INotifyPropertyChanged public IBaseLayout SlimContentPage => ContentPage; - public ICommandManager commands = Ioc.Default.GetRequiredService(); public IFilesystemHelpers FilesystemHelpers { get; protected set; } public Type CurrentPageType => ItemDisplay.SourcePageType; From a4ec37c5403ec5593d23f84b8537ee9c63ed960e Mon Sep 17 00:00:00 2001 From: ferrariofilippo Date: Sun, 5 Mar 2023 21:32:20 +0100 Subject: [PATCH 06/16] Path spaces fix --- src/Files.App/Actions/Global/OpenTerminalAction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Files.App/Actions/Global/OpenTerminalAction.cs b/src/Files.App/Actions/Global/OpenTerminalAction.cs index 6ec77d4db578..ee2335f08e32 100644 --- a/src/Files.App/Actions/Global/OpenTerminalAction.cs +++ b/src/Files.App/Actions/Global/OpenTerminalAction.cs @@ -46,7 +46,7 @@ public Task ExecuteAsync() return new() { FileName = "wt.exe", - Arguments = $"-d {path}" + Arguments = $"-d \"{path}\"" }; } From 934e9e87f90f6fbd09fbdc2afd2a4d408d37a9b2 Mon Sep 17 00:00:00 2001 From: Filippo Ferrario Date: Fri, 10 Mar 2023 17:43:53 +0100 Subject: [PATCH 07/16] Removed BaseShellPage Code --- src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs | 2 +- src/Files.App/Views/BaseShellPage.cs | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs b/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs index ccec070e8655..4a4e3796e993 100644 --- a/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs +++ b/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs @@ -23,4 +23,4 @@ internal class OpenTerminalAsAdminAction : OpenTerminalAction return startInfo; } } -} \ No newline at end of file +} diff --git a/src/Files.App/Views/BaseShellPage.cs b/src/Files.App/Views/BaseShellPage.cs index 85d45f140890..011bf1ba49e6 100644 --- a/src/Files.App/Views/BaseShellPage.cs +++ b/src/Files.App/Views/BaseShellPage.cs @@ -282,18 +282,6 @@ protected void ShellPage_PreviewKeyDown(object sender, KeyRoutedEventArgs args) switch (c: ctrl, s: shift, a: alt, t: tabInstance, k: args.Key) { - // Ctrl + ` (accent key), open terminal - case (true, _, false, true, (VirtualKey)192): - - if (shift) - commands.OpenTerminalAsAdmin.ExecuteAsync(); - else - commands.OpenTerminal.ExecuteAsync(); - - args.Handled = true; - - break; - // Ctrl + space, toggle media playback case (true, false, false, true, VirtualKey.Space): From 509d32cc13af16fe92ee3834a144c008bcd91889 Mon Sep 17 00:00:00 2001 From: Filippo Ferrario Date: Sat, 11 Mar 2023 18:15:29 +0100 Subject: [PATCH 08/16] Requested Changes --- .../Actions/Global/OpenTerminalAction.cs | 82 +++++++++++++------ .../Actions/Global/OpenTerminalAsAdmin.cs | 12 +-- 2 files changed, 65 insertions(+), 29 deletions(-) diff --git a/src/Files.App/Actions/Global/OpenTerminalAction.cs b/src/Files.App/Actions/Global/OpenTerminalAction.cs index ee2335f08e32..7bce44c45089 100644 --- a/src/Files.App/Actions/Global/OpenTerminalAction.cs +++ b/src/Files.App/Actions/Global/OpenTerminalAction.cs @@ -1,61 +1,97 @@ -using CommunityToolkit.Mvvm.DependencyInjection; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.DependencyInjection; using Files.App.Commands; using Files.App.Contexts; using Files.App.Extensions; using System; +using System.ComponentModel; using System.Diagnostics; +using System.Linq; using System.Threading.Tasks; using Windows.Storage; using Windows.System; namespace Files.App.Actions { - internal class OpenTerminalAction : IAction + internal class OpenTerminalAction : ObservableObject, IAction { + private readonly string[] emptyStrings = Array.Empty(); + private readonly ProcessStartInfo[] emptyProcessInfos = Array.Empty(); + private readonly IContentPageContext context = Ioc.Default.GetRequiredService(); - public string Label { get; } = "OpenTerminal".GetLocalizedResource(); + public virtual string Label { get; } = "OpenTerminal".GetLocalizedResource(); public virtual HotKey HotKey { get; } = new((VirtualKey)192, VirtualKeyModifiers.Control); - public RichGlyph Glyph { get; } = new RichGlyph("\uE756"); + public RichGlyph Glyph { get; } = new("\uE756"); + + public bool IsExecutable => + context.PageType is not ContentPageTypes.None && + context.PageType is not ContentPageTypes.Home && + context.PageType is not ContentPageTypes.RecycleBin && + context.PageType is not ContentPageTypes.ZipFolder && + !(context.PageType is ContentPageTypes.SearchResults && + !context.SelectedItems.Any(item => item.PrimaryItemAttribute is StorageItemTypes.Folder)); + + public OpenTerminalAction() + { + context.PropertyChanged += Context_PropertyChanged; + } + + private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + OnPropertyChanged(nameof(IsExecutable)); + } public Task ExecuteAsync() { - var terminalStartInfo = GetProcessStartInfo(); - if (terminalStartInfo is not null) + var terminalStartInfo = GetProcessesStartInfo(); + foreach (var startInfo in terminalStartInfo) { - try - { - App.Window.DispatcherQueue.TryEnqueue(() => Process.Start(terminalStartInfo)); - } - catch (OperationCanceledException) + App.Window.DispatcherQueue.TryEnqueue(() => { - } + try + { + Process.Start(startInfo); + } + catch (Win32Exception) + { + } + }); } return Task.CompletedTask; } - protected virtual ProcessStartInfo? GetProcessStartInfo() + protected virtual ProcessStartInfo[] GetProcessesStartInfo() { - var path = GetPath(); - if (path == string.Empty) - return null; + var paths = GetPaths(); + if (paths.Length == 0) + return emptyProcessInfos; - return new() + return paths.Select(path => new ProcessStartInfo() { FileName = "wt.exe", Arguments = $"-d \"{path}\"" - }; + }).ToArray(); } - protected string GetPath() + protected string[] GetPaths() { - // Return folder path if there is a folder selected, otherwise the current directory. - return context.ShellPage?.SlimContentPage?.SelectedItem?.PrimaryItemAttribute is StorageItemTypes.Folder - ? context.ShellPage.SlimContentPage.SelectedItem.ItemPath - : context.ShellPage?.FilesystemViewModel.WorkingDirectory ?? string.Empty; + var paths = context.ShellPage?.SlimContentPage?.SelectedItems? + .Where(item => item.PrimaryItemAttribute is StorageItemTypes.Folder) + .Select(item => item.ItemPath) + .ToArray(); + + if (paths is null || paths.Length == 0) + { + paths = context.ShellPage?.FilesystemViewModel.WorkingDirectory is not null + ? new string[1] { context.ShellPage!.FilesystemViewModel.WorkingDirectory } + : emptyStrings; + } + + return paths; } } } diff --git a/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs b/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs index 4a4e3796e993..115c4f0d37c8 100644 --- a/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs +++ b/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs @@ -7,17 +7,17 @@ namespace Files.App.Actions { internal class OpenTerminalAsAdminAction : OpenTerminalAction { - public new string Label { get; } = "OpenTerminalAsAdmin".GetLocalizedResource(); + public override string Label { get; } = "OpenTerminalAsAdmin".GetLocalizedResource(); public override HotKey HotKey { get; } = new((VirtualKey)192, VirtualKeyModifiers.Control | VirtualKeyModifiers.Shift); - protected override ProcessStartInfo? GetProcessStartInfo() + protected override ProcessStartInfo[] GetProcessesStartInfo() { - var startInfo = base.GetProcessStartInfo(); - if (startInfo is not null) + var startInfo = base.GetProcessesStartInfo(); + for (int i = 0; i < startInfo.Length; i++) { - startInfo.Verb = "runas"; - startInfo.UseShellExecute = true; + startInfo[i].Verb = "runas"; + startInfo[i].UseShellExecute = true; } return startInfo; From e6f7209e0e93a3340a2dd0a20ab3e32c95316cef Mon Sep 17 00:00:00 2001 From: Filippo Ferrario Date: Sat, 11 Mar 2023 20:04:59 +0100 Subject: [PATCH 09/16] Open folders in tabs instead of windows --- .../Actions/Global/OpenTerminalAction.cs | 24 +++++++++++-------- .../Actions/Global/OpenTerminalAsAdmin.cs | 10 ++++---- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/Files.App/Actions/Global/OpenTerminalAction.cs b/src/Files.App/Actions/Global/OpenTerminalAction.cs index 7bce44c45089..6cf21d76f5e9 100644 --- a/src/Files.App/Actions/Global/OpenTerminalAction.cs +++ b/src/Files.App/Actions/Global/OpenTerminalAction.cs @@ -7,6 +7,7 @@ using System.ComponentModel; using System.Diagnostics; using System.Linq; +using System.Text; using System.Threading.Tasks; using Windows.Storage; using Windows.System; @@ -16,7 +17,6 @@ namespace Files.App.Actions internal class OpenTerminalAction : ObservableObject, IAction { private readonly string[] emptyStrings = Array.Empty(); - private readonly ProcessStartInfo[] emptyProcessInfos = Array.Empty(); private readonly IContentPageContext context = Ioc.Default.GetRequiredService(); @@ -31,7 +31,7 @@ context.PageType is not ContentPageTypes.None && context.PageType is not ContentPageTypes.Home && context.PageType is not ContentPageTypes.RecycleBin && context.PageType is not ContentPageTypes.ZipFolder && - !(context.PageType is ContentPageTypes.SearchResults && + !(context.PageType is ContentPageTypes.SearchResults && !context.SelectedItems.Any(item => item.PrimaryItemAttribute is StorageItemTypes.Folder)); public OpenTerminalAction() @@ -46,14 +46,14 @@ private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e) public Task ExecuteAsync() { - var terminalStartInfo = GetProcessesStartInfo(); - foreach (var startInfo in terminalStartInfo) + var terminalStartInfo = GetProcessStartInfo(); + if (terminalStartInfo is not null) { App.Window.DispatcherQueue.TryEnqueue(() => { try { - Process.Start(startInfo); + Process.Start(terminalStartInfo); } catch (Win32Exception) { @@ -64,17 +64,21 @@ public Task ExecuteAsync() return Task.CompletedTask; } - protected virtual ProcessStartInfo[] GetProcessesStartInfo() + protected virtual ProcessStartInfo? GetProcessStartInfo() { var paths = GetPaths(); if (paths.Length == 0) - return emptyProcessInfos; + return null; - return paths.Select(path => new ProcessStartInfo() + var args = new StringBuilder($"-d \"{paths[0]}\""); + for (int i = 1; i < paths.Length; i++) + args.Append($" ; nt -d \"{paths[i]}\""); + + return new() { FileName = "wt.exe", - Arguments = $"-d \"{path}\"" - }).ToArray(); + Arguments = args.ToString() + }; } protected string[] GetPaths() diff --git a/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs b/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs index 115c4f0d37c8..6803e8c29c48 100644 --- a/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs +++ b/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs @@ -11,13 +11,13 @@ internal class OpenTerminalAsAdminAction : OpenTerminalAction public override HotKey HotKey { get; } = new((VirtualKey)192, VirtualKeyModifiers.Control | VirtualKeyModifiers.Shift); - protected override ProcessStartInfo[] GetProcessesStartInfo() + protected override ProcessStartInfo? GetProcessStartInfo() { - var startInfo = base.GetProcessesStartInfo(); - for (int i = 0; i < startInfo.Length; i++) + var startInfo = base.GetProcessStartInfo(); + if (startInfo is not null) { - startInfo[i].Verb = "runas"; - startInfo[i].UseShellExecute = true; + startInfo.Verb = "runas"; + startInfo.UseShellExecute = true; } return startInfo; From 8403589170483a0e78bca5d0f3b3bda7c6d88e55 Mon Sep 17 00:00:00 2001 From: Filippo Ferrario Date: Sat, 11 Mar 2023 20:49:12 +0100 Subject: [PATCH 10/16] Added Open actions folder --- .../Actions/{Global => Open}/OpenTerminalAction.cs | 0 .../Actions/{Global => Open}/OpenTerminalAsAdmin.cs | 0 src/Files.App/Commands/CommandCodes.cs | 8 +++++--- src/Files.App/Commands/Manager/CommandManager.cs | 8 ++++---- src/Files.App/Commands/Manager/ICommandManager.cs | 5 +++-- 5 files changed, 12 insertions(+), 9 deletions(-) rename src/Files.App/Actions/{Global => Open}/OpenTerminalAction.cs (100%) rename src/Files.App/Actions/{Global => Open}/OpenTerminalAsAdmin.cs (100%) diff --git a/src/Files.App/Actions/Global/OpenTerminalAction.cs b/src/Files.App/Actions/Open/OpenTerminalAction.cs similarity index 100% rename from src/Files.App/Actions/Global/OpenTerminalAction.cs rename to src/Files.App/Actions/Open/OpenTerminalAction.cs diff --git a/src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs b/src/Files.App/Actions/Open/OpenTerminalAsAdmin.cs similarity index 100% rename from src/Files.App/Actions/Global/OpenTerminalAsAdmin.cs rename to src/Files.App/Actions/Open/OpenTerminalAsAdmin.cs diff --git a/src/Files.App/Commands/CommandCodes.cs b/src/Files.App/Commands/CommandCodes.cs index 69914fb08d8c..3f9949f5b617 100644 --- a/src/Files.App/Commands/CommandCodes.cs +++ b/src/Files.App/Commands/CommandCodes.cs @@ -6,8 +6,6 @@ public enum CommandCodes // Global OpenHelp, - OpenTerminal, - OpenTerminalAsAdmin, ToggleFullScreen, // Show @@ -56,6 +54,10 @@ public enum CommandCodes // Image Edition RotateLeft, - RotateRight + RotateRight, + + // Open + OpenTerminal, + OpenTerminalAsAdmin, } } diff --git a/src/Files.App/Commands/Manager/CommandManager.cs b/src/Files.App/Commands/Manager/CommandManager.cs index 4ca516ca0a6c..ec06b6fae3e1 100644 --- a/src/Files.App/Commands/Manager/CommandManager.cs +++ b/src/Files.App/Commands/Manager/CommandManager.cs @@ -33,8 +33,6 @@ internal class CommandManager : ICommandManager public IRichCommand None => commands[CommandCodes.None]; public IRichCommand OpenHelp => commands[CommandCodes.OpenHelp]; - public IRichCommand OpenTerminal => commands[CommandCodes.OpenTerminal]; - public IRichCommand OpenTerminalAsAdmin => commands[CommandCodes.OpenTerminalAsAdmin]; public IRichCommand ToggleFullScreen => commands[CommandCodes.ToggleFullScreen]; public IRichCommand ToggleShowHiddenItems => commands[CommandCodes.ToggleShowHiddenItems]; public IRichCommand ToggleShowFileExtensions => commands[CommandCodes.ToggleShowFileExtensions]; @@ -66,6 +64,8 @@ internal class CommandManager : ICommandManager public IRichCommand CompressIntoZip => commands[CommandCodes.CompressIntoZip]; public IRichCommand RotateLeft => commands[CommandCodes.RotateLeft]; public IRichCommand RotateRight => commands[CommandCodes.RotateRight]; + public IRichCommand OpenTerminal => commands[CommandCodes.OpenTerminal]; + public IRichCommand OpenTerminalAsAdmin => commands[CommandCodes.OpenTerminalAsAdmin]; public CommandManager() { @@ -86,8 +86,6 @@ public CommandManager() private static IDictionary CreateActions() => new Dictionary { [CommandCodes.OpenHelp] = new OpenHelpAction(), - [CommandCodes.OpenTerminal] = new OpenTerminalAction(), - [CommandCodes.OpenTerminalAsAdmin] = new OpenTerminalAsAdminAction(), [CommandCodes.ToggleFullScreen] = new ToggleFullScreenAction(), [CommandCodes.ToggleShowHiddenItems] = new ToggleShowHiddenItemsAction(), [CommandCodes.ToggleShowFileExtensions] = new ToggleShowFileExtensionsAction(), @@ -119,6 +117,8 @@ public CommandManager() [CommandCodes.CompressIntoZip] = new CompressIntoZipAction(), [CommandCodes.RotateLeft] = new RotateLeftAction(), [CommandCodes.RotateRight] = new RotateRightAction() + [CommandCodes.OpenTerminal] = new OpenTerminalAction(), + [CommandCodes.OpenTerminalAsAdmin] = new OpenTerminalAsAdminAction(), }; [DebuggerDisplay("Command None")] diff --git a/src/Files.App/Commands/Manager/ICommandManager.cs b/src/Files.App/Commands/Manager/ICommandManager.cs index bb0cab92f7d1..13cbc861932c 100644 --- a/src/Files.App/Commands/Manager/ICommandManager.cs +++ b/src/Files.App/Commands/Manager/ICommandManager.cs @@ -13,8 +13,6 @@ public interface ICommandManager : IEnumerable IRichCommand None { get; } IRichCommand OpenHelp { get; } - IRichCommand OpenTerminal { get; } - IRichCommand OpenTerminalAsAdmin { get; } IRichCommand ToggleFullScreen { get; } IRichCommand ToggleShowHiddenItems { get; } @@ -53,5 +51,8 @@ public interface ICommandManager : IEnumerable IRichCommand RotateLeft { get; } IRichCommand RotateRight { get; } + + IRichCommand OpenTerminal { get; } + IRichCommand OpenTerminalAsAdmin { get; } } } From 5a369a42e0f98067a7898a3d9d55ca489ad16926 Mon Sep 17 00:00:00 2001 From: Filippo Ferrario Date: Sat, 11 Mar 2023 20:50:29 +0100 Subject: [PATCH 11/16] Build Error --- src/Files.App/Commands/Manager/CommandManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Files.App/Commands/Manager/CommandManager.cs b/src/Files.App/Commands/Manager/CommandManager.cs index ec06b6fae3e1..cfead25bde7f 100644 --- a/src/Files.App/Commands/Manager/CommandManager.cs +++ b/src/Files.App/Commands/Manager/CommandManager.cs @@ -116,7 +116,7 @@ public CommandManager() [CommandCodes.CompressIntoSevenZip] = new CompressIntoSevenZipAction(), [CommandCodes.CompressIntoZip] = new CompressIntoZipAction(), [CommandCodes.RotateLeft] = new RotateLeftAction(), - [CommandCodes.RotateRight] = new RotateRightAction() + [CommandCodes.RotateRight] = new RotateRightAction(), [CommandCodes.OpenTerminal] = new OpenTerminalAction(), [CommandCodes.OpenTerminalAsAdmin] = new OpenTerminalAsAdminAction(), }; From 625aa3fa3010eb44ce0b64dadc370ff4c746dd8e Mon Sep 17 00:00:00 2001 From: Filippo Ferrario Date: Sun, 12 Mar 2023 15:58:14 +0100 Subject: [PATCH 12/16] Avoid Character Escape --- src/Files.App/Actions/Open/OpenTerminalAction.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Files.App/Actions/Open/OpenTerminalAction.cs b/src/Files.App/Actions/Open/OpenTerminalAction.cs index 6cf21d76f5e9..0b52b1e3d89a 100644 --- a/src/Files.App/Actions/Open/OpenTerminalAction.cs +++ b/src/Files.App/Actions/Open/OpenTerminalAction.cs @@ -70,9 +70,14 @@ public Task ExecuteAsync() if (paths.Length == 0) return null; - var args = new StringBuilder($"-d \"{paths[0]}\""); + var path = paths[0] + (paths[0].EndsWith('\\') ? "\\" : ""); + + var args = new StringBuilder($"-d \"{path}\""); for (int i = 1; i < paths.Length; i++) - args.Append($" ; nt -d \"{paths[i]}\""); + { + path = paths[i] + (paths[i].EndsWith('\\') ? "\\" : ""); + args.Append($" ; nt -d \"{path}\""); + } return new() { From ab182544e27fef230e4630deb0c8af1379928a90 Mon Sep 17 00:00:00 2001 From: Filippo Ferrario Date: Sun, 12 Mar 2023 15:58:44 +0100 Subject: [PATCH 13/16] Add Action to file name --- .../Open/{OpenTerminalAsAdmin.cs => OpenTerminalAsAdminAction.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Files.App/Actions/Open/{OpenTerminalAsAdmin.cs => OpenTerminalAsAdminAction.cs} (100%) diff --git a/src/Files.App/Actions/Open/OpenTerminalAsAdmin.cs b/src/Files.App/Actions/Open/OpenTerminalAsAdminAction.cs similarity index 100% rename from src/Files.App/Actions/Open/OpenTerminalAsAdmin.cs rename to src/Files.App/Actions/Open/OpenTerminalAsAdminAction.cs From d133e40969431acf3c761acf28086e382f312764 Mon Sep 17 00:00:00 2001 From: Filippo Ferrario Date: Tue, 14 Mar 2023 09:20:51 +0100 Subject: [PATCH 14/16] Build Error --- src/Files.App/Commands/Manager/CommandManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Files.App/Commands/Manager/CommandManager.cs b/src/Files.App/Commands/Manager/CommandManager.cs index 67eab5e26748..62784bad1a53 100644 --- a/src/Files.App/Commands/Manager/CommandManager.cs +++ b/src/Files.App/Commands/Manager/CommandManager.cs @@ -59,7 +59,7 @@ internal class CommandManager : ICommandManager public IRichCommand CompressIntoSevenZip => commands[CommandCodes.CompressIntoSevenZip]; public IRichCommand CompressIntoZip => commands[CommandCodes.CompressIntoZip]; public IRichCommand RotateLeft => commands[CommandCodes.RotateLeft]; - public IRichCommand RotateRight => commands[CommandCodes.RotateRight];d + public IRichCommand RotateRight => commands[CommandCodes.RotateRight]; public IRichCommand OpenTerminal => commands[CommandCodes.OpenTerminal]; public IRichCommand OpenTerminalAsAdmin => commands[CommandCodes.OpenTerminalAsAdmin]; public IRichCommand NewTab => commands[CommandCodes.NewTab]; From f66ba20ed123d7526acb2a5a994505607dd87b35 Mon Sep 17 00:00:00 2001 From: Filippo Ferrario Date: Wed, 15 Mar 2023 22:09:09 +0100 Subject: [PATCH 15/16] Requested Changes --- .../Actions/Open/OpenTerminalAction.cs | 63 +++++++++++-------- src/Files.App/Constants.cs | 5 ++ 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/Files.App/Actions/Open/OpenTerminalAction.cs b/src/Files.App/Actions/Open/OpenTerminalAction.cs index 0b52b1e3d89a..52d2e03848d2 100644 --- a/src/Files.App/Actions/Open/OpenTerminalAction.cs +++ b/src/Files.App/Actions/Open/OpenTerminalAction.cs @@ -16,8 +16,6 @@ namespace Files.App.Actions { internal class OpenTerminalAction : ObservableObject, IAction { - private readonly string[] emptyStrings = Array.Empty(); - private readonly IContentPageContext context = Ioc.Default.GetRequiredService(); public virtual string Label { get; } = "OpenTerminal".GetLocalizedResource(); @@ -26,24 +24,15 @@ internal class OpenTerminalAction : ObservableObject, IAction public RichGlyph Glyph { get; } = new("\uE756"); - public bool IsExecutable => - context.PageType is not ContentPageTypes.None && - context.PageType is not ContentPageTypes.Home && - context.PageType is not ContentPageTypes.RecycleBin && - context.PageType is not ContentPageTypes.ZipFolder && - !(context.PageType is ContentPageTypes.SearchResults && - !context.SelectedItems.Any(item => item.PrimaryItemAttribute is StorageItemTypes.Folder)); + private bool isExecutable; + public bool IsExecutable => isExecutable; public OpenTerminalAction() { + isExecutable = GetIsExecutable(); context.PropertyChanged += Context_PropertyChanged; } - private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e) - { - OnPropertyChanged(nameof(IsExecutable)); - } - public Task ExecuteAsync() { var terminalStartInfo = GetProcessStartInfo(); @@ -67,7 +56,7 @@ public Task ExecuteAsync() protected virtual ProcessStartInfo? GetProcessStartInfo() { var paths = GetPaths(); - if (paths.Length == 0) + if (paths.Length is 0) return null; var path = paths[0] + (paths[0].EndsWith('\\') ? "\\" : ""); @@ -88,19 +77,43 @@ public Task ExecuteAsync() protected string[] GetPaths() { - var paths = context.ShellPage?.SlimContentPage?.SelectedItems? - .Where(item => item.PrimaryItemAttribute is StorageItemTypes.Folder) - .Select(item => item.ItemPath) - .ToArray(); - - if (paths is null || paths.Length == 0) + if (context.HasSelection) { - paths = context.ShellPage?.FilesystemViewModel.WorkingDirectory is not null - ? new string[1] { context.ShellPage!.FilesystemViewModel.WorkingDirectory } - : emptyStrings; + return context.SelectedItems! + .Where(item => item.PrimaryItemAttribute is StorageItemTypes.Folder) + .Select(item => item.ItemPath) + .ToArray(); } + else if (context.Folder is not null) + return new string[1] { context.Folder.ItemPath }; + + return Array.Empty(); + } + + private bool GetIsExecutable() + { + if (context.PageType is ContentPageTypes.None or ContentPageTypes.Home or ContentPageTypes.RecycleBin or ContentPageTypes.ZipFolder) + return false; + + if (!context.HasSelection) + return false; + + if (context.SelectedItems.Count > Constants.Actions.MaxSelectedItems) + return false; + + return context.SelectedItems.Any(item => item.PrimaryItemAttribute is StorageItemTypes.Folder); + } - return paths; + private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + switch (e.PropertyName) + { + case nameof(IContentPageContext.PageType): + case nameof(IContentPageContext.Folder): + case nameof(IContentPageContext.SelectedItems): + SetProperty(ref isExecutable, GetIsExecutable(), nameof(IsExecutable)); + break; + } } } } diff --git a/src/Files.App/Constants.cs b/src/Files.App/Constants.cs index 62436e8547c9..862dc60f9e3b 100644 --- a/src/Files.App/Constants.cs +++ b/src/Files.App/Constants.cs @@ -217,5 +217,10 @@ public static class GitHub public const string PrivacyPolicyUrl = @"https://github.com/files-community/Files/blob/main/Privacy.md"; public const string SupportUsUrl = @"https://github.com/sponsors/yaira2"; } + + public static class Actions + { + public const int MaxSelectedItems = 5; + } } } From 58d364ce56c409a54079cc8f02c4075dbc10a245 Mon Sep 17 00:00:00 2001 From: Filippo Ferrario Date: Mon, 20 Mar 2023 13:44:22 +0100 Subject: [PATCH 16/16] Open Parent Folder --- src/Files.App/Actions/Open/OpenTerminalAction.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Files.App/Actions/Open/OpenTerminalAction.cs b/src/Files.App/Actions/Open/OpenTerminalAction.cs index 52d2e03848d2..605965a62caa 100644 --- a/src/Files.App/Actions/Open/OpenTerminalAction.cs +++ b/src/Files.App/Actions/Open/OpenTerminalAction.cs @@ -95,13 +95,15 @@ private bool GetIsExecutable() if (context.PageType is ContentPageTypes.None or ContentPageTypes.Home or ContentPageTypes.RecycleBin or ContentPageTypes.ZipFolder) return false; - if (!context.HasSelection) + var isFolderNull = context.Folder is null; + + if (!context.HasSelection && isFolderNull) return false; if (context.SelectedItems.Count > Constants.Actions.MaxSelectedItems) return false; - return context.SelectedItems.Any(item => item.PrimaryItemAttribute is StorageItemTypes.Folder); + return context.SelectedItems.Any(item => item.PrimaryItemAttribute is StorageItemTypes.Folder) || !isFolderNull; } private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)