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  }