Main.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections.Generic; 7 using System.Linq; 8 using System.Windows.Controls; 9 using System.Windows.Input; 10 using System.Windows.Media; 11 using System.Windows.Media.Imaging; 12 13 using Microsoft.PowerToys.Run.Plugin.WindowsTerminal.Helpers; 14 using Microsoft.PowerToys.Run.Plugin.WindowsTerminal.Properties; 15 using Microsoft.PowerToys.Settings.UI.Library; 16 using Wox.Infrastructure; 17 using Wox.Plugin; 18 using Wox.Plugin.Logger; 19 20 namespace Microsoft.PowerToys.Run.Plugin.WindowsTerminal 21 { 22 public class Main : IPlugin, IContextMenu, IPluginI18n, ISettingProvider 23 { 24 private const string OpenNewTab = nameof(OpenNewTab); 25 private const string OpenQuake = nameof(OpenQuake); 26 private const string ShowHiddenProfiles = nameof(ShowHiddenProfiles); 27 private readonly TerminalQuery _terminalQuery = new TerminalQuery(); 28 private PluginInitContext _context; 29 private bool _openNewTab; 30 private bool _openQuake; 31 private bool _showHiddenProfiles; 32 private Dictionary<string, BitmapImage> _logoCache = new Dictionary<string, BitmapImage>(); 33 34 public string Name => Resources.plugin_name; 35 36 public string Description => Resources.plugin_description; 37 38 public static string PluginID => "F59BA85006B14389A72A0EA756695F1D"; 39 40 public IEnumerable<PluginAdditionalOption> AdditionalOptions => new List<PluginAdditionalOption>() 41 { 42 new PluginAdditionalOption() 43 { 44 Key = OpenNewTab, 45 DisplayLabel = Resources.open_new_tab, 46 Value = false, 47 }, 48 49 new PluginAdditionalOption() 50 { 51 Key = OpenQuake, 52 DisplayLabel = Resources.open_quake, 53 DisplayDescription = Resources.open_quake_description, 54 Value = false, 55 }, 56 57 new PluginAdditionalOption() 58 { 59 Key = ShowHiddenProfiles, 60 DisplayLabel = Resources.show_hidden_profiles, 61 Value = false, 62 }, 63 }; 64 65 public void Init(PluginInitContext context) 66 { 67 _context = context; 68 } 69 70 public List<Result> Query(Query query) 71 { 72 var search = query?.Search ?? string.Empty; 73 var profiles = _terminalQuery.GetProfiles(); 74 75 var result = new List<Result>(); 76 77 foreach (var profile in profiles) 78 { 79 if (profile.Hidden && !_showHiddenProfiles) 80 { 81 continue; 82 } 83 84 // Action keyword only or search query match 85 int score = StringMatcher.FuzzySearch(search, profile.Name).Score; 86 if (string.IsNullOrWhiteSpace(search) || score > 0) 87 { 88 result.Add(new Result 89 { 90 Title = profile.Name, 91 SubTitle = profile.Terminal.DisplayName, 92 Icon = () => GetLogo(profile.Terminal), 93 Score = score, 94 Action = _ => 95 { 96 Launch(profile.Terminal.AppUserModelId, profile.Name); 97 return true; 98 }, 99 ContextData = profile, 100 }); 101 } 102 } 103 104 return result; 105 } 106 107 public List<ContextMenuResult> LoadContextMenus(Result selectedResult) 108 { 109 if (!(selectedResult?.ContextData is TerminalProfile)) 110 { 111 return new List<ContextMenuResult>(); 112 } 113 114 var result = new List<ContextMenuResult>(); 115 116 if (selectedResult.ContextData is TerminalProfile profile) 117 { 118 result.Add(new ContextMenuResult 119 { 120 Title = Resources.run_as_administrator, 121 Glyph = "\xE7EF", 122 FontFamily = "Segoe Fluent Icons,Segoe MDL2 Assets", 123 AcceleratorKey = Key.Enter, 124 AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift, 125 Action = _ => 126 { 127 LaunchElevated(profile.Terminal.AppUserModelId, profile.Name); 128 return true; 129 }, 130 }); 131 } 132 133 return result; 134 } 135 136 public string GetTranslatedPluginTitle() 137 { 138 return Resources.plugin_name; 139 } 140 141 public string GetTranslatedPluginDescription() 142 { 143 return Resources.plugin_description; 144 } 145 146 private void Launch(string id, string profile) 147 { 148 var appManager = new ApplicationActivationManager(); 149 const ActivateOptions noFlags = ActivateOptions.None; 150 var queryArguments = TerminalHelper.GetArguments(profile, _openNewTab, _openQuake); 151 try 152 { 153 appManager.ActivateApplication(id, queryArguments, noFlags, out var unusedPid); 154 } 155 catch (Exception ex) 156 { 157 var name = "Plugin: " + Resources.plugin_name; 158 var message = Resources.run_terminal_failed; 159 Log.Exception("Failed to open Windows Terminal", ex, GetType()); 160 _context.API.ShowMsg(name, message, string.Empty); 161 } 162 } 163 164 private void LaunchElevated(string id, string profile) 165 { 166 try 167 { 168 string path = "shell:AppsFolder\\" + id; 169 Helper.OpenInShell(path, TerminalHelper.GetArguments(profile, _openNewTab, _openQuake), runAs: Helper.ShellRunAsType.Administrator); 170 } 171 catch (Exception ex) 172 { 173 var name = "Plugin: " + Resources.plugin_name; 174 var message = Resources.run_terminal_failed; 175 Log.Exception("Failed to open Windows Terminal", ex, GetType()); 176 _context.API.ShowMsg(name, message, string.Empty); 177 } 178 } 179 180 public Control CreateSettingPanel() 181 { 182 throw new NotImplementedException(); 183 } 184 185 public void UpdateSettings(PowerLauncherPluginSettings settings) 186 { 187 var openNewTab = false; 188 var openQuake = false; 189 var showHiddenProfiles = false; 190 191 if (settings != null && settings.AdditionalOptions != null) 192 { 193 openNewTab = settings.AdditionalOptions.FirstOrDefault(x => x.Key == OpenNewTab)?.Value ?? false; 194 openQuake = settings.AdditionalOptions.FirstOrDefault(x => x.Key == OpenQuake)?.Value ?? false; 195 showHiddenProfiles = settings.AdditionalOptions.FirstOrDefault(x => x.Key == ShowHiddenProfiles)?.Value ?? false; 196 } 197 198 _openNewTab = openNewTab; 199 _openQuake = openQuake; 200 _showHiddenProfiles = showHiddenProfiles; 201 } 202 203 private BitmapImage GetLogo(TerminalPackage terminal) 204 { 205 var aumid = terminal.AppUserModelId; 206 207 if (!_logoCache.TryGetValue(aumid, out BitmapImage value)) 208 { 209 value = terminal.GetLogo(); 210 _logoCache.Add(aumid, value); 211 } 212 213 return value; 214 } 215 } 216 }