[PowerToys Run] Plugin manager (#9872)

This commit is contained in:
Mykhailo Pylyp 2021-02-26 13:21:58 +02:00 committed by GitHub
parent f839a408de
commit 4a9e920a1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 749 additions and 276 deletions

View file

@ -15,7 +15,7 @@ using Wox.Plugin;
namespace Microsoft.Plugin.Folder namespace Microsoft.Plugin.Folder
{ {
public class Main : IPlugin, ISettingProvider, IPluginI18n, ISavable, IContextMenu, IDisposable public class Main : IPlugin, IPluginI18n, ISavable, IContextMenu, IDisposable
{ {
public const string FolderImagePath = "Images\\folder.dark.png"; public const string FolderImagePath = "Images\\folder.dark.png";
public const string FileImagePath = "Images\\file.dark.png"; public const string FileImagePath = "Images\\file.dark.png";
@ -38,6 +38,10 @@ namespace Microsoft.Plugin.Folder
private IContextMenu _contextMenuLoader; private IContextMenu _contextMenuLoader;
private bool _disposed; private bool _disposed;
public string Name => Properties.Resources.wox_plugin_folder_plugin_name;
public string Description => Properties.Resources.wox_plugin_folder_plugin_description;
public void Save() public void Save()
{ {
_storage.Save(); _storage.Save();
@ -119,10 +123,6 @@ namespace Microsoft.Plugin.Folder
return _contextMenuLoader.LoadContextMenus(selectedResult); return _contextMenuLoader.LoadContextMenus(selectedResult);
} }
public void UpdateSettings(PowerLauncherSettings settings)
{
}
public void Dispose() public void Dispose()
{ {
Dispose(disposing: true); Dispose(disposing: true);

View file

@ -124,7 +124,7 @@ namespace Microsoft.Plugin.Folder.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Open favorite folder from PowerToys Run directly. /// Looks up a localized string similar to Navigates folders starting from a drive letter &apos;C:\&apos; or from the user home &apos;~&apos;..
/// </summary> /// </summary>
public static string wox_plugin_folder_plugin_description { public static string wox_plugin_folder_plugin_description {
get { get {

View file

@ -121,7 +121,7 @@
<value>Folder</value> <value>Folder</value>
</data> </data>
<data name="wox_plugin_folder_plugin_description" xml:space="preserve"> <data name="wox_plugin_folder_plugin_description" xml:space="preserve">
<value>Open favorite folder from PowerToys Run directly</value> <value>Navigates folders starting from a drive letter 'C:\' or from the user home '~'.</value>
</data> </data>
<data name="Microsoft_plugin_folder_copy_path" xml:space="preserve"> <data name="Microsoft_plugin_folder_copy_path" xml:space="preserve">
<value>Copy path (Ctrl+C)</value> <value>Copy path (Ctrl+C)</value>

View file

@ -3,7 +3,6 @@
"ActionKeyword": "", "ActionKeyword": "",
"IsGlobal": true, "IsGlobal": true,
"Name": "Folder", "Name": "Folder",
"Description": "Search and open folders",
"Author": "qianlifeng", "Author": "qianlifeng",
"Version": "1.0.0", "Version": "1.0.0",
"Language": "csharp", "Language": "csharp",

View file

@ -23,6 +23,7 @@ namespace Microsoft.Plugin.Indexer
{ {
internal class Main : ISettingProvider, IPlugin, ISavable, IPluginI18n, IContextMenu, IDisposable, IDelayedExecutionPlugin internal class Main : ISettingProvider, IPlugin, ISavable, IPluginI18n, IContextMenu, IDisposable, IDelayedExecutionPlugin
{ {
private const string DisableDriveDetectionWarning = nameof(DisableDriveDetectionWarning);
private static readonly IFileSystem _fileSystem = new FileSystem(); private static readonly IFileSystem _fileSystem = new FileSystem();
// This variable contains metadata about the Plugin // This variable contains metadata about the Plugin
@ -46,6 +47,20 @@ namespace Microsoft.Plugin.Indexer
private string WarningIconPath { get; set; } private string WarningIconPath { get; set; }
public string Name => Properties.Resources.Microsoft_plugin_indexer_plugin_name;
public string Description => Properties.Resources.Microsoft_plugin_indexer_plugin_description;
public IEnumerable<PluginAdditionalOption> AdditionalOptions => new List<PluginAdditionalOption>()
{
new PluginAdditionalOption()
{
Key = DisableDriveDetectionWarning,
DisplayLabel = Properties.Resources.disable_drive_detection_warning,
Value = false,
},
};
private IContextMenu _contextMenuLoader; private IContextMenu _contextMenuLoader;
private bool disposedValue; private bool disposedValue;
@ -210,9 +225,10 @@ namespace Microsoft.Plugin.Indexer
return _contextMenuLoader.LoadContextMenus(selectedResult); return _contextMenuLoader.LoadContextMenus(selectedResult);
} }
public void UpdateSettings(PowerLauncherSettings settings) public void UpdateSettings(PowerLauncherPluginSettings settings)
{ {
_driveDetection.IsDriveDetectionWarningCheckBoxSelected = settings.Properties.DisableDriveDetectionWarning; var option = settings.AdditionalOptions.FirstOrDefault(x => x.Key == DisableDriveDetectionWarning);
_driveDetection.IsDriveDetectionWarningCheckBoxSelected = option == null ? false : option.Value;
} }
public Control CreateSettingPanel() public Control CreateSettingPanel()

View file

@ -60,6 +60,15 @@ namespace Microsoft.Plugin.Indexer.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to Disable drive detection warning.
/// </summary>
public static string disable_drive_detection_warning {
get {
return ResourceManager.GetString("disable_drive_detection_warning", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Fail to set text in clipboard. /// Looks up a localized string similar to Fail to set text in clipboard.
/// </summary> /// </summary>
@ -151,7 +160,7 @@ namespace Microsoft.Plugin.Indexer.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Returns files and folders. /// Looks up a localized string similar to Searches files and folders..
/// </summary> /// </summary>
public static string Microsoft_plugin_indexer_plugin_description { public static string Microsoft_plugin_indexer_plugin_description {
get { get {
@ -160,7 +169,7 @@ namespace Microsoft.Plugin.Indexer.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Windows Indexer. /// Looks up a localized string similar to Windows Search.
/// </summary> /// </summary>
public static string Microsoft_plugin_indexer_plugin_name { public static string Microsoft_plugin_indexer_plugin_name {
get { get {

View file

@ -151,12 +151,15 @@
<value>Fail to open folder at</value> <value>Fail to open folder at</value>
</data> </data>
<data name="Microsoft_plugin_indexer_plugin_description" xml:space="preserve"> <data name="Microsoft_plugin_indexer_plugin_description" xml:space="preserve">
<value>Returns files and folders</value> <value>Searches files and folders.</value>
</data> </data>
<data name="Microsoft_plugin_indexer_plugin_name" xml:space="preserve"> <data name="Microsoft_plugin_indexer_plugin_name" xml:space="preserve">
<value>Windows Indexer</value> <value>Windows Search</value>
</data> </data>
<data name="Microsoft_plugin_indexer_subtitle_header" xml:space="preserve"> <data name="Microsoft_plugin_indexer_subtitle_header" xml:space="preserve">
<value>Search</value> <value>Search</value>
</data> </data>
<data name="disable_drive_detection_warning" xml:space="preserve">
<value>Disable drive detection warning</value>
</data>
</root> </root>

View file

@ -3,7 +3,6 @@
"ActionKeyword": "?", "ActionKeyword": "?",
"IsGlobal": true, "IsGlobal": true,
"Name": "Windows Indexer", "Name": "Windows Indexer",
"Description": "Search for files and folders",
"Author": "Microsoft", "Author": "Microsoft",
"Version": "1.0.0", "Version": "1.0.0",
"Language": "csharp", "Language": "csharp",

View file

@ -32,10 +32,7 @@ namespace Microsoft.Plugin.Program.UnitTests.ProgramArgumentParser
new NoArgumentsArgumentParser(), new NoArgumentsArgumentParser(),
}; };
// basic version of the Quey parser which can be found at Wox.Core.Plugin.QueryBuilder but did not want to create a project reference var query = new Query(inputQuery);
var splittedSearchString = inputQuery?.Split(Query.TermSeparator, System.StringSplitOptions.RemoveEmptyEntries);
var cleanQuery = string.Join(Query.TermSeparator, splittedSearchString);
var query = new Query(cleanQuery, cleanQuery, new ReadOnlyCollection<string>(splittedSearchString), string.Empty);
// Act // Act
string program = null, programArguments = null; string program = null, programArguments = null;

View file

@ -32,6 +32,10 @@ namespace Microsoft.Plugin.Program
internal static ProgramPluginSettings Settings { get; set; } internal static ProgramPluginSettings Settings { get; set; }
public string Name => Properties.Resources.wox_plugin_program_plugin_name;
public string Description => Properties.Resources.wox_plugin_program_plugin_description;
private static PluginInitContext _context; private static PluginInitContext _context;
private readonly PluginJsonStorage<ProgramPluginSettings> _settingsStorage; private readonly PluginJsonStorage<ProgramPluginSettings> _settingsStorage;
private bool _disposed; private bool _disposed;

View file

@ -178,7 +178,7 @@ namespace Microsoft.Plugin.Program.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Search programs in PowerToys Run. /// Looks up a localized string similar to Searches programs..
/// </summary> /// </summary>
public static string wox_plugin_program_plugin_description { public static string wox_plugin_program_plugin_description {
get { get {

View file

@ -130,7 +130,7 @@
<value>Program</value> <value>Program</value>
</data> </data>
<data name="wox_plugin_program_plugin_description" xml:space="preserve"> <data name="wox_plugin_program_plugin_description" xml:space="preserve">
<value>Search programs in PowerToys Run</value> <value>Searches programs.</value>
</data> </data>
<data name="powertoys_run_plugin_program_win32_application" xml:space="preserve"> <data name="powertoys_run_plugin_program_win32_application" xml:space="preserve">
<value>Application</value> <value>Application</value>

View file

@ -3,7 +3,6 @@
"ActionKeyword": ".", "ActionKeyword": ".",
"IsGlobal": true, "IsGlobal": true,
"Name": "Program", "Name": "Program",
"Description": "Search for programs",
"Author": "qianlifeng", "Author": "qianlifeng",
"Version": "1.0.0", "Version": "1.0.0",
"Language": "csharp", "Language": "csharp",

View file

@ -22,7 +22,7 @@ using Control = System.Windows.Controls.Control;
namespace Microsoft.Plugin.Shell namespace Microsoft.Plugin.Shell
{ {
public class Main : IPlugin, ISettingProvider, IPluginI18n, IContextMenu, ISavable public class Main : IPlugin, IPluginI18n, IContextMenu, ISavable
{ {
private static readonly IFileSystem FileSystem = new FileSystem(); private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IPath Path = FileSystem.Path; private static readonly IPath Path = FileSystem.Path;
@ -34,6 +34,10 @@ namespace Microsoft.Plugin.Shell
private string IconPath { get; set; } private string IconPath { get; set; }
public string Name => Properties.Resources.wox_plugin_cmd_plugin_name;
public string Description => Properties.Resources.wox_plugin_cmd_plugin_description;
private PluginInitContext _context; private PluginInitContext _context;
public Main() public Main()
@ -331,9 +335,5 @@ namespace Microsoft.Plugin.Shell
return resultlist; return resultlist;
} }
public void UpdateSettings(PowerLauncherSettings settings)
{
}
} }
} }

View file

@ -97,7 +97,7 @@ namespace Microsoft.Plugin.Shell.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Allows to execute system commands from PowerToys Run. Commands should start with &gt;. /// Looks up a localized string similar to Executes commands (e.g &apos;ping&apos;, &apos;cmd&apos;)..
/// </summary> /// </summary>
public static string wox_plugin_cmd_plugin_description { public static string wox_plugin_cmd_plugin_description {
get { get {

View file

@ -121,7 +121,7 @@
<value>Shell</value> <value>Shell</value>
</data> </data>
<data name="wox_plugin_cmd_plugin_description" xml:space="preserve"> <data name="wox_plugin_cmd_plugin_description" xml:space="preserve">
<value>Allows to execute system commands from PowerToys Run. Commands should start with &gt;</value> <value>Executes commands (e.g 'ping', 'cmd').</value>
</data> </data>
<data name="wox_plugin_cmd_cmd_has_been_executed_times" xml:space="preserve"> <data name="wox_plugin_cmd_cmd_has_been_executed_times" xml:space="preserve">
<value>this command has been executed {0} times</value> <value>this command has been executed {0} times</value>

View file

@ -3,7 +3,6 @@
"ActionKeyword": ">", "ActionKeyword": ">",
"IsGlobal": false, "IsGlobal": false,
"Name": "Shell", "Name": "Shell",
"Description": "Provide executing commands. Commands should start with >",
"Author": "qianlifeng", "Author": "qianlifeng",
"Version": "1.0.0", "Version": "1.0.0",
"Language": "csharp", "Language": "csharp",

View file

@ -43,6 +43,10 @@ namespace Microsoft.Plugin.Uri
public PluginInitContext Context { get; protected set; } public PluginInitContext Context { get; protected set; }
public string Name => Properties.Resources.Microsoft_plugin_uri_plugin_name;
public string Description => Properties.Resources.Microsoft_plugin_uri_plugin_description;
public List<ContextMenuResult> LoadContextMenus(Result selectedResult) public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
{ {
return new List<ContextMenuResult>(0); return new List<ContextMenuResult>(0);

View file

@ -70,7 +70,7 @@ namespace Microsoft.Plugin.Uri.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Handles urls. /// Looks up a localized string similar to Opens URLs and UNC network shares..
/// </summary> /// </summary>
public static string Microsoft_plugin_uri_plugin_description { public static string Microsoft_plugin_uri_plugin_description {
get { get {
@ -79,7 +79,7 @@ namespace Microsoft.Plugin.Uri.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Url Handler. /// Looks up a localized string similar to URI Handler.
/// </summary> /// </summary>
public static string Microsoft_plugin_uri_plugin_name { public static string Microsoft_plugin_uri_plugin_name {
get { get {

View file

@ -121,10 +121,10 @@
<value>Failed to open URL</value> <value>Failed to open URL</value>
</data> </data>
<data name="Microsoft_plugin_uri_plugin_description" xml:space="preserve"> <data name="Microsoft_plugin_uri_plugin_description" xml:space="preserve">
<value>Handles urls</value> <value>Opens URLs and UNC network shares.</value>
</data> </data>
<data name="Microsoft_plugin_uri_plugin_name" xml:space="preserve"> <data name="Microsoft_plugin_uri_plugin_name" xml:space="preserve">
<value>Url Handler</value> <value>URI Handler</value>
</data> </data>
<data name="Microsoft_plugin_uri_website" xml:space="preserve"> <data name="Microsoft_plugin_uri_website" xml:space="preserve">
<value>Open in browser</value> <value>Open in browser</value>

View file

@ -3,7 +3,6 @@
"ActionKeyword": "//", "ActionKeyword": "//",
"IsGlobal": true, "IsGlobal": true,
"Name": "Windows Uri Handler", "Name": "Windows Uri Handler",
"Description": "Handles urls",
"Author": "Microsoft", "Author": "Microsoft",
"Version": "1.0.0", "Version": "1.0.0",
"Language": "csharp", "Language": "csharp",

View file

@ -19,6 +19,10 @@ namespace Microsoft.Plugin.WindowWalker
private PluginInitContext Context { get; set; } private PluginInitContext Context { get; set; }
public string Name => Properties.Resources.wox_plugin_windowwalker_plugin_name;
public string Description => Properties.Resources.wox_plugin_windowwalker_plugin_description;
static Main() static Main()
{ {
SearchController.Instance.OnSearchResultUpdateEventHandler += SearchResultUpdated; SearchController.Instance.OnSearchResultUpdateEventHandler += SearchResultUpdated;

View file

@ -61,7 +61,7 @@ namespace Microsoft.Plugin.WindowWalker.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Alt-Tab alternative enabling searching through your windows.. /// Looks up a localized string similar to Switches between open windows..
/// </summary> /// </summary>
public static string wox_plugin_windowwalker_plugin_description { public static string wox_plugin_windowwalker_plugin_description {
get { get {

View file

@ -121,7 +121,7 @@
<value>Window Walker</value> <value>Window Walker</value>
</data> </data>
<data name="wox_plugin_windowwalker_plugin_description" xml:space="preserve"> <data name="wox_plugin_windowwalker_plugin_description" xml:space="preserve">
<value>Alt-Tab alternative enabling searching through your windows.</value> <value>Switches between open windows.</value>
</data> </data>
<data name="wox_plugin_windowwalker_running" xml:space="preserve"> <data name="wox_plugin_windowwalker_running" xml:space="preserve">
<value>Running</value> <value>Running</value>

View file

@ -3,7 +3,6 @@
"ActionKeyword": "<", "ActionKeyword": "<",
"IsGlobal": true, "IsGlobal": true,
"Name": "Window Walker", "Name": "Window Walker",
"Description": "Alt-Tab alternative enabling searching through your windows.",
"Author": "betadele", "Author": "betadele",
"Version": "1.0.0", "Version": "1.0.0",
"Language": "csharp", "Language": "csharp",

View file

@ -19,6 +19,10 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator
private string IconPath { get; set; } private string IconPath { get; set; }
public string Name => Properties.Resources.wox_plugin_calculator_plugin_name;
public string Description => Properties.Resources.wox_plugin_calculator_plugin_description;
private bool _disposed; private bool _disposed;
public List<Result> Query(Query query) public List<Result> Query(Query query)

View file

@ -9,6 +9,9 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace Microsoft.PowerToys.Run.Plugin.Calculator.Properties { namespace Microsoft.PowerToys.Run.Plugin.Calculator.Properties {
using System;
/// <summary> /// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc. /// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary> /// </summary>
@ -20,15 +23,15 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator.Properties {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Resources { public class Resources {
private static global::System.Resources.ResourceManager resourceMan; private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture; private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() { internal Resources() {
} }
/// <summary> /// <summary>
/// Returns the cached ResourceManager instance used by this class. /// Returns the cached ResourceManager instance used by this class.
/// </summary> /// </summary>
@ -42,7 +45,7 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator.Properties {
return resourceMan; return resourceMan;
} }
} }
/// <summary> /// <summary>
/// Overrides the current thread's CurrentUICulture property for all /// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class. /// resource lookups using this strongly typed resource class.
@ -56,7 +59,7 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator.Properties {
resourceCulture = value; resourceCulture = value;
} }
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Copy failed, please try later. /// Looks up a localized string similar to Copy failed, please try later.
/// </summary> /// </summary>
@ -65,7 +68,7 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator.Properties {
return ResourceManager.GetString("wox_plugin_calculator_copy_failed", resourceCulture); return ResourceManager.GetString("wox_plugin_calculator_copy_failed", resourceCulture);
} }
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Copy this number to the clipboard. /// Looks up a localized string similar to Copy this number to the clipboard.
/// </summary> /// </summary>
@ -74,7 +77,7 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator.Properties {
return ResourceManager.GetString("wox_plugin_calculator_copy_number_to_clipboard", resourceCulture); return ResourceManager.GetString("wox_plugin_calculator_copy_number_to_clipboard", resourceCulture);
} }
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Expression wrong or incomplete (Did you forget some parentheses?). /// Looks up a localized string similar to Expression wrong or incomplete (Did you forget some parentheses?).
/// </summary> /// </summary>
@ -83,7 +86,7 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator.Properties {
return ResourceManager.GetString("wox_plugin_calculator_expression_not_complete", resourceCulture); return ResourceManager.GetString("wox_plugin_calculator_expression_not_complete", resourceCulture);
} }
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Not a number (NaN). /// Looks up a localized string similar to Not a number (NaN).
/// </summary> /// </summary>
@ -92,16 +95,16 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator.Properties {
return ResourceManager.GetString("wox_plugin_calculator_not_a_number", resourceCulture); return ResourceManager.GetString("wox_plugin_calculator_not_a_number", resourceCulture);
} }
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Allows you to do mathematical calculations. (Try 5*3-2 in PowerToys Run). /// Looks up a localized string similar to Does mathematical calculations (e.g. 5*3-2)..
/// </summary> /// </summary>
public static string wox_plugin_calculator_plugin_description { public static string wox_plugin_calculator_plugin_description {
get { get {
return ResourceManager.GetString("wox_plugin_calculator_plugin_description", resourceCulture); return ResourceManager.GetString("wox_plugin_calculator_plugin_description", resourceCulture);
} }
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Calculator. /// Looks up a localized string similar to Calculator.
/// </summary> /// </summary>

View file

@ -121,7 +121,7 @@
<value>Calculator</value> <value>Calculator</value>
</data> </data>
<data name="wox_plugin_calculator_plugin_description" xml:space="preserve"> <data name="wox_plugin_calculator_plugin_description" xml:space="preserve">
<value>Allows you to do mathematical calculations. (Try 5*3-2 in PowerToys Run)</value> <value>Does mathematical calculations (e.g. 5*3-2).</value>
</data> </data>
<data name="wox_plugin_calculator_not_a_number" xml:space="preserve"> <data name="wox_plugin_calculator_not_a_number" xml:space="preserve">
<value>Not a number (NaN)</value> <value>Not a number (NaN)</value>

View file

@ -3,7 +3,6 @@
"ActionKeyword": "=", "ActionKeyword": "=",
"IsGlobal": true, "IsGlobal": true,
"Name": "Calculator", "Name": "Calculator",
"Description": "Provide mathematical calculations.(Try 5*3-2 in PowerToys)",
"Author": "cxfksword", "Author": "cxfksword",
"Version": "1.0.0", "Version": "1.0.0",
"Language": "csharp", "Language": "csharp",

View file

@ -42,6 +42,10 @@ namespace Microsoft.PowerToys.Run.Plugin.Registry
/// </summary> /// </summary>
private bool _disposed; private bool _disposed;
public string Name => Resources.PluginTitle;
public string Description => Resources.PluginDescription;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Main"/> class. /// Initializes a new instance of the <see cref="Main"/> class.
/// </summary> /// </summary>

View file

@ -133,7 +133,7 @@ namespace Microsoft.PowerToys.Run.Plugin.Registry.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Search inside the Windows Registry. /// Looks up a localized string similar to Navigates inside the Windows Registry..
/// </summary> /// </summary>
internal static string PluginDescription { internal static string PluginDescription {
get { get {

View file

@ -121,7 +121,7 @@
<value>Registry Plugin</value> <value>Registry Plugin</value>
</data> </data>
<data name="PluginDescription" xml:space="preserve"> <data name="PluginDescription" xml:space="preserve">
<value>Search inside the Windows Registry</value> <value>Navigates inside the Windows Registry.</value>
<comment>"this built into Windows the OS. translate accordingly, https://docs.microsoft.com/de-de/troubleshoot/windows-server/performance/windows-registry-advanced-users is an example of it translated in German"</comment> <comment>"this built into Windows the OS. translate accordingly, https://docs.microsoft.com/de-de/troubleshoot/windows-server/performance/windows-registry-advanced-users is an example of it translated in German"</comment>
</data> </data>
<data name="CopyKeyNamePath" xml:space="preserve"> <data name="CopyKeyNamePath" xml:space="preserve">

View file

@ -3,7 +3,6 @@
"ActionKeyword": ":", "ActionKeyword": ":",
"IsGlobal": false, "IsGlobal": false,
"Name": "Registry", "Name": "Registry",
"Description": "Search inside the Windows Registry",
"Author": "TobiasSekan", "Author": "TobiasSekan",
"Version": "1.0.0", "Version": "1.0.0",
"Language": "csharp", "Language": "csharp",

View file

@ -19,6 +19,10 @@ namespace Microsoft.PowerToys.Run.Plugin.Service
private PluginInitContext _context; private PluginInitContext _context;
private string _icoPath; private string _icoPath;
public string Name => Resources.wox_plugin_service_plugin_name;
public string Description => Resources.wox_plugin_service_plugin_description;
public void Init(PluginInitContext context) public void Init(PluginInitContext context)
{ {
_context = context; _context = context;

View file

@ -97,7 +97,7 @@ namespace Microsoft.PowerToys.Run.Plugin.Service.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Manages Windows services. /// Looks up a localized string similar to Manages Windows services..
/// </summary> /// </summary>
internal static string wox_plugin_service_plugin_description { internal static string wox_plugin_service_plugin_description {
get { get {

View file

@ -130,7 +130,7 @@
<value>Pausing</value> <value>Pausing</value>
</data> </data>
<data name="wox_plugin_service_plugin_description" xml:space="preserve"> <data name="wox_plugin_service_plugin_description" xml:space="preserve">
<value>Manages Windows services</value> <value>Manages Windows services.</value>
</data> </data>
<data name="wox_plugin_service_plugin_name" xml:space="preserve"> <data name="wox_plugin_service_plugin_name" xml:space="preserve">
<value>Service</value> <value>Service</value>

View file

@ -3,7 +3,6 @@
"ActionKeyword": "!", "ActionKeyword": "!",
"IsGlobal": false, "IsGlobal": false,
"Name": "Service", "Name": "Service",
"Description": "Manages Windows services",
"Author": "davidegiacometti", "Author": "davidegiacometti",
"Version": "1.0.0", "Version": "1.0.0",
"Language": "csharp", "Language": "csharp",

View file

@ -32,8 +32,7 @@ namespace Microsoft.PowerToys.Run.Plugin.System.UnitTests
// Setup // Setup
Mock<Main> main = new Mock<Main>(); Mock<Main> main = new Mock<Main>();
main.Object.IconTheme = "dark"; main.Object.IconTheme = "dark";
string[] terms = { typedString }; Query expectedQuery = new Query(typedString);
Query expectedQuery = new Query(typedString, typedString, new ReadOnlyCollection<string>(terms), string.Empty);
// Act // Act
var result = main.Object.Query(expectedQuery).FirstOrDefault().IcoPath; var result = main.Object.Query(expectedQuery).FirstOrDefault().IcoPath;
@ -54,8 +53,7 @@ namespace Microsoft.PowerToys.Run.Plugin.System.UnitTests
// Setup // Setup
Mock<Main> main = new Mock<Main>(); Mock<Main> main = new Mock<Main>();
main.Object.IconTheme = "light"; main.Object.IconTheme = "light";
string[] terms = { typedString }; Query expectedQuery = new Query(typedString);
Query expectedQuery = new Query(typedString, typedString, new ReadOnlyCollection<string>(terms), string.Empty);
// Act // Act
var result = main.Object.Query(expectedQuery).FirstOrDefault().IcoPath; var result = main.Object.Query(expectedQuery).FirstOrDefault().IcoPath;

View file

@ -30,8 +30,7 @@ namespace Microsoft.PowerToys.Run.Plugin.System.UnitTests
{ {
// Setup // Setup
Mock<Main> main = new Mock<Main>(); Mock<Main> main = new Mock<Main>();
string[] terms = { typedString }; Query expectedQuery = new Query(typedString);
Query expectedQuery = new Query(typedString, typedString, new ReadOnlyCollection<string>(terms), string.Empty);
// Act // Act
var result = main.Object.Query(expectedQuery).FirstOrDefault().SubTitle; var result = main.Object.Query(expectedQuery).FirstOrDefault().SubTitle;

View file

@ -26,6 +26,10 @@ namespace Microsoft.PowerToys.Run.Plugin.System
public string IconTheme { get; set; } public string IconTheme { get; set; }
public string Name => Properties.Resources.Microsoft_plugin_sys_plugin_name;
public string Description => Properties.Resources.Microsoft_plugin_sys_plugin_description;
public void Init(PluginInitContext context) public void Init(PluginInitContext context)
{ {
this._context = context; this._context = context;

View file

@ -115,7 +115,7 @@ namespace Microsoft.PowerToys.Run.Plugin.System.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Provides Windows related commands, shutdown, lock, sleep ..... /// Looks up a localized string similar to Executes system commands (e.g. &apos;shutdown&apos;, &apos;lock&apos;, &apos;sleep&apos;)..
/// </summary> /// </summary>
internal static string Microsoft_plugin_sys_plugin_description { internal static string Microsoft_plugin_sys_plugin_description {
get { get {

View file

@ -142,7 +142,7 @@
<comment>This should align to the action in Windows of a locking your computer.</comment> <comment>This should align to the action in Windows of a locking your computer.</comment>
</data> </data>
<data name="Microsoft_plugin_sys_plugin_description" xml:space="preserve"> <data name="Microsoft_plugin_sys_plugin_description" xml:space="preserve">
<value>Provides Windows related commands, shutdown, lock, sleep ....</value> <value>Executes system commands (e.g. 'shutdown', 'lock', 'sleep').</value>
<comment>This should align to the actions in Windows relating to shutting down, signing out, locking, sleeping, restarting, emptying the recycle bin, and hibernating your computer. </comment> <comment>This should align to the actions in Windows relating to shutting down, signing out, locking, sleeping, restarting, emptying the recycle bin, and hibernating your computer. </comment>
</data> </data>
<data name="Microsoft_plugin_sys_plugin_name" xml:space="preserve"> <data name="Microsoft_plugin_sys_plugin_name" xml:space="preserve">

View file

@ -3,7 +3,6 @@
"ActionKeyword": "", "ActionKeyword": "",
"IsGlobal": true, "IsGlobal": true,
"Name": "System Commands", "Name": "System Commands",
"Description": "Provide System related commands. e.g. shutdown,lock,setting etc.",
"Author": "Wox", "Author": "Wox",
"Version": "1.0.0", "Version": "1.0.0",
"Language": "csharp", "Language": "csharp",

View file

@ -12,7 +12,6 @@ using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Wox.Infrastructure; using Wox.Infrastructure;
using Wox.Infrastructure.Storage; using Wox.Infrastructure.Storage;
using Wox.Infrastructure.UserSettings;
using Wox.Plugin; using Wox.Plugin;
using Wox.Plugin.Logger; using Wox.Plugin.Logger;
@ -62,15 +61,11 @@ namespace PowerLauncher.Plugin
} }
} }
public static Dictionary<string, PluginPair> NonGlobalPlugins public static IEnumerable<PluginPair> NonGlobalPlugins
{ {
get get
{ {
return AllPlugins return AllPlugins.Where(x => !string.IsNullOrWhiteSpace(x.Metadata.ActionKeyword));
.Where(x => !string.IsNullOrWhiteSpace(x.Metadata.ActionKeyword))
.GroupBy(x => x.Metadata.ActionKeyword)
.Select(x => x.First())
.ToDictionary(x => x.Metadata.ActionKeyword);
} }
} }

View file

@ -4,66 +4,34 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Mono.Collections.Generic;
using Wox.Plugin; using Wox.Plugin;
namespace PowerLauncher.Plugin namespace PowerLauncher.Plugin
{ {
public static class QueryBuilder public static class QueryBuilder
{ {
public static Dictionary<PluginPair, Query> Build(ref string text) public static Dictionary<PluginPair, Query> Build(string text)
{ {
if (text == null) if (text == null)
{ {
throw new ArgumentNullException(nameof(text)); throw new ArgumentNullException(nameof(text));
} }
// replace multiple white spaces with one white space text = text.Trim();
var terms = text.Split(new[] { Query.TermSeparator }, StringSplitOptions.RemoveEmptyEntries);
if (terms.Length == 0)
{ // nothing was typed
return null;
}
// This Dictionary contains the corresponding query for each plugin // This Dictionary contains the corresponding query for each plugin
Dictionary<PluginPair, Query> pluginQueryPair = new Dictionary<PluginPair, Query>(); Dictionary<PluginPair, Query> pluginQueryPair = new Dictionary<PluginPair, Query>();
foreach (var plugin in PluginManager.NonGlobalPlugins)
var rawQuery = string.Join(Query.TermSeparator, terms);
// This is the query on removing extra spaces which would be executed by global Plugins
text = rawQuery;
string possibleActionKeyword = terms[0];
foreach (string pluginActionKeyword in PluginManager.NonGlobalPlugins.Keys)
{ {
// Using Ordinal since this is used internally var pluginActionKeyword = plugin.Metadata.ActionKeyword;
if (possibleActionKeyword.StartsWith(pluginActionKeyword, StringComparison.Ordinal)) if (plugin.Metadata.Disabled || !text.StartsWith(pluginActionKeyword, StringComparison.Ordinal))
{ {
if (PluginManager.NonGlobalPlugins.TryGetValue(pluginActionKeyword, out var pluginPair) && !pluginPair.Metadata.Disabled) continue;
{
// The search string is the raw query excluding the action keyword
string search = rawQuery.Substring(pluginActionKeyword.Length).Trim();
// To set the terms of the query after removing the action keyword
if (possibleActionKeyword.Length > pluginActionKeyword.Length)
{
// If the first term contains the action keyword, then set the remaining string to be the first term
terms[0] = possibleActionKeyword.Substring(pluginActionKeyword.Length);
}
else
{
// If the first term is the action keyword, then skip it.
terms = terms.Skip(1).ToArray();
}
// A new query is constructed for each plugin as they have different action keywords
var query = new Query(rawQuery, search, new ReadOnlyCollection<string>(terms), pluginActionKeyword);
pluginQueryPair.TryAdd(pluginPair, query);
}
} }
// A new query is constructed for each plugin
var query = new Query(text, pluginActionKeyword);
pluginQueryPair.TryAdd(plugin, query);
} }
// If the user has specified a matching action keyword, then do not // If the user has specified a matching action keyword, then do not
@ -72,9 +40,9 @@ namespace PowerLauncher.Plugin
{ {
foreach (PluginPair globalPlugin in PluginManager.GlobalPlugins) foreach (PluginPair globalPlugin in PluginManager.GlobalPlugins)
{ {
if (!pluginQueryPair.ContainsKey(globalPlugin)) if (!globalPlugin.Metadata.Disabled && !pluginQueryPair.ContainsKey(globalPlugin))
{ {
var query = new Query(rawQuery, rawQuery, new ReadOnlyCollection<string>(terms), string.Empty); var query = new Query(text);
pluginQueryPair.Add(globalPlugin, query); pluginQueryPair.Add(globalPlugin, query);
} }
} }

View file

@ -56,7 +56,7 @@ namespace PowerLauncher
Log.Info("PT Run settings.json was missing, creating a new one", GetType()); Log.Info("PT Run settings.json was missing, creating a new one", GetType());
var defaultSettings = new PowerLauncherSettings(); var defaultSettings = new PowerLauncherSettings();
defaultSettings.Plugins = GetPluginsSettings(); defaultSettings.Plugins = GetDefaultPluginsSettings();
defaultSettings.Save(_settingsUtils); defaultSettings.Save(_settingsUtils);
} }
} }
@ -78,7 +78,7 @@ namespace PowerLauncher
if (overloadSettings.Plugins == null || !overloadSettings.Plugins.Any()) if (overloadSettings.Plugins == null || !overloadSettings.Plugins.Any())
{ {
// Needed to be consistent with old settings // Needed to be consistent with old settings
overloadSettings.Plugins = GetPluginsSettings(); overloadSettings.Plugins = GetDefaultPluginsSettings();
_settingsUtils.SaveSettings(overloadSettings.ToJsonString(), PowerLauncherSettings.ModuleName); _settingsUtils.SaveSettings(overloadSettings.ToJsonString(), PowerLauncherSettings.ModuleName);
} }
else else
@ -91,6 +91,10 @@ namespace PowerLauncher
plugin.Metadata.Disabled = setting.Disabled; plugin.Metadata.Disabled = setting.Disabled;
plugin.Metadata.ActionKeyword = setting.ActionKeyword; plugin.Metadata.ActionKeyword = setting.ActionKeyword;
plugin.Metadata.IsGlobal = setting.IsGlobal; plugin.Metadata.IsGlobal = setting.IsGlobal;
if (plugin.Plugin is ISettingProvider)
{
(plugin.Plugin as ISettingProvider).UpdateSettings(setting);
}
} }
} }
} }
@ -101,13 +105,6 @@ namespace PowerLauncher
_settings.Hotkey = openPowerlauncher; _settings.Hotkey = openPowerlauncher;
} }
var shell = PluginManager.AllPlugins.Find(pp => pp.Metadata.Name == "Shell");
if (shell != null)
{
var shellSettings = shell.Plugin as ISettingProvider;
shellSettings.UpdateSettings(overloadSettings);
}
if (_settings.MaxResultsToShow != overloadSettings.Properties.MaximumNumberOfResults) if (_settings.MaxResultsToShow != overloadSettings.Properties.MaximumNumberOfResults)
{ {
_settings.MaxResultsToShow = overloadSettings.Properties.MaximumNumberOfResults; _settings.MaxResultsToShow = overloadSettings.Properties.MaximumNumberOfResults;
@ -118,14 +115,6 @@ namespace PowerLauncher
_settings.IgnoreHotkeysOnFullscreen = overloadSettings.Properties.IgnoreHotkeysInFullscreen; _settings.IgnoreHotkeysOnFullscreen = overloadSettings.Properties.IgnoreHotkeysInFullscreen;
} }
// Using OrdinalIgnoreCase since this is internal
var indexer = PluginManager.AllPlugins.Find(p => p.Metadata.Name.Equals("Windows Indexer", StringComparison.OrdinalIgnoreCase));
if (indexer != null)
{
var indexerSettings = indexer.Plugin as ISettingProvider;
indexerSettings.UpdateSettings(overloadSettings);
}
if (_settings.ClearInputOnLaunch != overloadSettings.Properties.ClearInputOnLaunch) if (_settings.ClearInputOnLaunch != overloadSettings.Properties.ClearInputOnLaunch)
{ {
_settings.ClearInputOnLaunch = overloadSettings.Properties.ClearInputOnLaunch; _settings.ClearInputOnLaunch = overloadSettings.Properties.ClearInputOnLaunch;
@ -184,19 +173,20 @@ namespace PowerLauncher
return model.ToString(); return model.ToString();
} }
private static IEnumerable<PowerLauncherPluginSettings> GetPluginsSettings() private static IEnumerable<PowerLauncherPluginSettings> GetDefaultPluginsSettings()
{ {
return PluginManager.AllPlugins.Select(x => x.Metadata).Select(x => new PowerLauncherPluginSettings return PluginManager.AllPlugins.Select(x => new PowerLauncherPluginSettings()
{ {
Id = x.ID, Id = x.Metadata.ID,
Name = x.Name, Name = x.Plugin.Name,
Description = x.Description, Description = x.Plugin.Description,
Author = x.Author, Author = x.Metadata.Author,
Disabled = x.Disabled, Disabled = x.Metadata.Disabled,
IsGlobal = x.IsGlobal, IsGlobal = x.Metadata.IsGlobal,
ActionKeyword = x.ActionKeyword, ActionKeyword = x.Metadata.ActionKeyword,
IconPathDark = x.IcoPathDark, IconPathDark = x.Metadata.IcoPathDark,
IconPathLight = x.IcoPathLight, IconPathLight = x.Metadata.IcoPathLight,
AdditionalOptions = x.Plugin is ISettingProvider ? (x.Plugin as ISettingProvider).AdditionalOptions : new List<PluginAdditionalOption>(),
}); });
} }
} }

View file

@ -493,7 +493,7 @@ namespace PowerLauncher.ViewModel
Title = string.Format(CultureInfo.InvariantCulture, title, h.Query), Title = string.Format(CultureInfo.InvariantCulture, title, h.Query),
SubTitle = string.Format(CultureInfo.InvariantCulture, time, h.ExecutedDateTime), SubTitle = string.Format(CultureInfo.InvariantCulture, time, h.ExecutedDateTime),
IcoPath = "Images\\history.png", IcoPath = "Images\\history.png",
OriginQuery = new Query { RawQuery = h.Query }, OriginQuery = new Query(h.Query),
Action = _ => Action = _ =>
{ {
SelectedResults = Results; SelectedResults = Results;
@ -531,9 +531,10 @@ namespace PowerLauncher.ViewModel
_updateToken = currentCancellationToken; _updateToken = currentCancellationToken;
var queryText = QueryText.Trim(); var queryText = QueryText.Trim();
var pluginQueryPairs = QueryBuilder.Build(ref queryText); var pluginQueryPairs = QueryBuilder.Build(queryText);
if (pluginQueryPairs != null && pluginQueryPairs.Count > 0) if (pluginQueryPairs != null && pluginQueryPairs.Count > 0)
{ {
queryText = pluginQueryPairs.Values.First().RawQuery;
_currentQuery = queryText; _currentQuery = queryText;
Task.Run( Task.Run(
() => () =>
@ -557,13 +558,9 @@ namespace PowerLauncher.ViewModel
{ {
var plugin = pluginQueryItem.Key; var plugin = pluginQueryItem.Key;
var query = pluginQueryItem.Value; var query = pluginQueryItem.Value;
var results = PluginManager.QueryForPlugin(plugin, query);
if (!plugin.Metadata.Disabled) resultPluginPair.Add((results, plugin.Metadata));
{ currentCancellationToken.ThrowIfCancellationRequested();
var results = PluginManager.QueryForPlugin(plugin, query);
resultPluginPair.Add((results, plugin.Metadata));
currentCancellationToken.ThrowIfCancellationRequested();
}
} }
lock (_addResultsLock) lock (_addResultsLock)
@ -595,39 +592,36 @@ namespace PowerLauncher.ViewModel
{ {
try try
{ {
if (!plugin.Metadata.Disabled) Query query;
pluginQueryPairs.TryGetValue(plugin, out query);
var results = PluginManager.QueryForPlugin(plugin, query, true);
currentCancellationToken.ThrowIfCancellationRequested();
if ((results?.Count ?? 0) != 0)
{ {
Query query; lock (_addResultsLock)
pluginQueryPairs.TryGetValue(plugin, out query);
var results = PluginManager.QueryForPlugin(plugin, query, true);
currentCancellationToken.ThrowIfCancellationRequested();
if ((results?.Count ?? 0) != 0)
{ {
lock (_addResultsLock) // Using CurrentCultureIgnoreCase since this is user facing
if (queryText.Equals(_currentQuery, StringComparison.CurrentCultureIgnoreCase))
{ {
// Using CurrentCultureIgnoreCase since this is user facing currentCancellationToken.ThrowIfCancellationRequested();
if (queryText.Equals(_currentQuery, StringComparison.CurrentCultureIgnoreCase))
{
currentCancellationToken.ThrowIfCancellationRequested();
// Remove the original results from the plugin // Remove the original results from the plugin
Results.Results.RemoveAll(r => r.Result.PluginID == plugin.Metadata.ID); Results.Results.RemoveAll(r => r.Result.PluginID == plugin.Metadata.ID);
currentCancellationToken.ThrowIfCancellationRequested(); currentCancellationToken.ThrowIfCancellationRequested();
// Add the new results from the plugin // Add the new results from the plugin
UpdateResultView(results, queryText, currentCancellationToken); UpdateResultView(results, queryText, currentCancellationToken);
currentCancellationToken.ThrowIfCancellationRequested(); currentCancellationToken.ThrowIfCancellationRequested();
numResults = Results.Results.Count; numResults = Results.Results.Count;
Results.Sort(); Results.Sort();
Results.SelectedItem = Results.Results.FirstOrDefault(); Results.SelectedItem = Results.Results.FirstOrDefault();
}
} }
currentCancellationToken.ThrowIfCancellationRequested();
UpdateResultsListViewAfterQuery(queryText, true);
} }
currentCancellationToken.ThrowIfCancellationRequested();
UpdateResultsListViewAfterQuery(queryText, true);
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)
@ -875,9 +869,8 @@ namespace PowerLauncher.ViewModel
Results.Clear(); Results.Clear();
MainWindowVisibility = System.Windows.Visibility.Collapsed; MainWindowVisibility = System.Windows.Visibility.Collapsed;
// Fix Cold start for plugins // Fix Cold start for plugins, "m" is just a random string needed to query results
string s = "m"; var pluginQueryPairs = QueryBuilder.Build("m");
var pluginQueryPairs = QueryBuilder.Build(ref s);
// To execute a query corresponding to each plugin // To execute a query corresponding to each plugin
foreach (KeyValuePair<PluginPair, Query> pluginQueryItem in pluginQueryPairs) foreach (KeyValuePair<PluginPair, Query> pluginQueryItem in pluginQueryPairs)

View file

@ -11,5 +11,11 @@ namespace Wox.Plugin
List<Result> Query(Query query); List<Result> Query(Query query);
void Init(PluginInitContext context); void Init(PluginInitContext context);
// Localized name
string Name { get; }
// Localized description
string Description { get; }
} }
} }

View file

@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Windows.Controls; using System.Windows.Controls;
using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library;
@ -11,6 +12,8 @@ namespace Wox.Plugin
{ {
Control CreateSettingPanel(); Control CreateSettingPanel();
void UpdateSettings(PowerLauncherSettings settings); void UpdateSettings(PowerLauncherPluginSettings settings);
IEnumerable<PluginAdditionalOption> AdditionalOptions { get; }
} }
} }

View file

@ -32,8 +32,6 @@ namespace Wox.Plugin
public string Language { get; set; } public string Language { get; set; }
public string Description { get; set; }
public string Website { get; set; } public string Website { get; set; }
public bool Disabled { get; set; } public bool Disabled { get; set; }

View file

@ -19,19 +19,32 @@ namespace Wox.Plugin
/// Initializes a new instance of the <see cref="Query"/> class. /// Initializes a new instance of the <see cref="Query"/> class.
/// to allow unit tests for plug ins /// to allow unit tests for plug ins
/// </summary> /// </summary>
public Query(string rawQuery, string search, ReadOnlyCollection<string> terms, string actionKeyword = "") public Query(string query, string actionKeyword = "")
{ {
Search = search; _query = query;
RawQuery = rawQuery;
Terms = terms;
ActionKeyword = actionKeyword; ActionKeyword = actionKeyword;
} }
private string _rawQuery;
/// <summary> /// <summary>
/// Gets raw query, this includes action keyword if it has /// Gets raw query, this includes action keyword if it has
/// We didn't recommend use this property directly. You should always use Search property. /// We didn't recommend use this property directly. You should always use Search property.
/// </summary> /// </summary>
public string RawQuery { get; internal set; } public string RawQuery
{
get
{
if (_rawQuery == null)
{
_rawQuery = string.Join(Query.TermSeparator, _query.Split(new[] { TermSeparator }, StringSplitOptions.RemoveEmptyEntries));
}
return _rawQuery;
}
}
private string _search;
/// <summary> /// <summary>
/// Gets search part of a query. /// Gets search part of a query.
@ -39,12 +52,41 @@ namespace Wox.Plugin
/// Since we allow user to switch a exclusive plugin to generic plugin, /// Since we allow user to switch a exclusive plugin to generic plugin,
/// so this property will always give you the "real" query part of the query /// so this property will always give you the "real" query part of the query
/// </summary> /// </summary>
public string Search { get; internal set; } public string Search
{
get
{
if (_search == null)
{
_search = RawQuery.Substring(ActionKeyword.Length).Trim();
}
return _search;
}
}
private ReadOnlyCollection<string> _terms;
/// <summary> /// <summary>
/// Gets the raw query splited into a string array. /// Gets the raw query splited into a string array.
/// </summary> /// </summary>
public ReadOnlyCollection<string> Terms { get; private set; } public ReadOnlyCollection<string> Terms
{
get
{
if (_terms == null)
{
var terms = _query
.Trim()
.Substring(ActionKeyword.Length)
.Split(new[] { TermSeparator }, StringSplitOptions.RemoveEmptyEntries);
_terms = new ReadOnlyCollection<string>(terms);
}
return _terms;
}
}
/// <summary> /// <summary>
/// Query can be splited into multiple terms by whitespace /// Query can be splited into multiple terms by whitespace
@ -102,6 +144,8 @@ namespace Wox.Plugin
} }
} }
private string _query;
public override string ToString() => RawQuery; public override string ToString() => RawQuery;
[Obsolete("Use Search instead, this method will be removed in v1.3.0")] [Obsolete("Use Search instead, this method will be removed in v1.3.0")]

View file

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Mono.Collections.Generic; using Mono.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using PowerLauncher.Plugin; using PowerLauncher.Plugin;
@ -36,25 +37,8 @@ namespace Wox.Test
string searchQuery = "> file.txt file2 file3"; string searchQuery = "> file.txt file2 file3";
// Act // Act
var pluginQueryPairs = QueryBuilder.Build(ref searchQuery); var pluginQueryPairs = QueryBuilder.Build(searchQuery);
searchQuery = pluginQueryPairs.Values.First().RawQuery;
// Assert
Assert.AreEqual("> file.txt file2 file3", searchQuery);
}
[Test]
public void QueryBuilderShouldRemoveExtraSpacesForDisabledNonGlobalPlugin()
{
// Arrange
PluginManager.SetAllPlugins(new List<PluginPair>()
{
new PluginPair { Metadata = new PluginMetadata() { Disabled = true, ActionKeyword = ">" } },
});
string searchQuery = "> file.txt file2 file3";
// Act
var pluginQueryPairs = QueryBuilder.Build(ref searchQuery);
// Assert // Assert
Assert.AreEqual("> file.txt file2 file3", searchQuery); Assert.AreEqual("> file.txt file2 file3", searchQuery);
@ -65,9 +49,14 @@ namespace Wox.Test
{ {
// Arrange // Arrange
string searchQuery = "file.txt file2 file3"; string searchQuery = "file.txt file2 file3";
PluginManager.SetAllPlugins(new List<PluginPair>()
{
new PluginPair { Metadata = new PluginMetadata() { Disabled = false, IsGlobal = true } },
});
// Act // Act
var pluginQueryPairs = QueryBuilder.Build(ref searchQuery); var pluginQueryPairs = QueryBuilder.Build(searchQuery);
searchQuery = pluginQueryPairs.Values.First().RawQuery;
// Assert // Assert
Assert.AreEqual("file.txt file2 file3", searchQuery); Assert.AreEqual("file.txt file2 file3", searchQuery);
@ -87,10 +76,10 @@ namespace Wox.Test
var secondQueryText = "a search"; var secondQueryText = "a search";
// Act // Act
var firstPluginQueryPair = QueryBuilder.Build(ref firstQueryText); var firstPluginQueryPair = QueryBuilder.Build(firstQueryText);
var firstQuery = firstPluginQueryPair.GetValueOrDefault(plugin); var firstQuery = firstPluginQueryPair.GetValueOrDefault(plugin);
var secondPluginQueryPairs = QueryBuilder.Build(ref secondQueryText); var secondPluginQueryPairs = QueryBuilder.Build(secondQueryText);
var secondQuery = secondPluginQueryPairs.GetValueOrDefault(plugin); var secondQuery = secondPluginQueryPairs.GetValueOrDefault(plugin);
// Assert // Assert
@ -113,14 +102,14 @@ namespace Wox.Test
}); });
// Act // Act
var pluginQueryPairs = QueryBuilder.Build(ref searchQuery); var pluginQueryPairs = QueryBuilder.Build(searchQuery);
var firstQuery = pluginQueryPairs.GetValueOrDefault(firstPlugin); var firstQuery = pluginQueryPairs.GetValueOrDefault(firstPlugin);
var secondQuery = pluginQueryPairs.GetValueOrDefault(secondPlugin); var secondQuery = pluginQueryPairs.GetValueOrDefault(secondPlugin);
// Assert // Assert
Assert.IsTrue(AreEqual(firstQuery, new Query { RawQuery = searchQuery, Search = searchQuery.Substring(firstPlugin.Metadata.ActionKeyword.Length), ActionKeyword = firstPlugin.Metadata.ActionKeyword } )); Assert.IsTrue(AreEqual(firstQuery, new Query(searchQuery, firstPlugin.Metadata.ActionKeyword)));
Assert.IsTrue(AreEqual(secondQuery, new Query { RawQuery = searchQuery, Search = searchQuery.Substring(secondPlugin.Metadata.ActionKeyword.Length), ActionKeyword = secondPlugin.Metadata.ActionKeyword })); Assert.IsTrue(AreEqual(secondQuery, new Query(searchQuery, secondPlugin.Metadata.ActionKeyword)));
} }
[Test] [Test]
@ -137,7 +126,7 @@ namespace Wox.Test
}); });
// Act // Act
var pluginQueryPairs = QueryBuilder.Build(ref searchQuery); var pluginQueryPairs = QueryBuilder.Build(searchQuery);
var firstQuery = pluginQueryPairs.GetValueOrDefault(firstPlugin); var firstQuery = pluginQueryPairs.GetValueOrDefault(firstPlugin);
var secondQuery = pluginQueryPairs.GetValueOrDefault(secondPlugin); var secondQuery = pluginQueryPairs.GetValueOrDefault(secondPlugin);
@ -147,5 +136,25 @@ namespace Wox.Test
Assert.IsTrue(firstQuery.Terms[0].Equals("cd", StringComparison.Ordinal) && firstQuery.Terms[1].Equals("efgh", StringComparison.Ordinal) && firstQuery.Terms.Count == 2); Assert.IsTrue(firstQuery.Terms[0].Equals("cd", StringComparison.Ordinal) && firstQuery.Terms[1].Equals("efgh", StringComparison.Ordinal) && firstQuery.Terms.Count == 2);
Assert.IsTrue(secondQuery.Terms[0].Equals("efgh", StringComparison.Ordinal) && secondQuery.Terms.Count == 1); Assert.IsTrue(secondQuery.Terms[0].Equals("efgh", StringComparison.Ordinal) && secondQuery.Terms.Count == 1);
} }
[Test]
public void QueryBuilderShouldReturnAllPluginsWithTheActionWord()
{
// Arrange
string searchQuery = "!efgh";
var firstPlugin = new PluginPair { Metadata = new PluginMetadata { ActionKeyword = "!", ID = "plugin1" } };
var secondPlugin = new PluginPair { Metadata = new PluginMetadata { ActionKeyword = "!", ID = "plugin2" } };
PluginManager.SetAllPlugins(new List<PluginPair>()
{
firstPlugin,
secondPlugin,
});
// Act
var pluginQueryPairs = QueryBuilder.Build(searchQuery);
// Assert
Assert.AreEqual(2, pluginQueryPairs.Count);
}
} }
} }

View file

@ -0,0 +1,15 @@
// 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.
namespace Microsoft.PowerToys.Settings.UI.Library
{
public class PluginAdditionalOption
{
public string Key { get; set; }
public string DisplayLabel { get; set; }
public bool Value { get; set; }
}
}

View file

@ -2,6 +2,8 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Collections.Generic;
namespace Microsoft.PowerToys.Settings.UI.Library namespace Microsoft.PowerToys.Settings.UI.Library
{ {
public class PowerLauncherPluginSettings public class PowerLauncherPluginSettings
@ -23,5 +25,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string IconPathDark { get; set; } public string IconPathDark { get; set; }
public string IconPathLight { get; set; } public string IconPathLight { get; set; }
public IEnumerable<PluginAdditionalOption> AdditionalOptions { get; set; }
} }
} }

View file

@ -39,9 +39,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonPropertyName("ignore_hotkeys_in_fullscreen")] [JsonPropertyName("ignore_hotkeys_in_fullscreen")]
public bool IgnoreHotkeysInFullscreen { get; set; } public bool IgnoreHotkeysInFullscreen { get; set; }
[JsonPropertyName("disable_drive_detection_warning")]
public bool DisableDriveDetectionWarning { get; set; }
[JsonPropertyName("clear_input_on_launch")] [JsonPropertyName("clear_input_on_launch")]
public bool ClearInputOnLaunch { get; set; } public bool ClearInputOnLaunch { get; set; }
@ -57,7 +54,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
SearchResultPreference = "most_recently_used"; SearchResultPreference = "most_recently_used";
SearchTypePreference = "application_name"; SearchTypePreference = "application_name";
IgnoreHotkeysInFullscreen = false; IgnoreHotkeysInFullscreen = false;
DisableDriveDetectionWarning = false;
ClearInputOnLaunch = false; ClearInputOnLaunch = false;
MaximumNumberOfResults = 4; MaximumNumberOfResults = 4;
Theme = Theme.System; Theme = Theme.System;

View file

@ -18,7 +18,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public PowerLauncherProperties Properties { get; set; } public PowerLauncherProperties Properties { get; set; }
[JsonPropertyName("plugins")] [JsonPropertyName("plugins")]
public IEnumerable<PowerLauncherPluginSettings> Plugins { get; set; } public IEnumerable<PowerLauncherPluginSettings> Plugins { get; set; } = new List<PowerLauncherPluginSettings>();
public PowerLauncherSettings() public PowerLauncherSettings()
{ {

View file

@ -0,0 +1,41 @@
// 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.Runtime.CompilerServices;
namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
{
public class PluginAdditionalOptionViewModel : INotifyPropertyChanged
{
private PluginAdditionalOption _additionalOption;
internal PluginAdditionalOptionViewModel(PluginAdditionalOption additionalOption)
{
_additionalOption = additionalOption;
}
public string DisplayLabel { get => _additionalOption.DisplayLabel; }
public bool Value
{
get => _additionalOption.Value;
set
{
if (value != _additionalOption.Value)
{
_additionalOption.Value = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View file

@ -0,0 +1,170 @@
// 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.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
{
public class PowerLauncherPluginViewModel : INotifyPropertyChanged
{
private readonly PowerLauncherPluginSettings settings;
private readonly Func<bool> isDark;
public PowerLauncherPluginViewModel(PowerLauncherPluginSettings settings, Func<bool> isDark)
{
if (settings == null)
{
throw new ArgumentNullException(nameof(settings), "PowerLauncherPluginSettings object is null");
}
this.settings = settings;
this.isDark = isDark;
foreach (var item in AdditionalOptions)
{
item.PropertyChanged += (object sender, PropertyChangedEventArgs e) =>
{
NotifyPropertyChanged(nameof(AdditionalOptions));
};
}
}
public string Id { get => settings.Id; }
public string Name { get => settings.Name; }
public string Description { get => settings.Description; }
public string Author { get => settings.Author; }
public bool Disabled
{
get
{
return settings.Disabled;
}
set
{
if (settings.Disabled != value)
{
settings.Disabled = value;
NotifyPropertyChanged();
NotifyPropertyChanged(nameof(ShowNotAccessibleWarning));
NotifyPropertyChanged(nameof(ShowNotAllowedKeywordWarning));
NotifyPropertyChanged(nameof(Enabled));
NotifyPropertyChanged(nameof(DisabledOpacity));
}
}
}
public bool Enabled => !Disabled;
public double DisabledOpacity => Disabled ? 0.5 : 1;
public bool IsGlobal
{
get
{
return settings.IsGlobal;
}
set
{
if (settings.IsGlobal != value)
{
settings.IsGlobal = value;
NotifyPropertyChanged();
NotifyPropertyChanged(nameof(ShowNotAccessibleWarning));
}
}
}
public string ActionKeyword
{
get
{
return settings.ActionKeyword;
}
set
{
if (settings.ActionKeyword != value)
{
settings.ActionKeyword = value;
NotifyPropertyChanged();
NotifyPropertyChanged(nameof(ShowNotAccessibleWarning));
NotifyPropertyChanged(nameof(ShowNotAllowedKeywordWarning));
}
}
}
private IEnumerable<PluginAdditionalOptionViewModel> _additionalOptions;
public IEnumerable<PluginAdditionalOptionViewModel> AdditionalOptions
{
get
{
if (_additionalOptions == null)
{
_additionalOptions = settings.AdditionalOptions.Select(x => new PluginAdditionalOptionViewModel(x)).ToList();
}
return _additionalOptions;
}
}
public bool ShowAdditionalOptions
{
get => AdditionalOptions.Any();
}
public override string ToString()
{
return $"{Name}. {Description}";
}
public string IconPath { get => isDark() ? settings.IconPathDark : settings.IconPathLight; }
private bool _showAdditionalInfoPanel;
public bool ShowAdditionalInfoPanel
{
get => _showAdditionalInfoPanel;
set
{
if (value != _showAdditionalInfoPanel)
{
_showAdditionalInfoPanel = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public bool ShowNotAccessibleWarning
{
get => !Disabled && !IsGlobal && string.IsNullOrWhiteSpace(ActionKeyword);
}
private static readonly List<string> NotAllowedKeywords = new List<string>()
{
"~", @"\", @"\\",
};
public bool ShowNotAllowedKeywordWarning
{
get => !Disabled && NotAllowedKeywords.Contains(ActionKeyword);
}
}
}

View file

@ -3,7 +3,11 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System; using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization; using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text.Json; using System.Text.Json;
using ManagedCommon; using ManagedCommon;
@ -28,11 +32,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
private readonly SendCallback callback; private readonly SendCallback callback;
private readonly Func<bool> isDark;
private Func<string, int> SendConfigMSG { get; } private Func<string, int> SendConfigMSG { get; }
public PowerLauncherViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc, int defaultKeyCode) public PowerLauncherViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc, int defaultKeyCode, Func<bool> isDark)
{ {
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils)); _settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
this.isDark = isDark;
// To obtain the general Settings configurations of PowerToys // To obtain the general Settings configurations of PowerToys
if (settingsRepository == null) if (settingsRepository == null)
@ -81,6 +88,17 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
_isSystemThemeRadioButtonChecked = true; _isSystemThemeRadioButtonChecked = true;
break; break;
} }
foreach (var plugin in Plugins)
{
plugin.PropertyChanged += OnPluginInfoChange;
}
}
private void OnPluginInfoChange(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(nameof(ShowAllPluginsDisabledWarning));
UpdateSettings();
} }
public PowerLauncherViewModel(PowerLauncherSettings settings, SendCallback callback) public PowerLauncherViewModel(PowerLauncherSettings settings, SendCallback callback)
@ -110,6 +128,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
{ {
GeneralSettingsConfig.Enabled.PowerLauncher = value; GeneralSettingsConfig.Enabled.PowerLauncher = value;
OnPropertyChanged(nameof(EnablePowerLauncher)); OnPropertyChanged(nameof(EnablePowerLauncher));
OnPropertyChanged(nameof(ShowAllPluginsDisabledWarning));
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig); OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(outgoing.ToString()); SendConfigMSG(outgoing.ToString());
} }
@ -343,21 +362,24 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
} }
} }
public bool DisableDriveDetectionWarning private ObservableCollection<PowerLauncherPluginViewModel> _plugins;
public ObservableCollection<PowerLauncherPluginViewModel> Plugins
{ {
get get
{ {
return settings.Properties.DisableDriveDetectionWarning; if (_plugins == null)
}
set
{
if (settings.Properties.DisableDriveDetectionWarning != value)
{ {
settings.Properties.DisableDriveDetectionWarning = value; _plugins = new ObservableCollection<PowerLauncherPluginViewModel>(settings.Plugins.Select(x => new PowerLauncherPluginViewModel(x, isDark)));
UpdateSettings();
} }
return _plugins;
} }
} }
public bool ShowAllPluginsDisabledWarning
{
get => EnablePowerLauncher && Plugins.All(x => x.Disabled);
}
} }
} }

View file

@ -66,13 +66,12 @@ namespace ViewModelTests
// Initialise View Model with test Config files // Initialise View Model with test Config files
Func<string, int> sendMockIPCConfigMSG = msg => { return 0; }; Func<string, int> sendMockIPCConfigMSG = msg => { return 0; };
PowerLauncherViewModel viewModel = new PowerLauncherViewModel(mockSettingsUtils, generalSettingsRepository, sendMockIPCConfigMSG, 32); PowerLauncherViewModel viewModel = new PowerLauncherViewModel(mockSettingsUtils, generalSettingsRepository, sendMockIPCConfigMSG, 32, () => true);
// Verify that the old settings persisted // Verify that the old settings persisted
Assert.AreEqual(originalGeneralSettings.Enabled.PowerLauncher, viewModel.EnablePowerLauncher); Assert.AreEqual(originalGeneralSettings.Enabled.PowerLauncher, viewModel.EnablePowerLauncher);
Assert.AreEqual(originalSettings.Properties.ClearInputOnLaunch, viewModel.ClearInputOnLaunch); Assert.AreEqual(originalSettings.Properties.ClearInputOnLaunch, viewModel.ClearInputOnLaunch);
Assert.AreEqual(originalSettings.Properties.CopyPathLocation.ToString(), viewModel.CopyPathLocation.ToString()); Assert.AreEqual(originalSettings.Properties.CopyPathLocation.ToString(), viewModel.CopyPathLocation.ToString());
Assert.AreEqual(originalSettings.Properties.DisableDriveDetectionWarning, viewModel.DisableDriveDetectionWarning);
Assert.AreEqual(originalSettings.Properties.IgnoreHotkeysInFullscreen, viewModel.IgnoreHotkeysInFullScreen); Assert.AreEqual(originalSettings.Properties.IgnoreHotkeysInFullscreen, viewModel.IgnoreHotkeysInFullScreen);
Assert.AreEqual(originalSettings.Properties.MaximumNumberOfResults, viewModel.MaximumNumberOfResults); Assert.AreEqual(originalSettings.Properties.MaximumNumberOfResults, viewModel.MaximumNumberOfResults);
Assert.AreEqual(originalSettings.Properties.OpenPowerLauncher.ToString(), viewModel.OpenPowerLauncher.ToString()); Assert.AreEqual(originalSettings.Properties.OpenPowerLauncher.ToString(), viewModel.OpenPowerLauncher.ToString());
@ -173,16 +172,5 @@ namespace ViewModelTests
Assert.IsTrue(mockSettings.Properties.OverrideWinkeyR); Assert.IsTrue(mockSettings.Properties.OverrideWinkeyR);
Assert.IsFalse(mockSettings.Properties.OverrideWinkeyS); Assert.IsFalse(mockSettings.Properties.OverrideWinkeyS);
} }
[TestMethod]
public void DriveDetectionViewModelWhenSetMustUpdateOverrides()
{
// Act
viewModel.DisableDriveDetectionWarning = true;
// Assert
Assert.AreEqual(1, sendCallbackMock.TimesSent);
Assert.IsTrue(mockSettings.Properties.DisableDriveDetectionWarning);
}
} }
} }

View file

@ -18,7 +18,6 @@
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<converters:ModuleEnabledToForegroundConverter x:Key="ModuleEnabledToForegroundConverter"/> <converters:ModuleEnabledToForegroundConverter x:Key="ModuleEnabledToForegroundConverter"/>
<SolidColorBrush x:Key="DarkForegroundDisabledBrush">#66FFFFFF</SolidColorBrush> <SolidColorBrush x:Key="DarkForegroundDisabledBrush">#66FFFFFF</SolidColorBrush>
<SolidColorBrush x:Key="DarkForegroundBrush">#FFFFFFFF</SolidColorBrush> <SolidColorBrush x:Key="DarkForegroundBrush">#FFFFFFFF</SolidColorBrush>

View file

@ -2,7 +2,9 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Globalization;
using Microsoft.PowerToys.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.Toolkit.Win32.UI.XamlHost; using Microsoft.Toolkit.Win32.UI.XamlHost;
namespace Microsoft.PowerToys.Settings.UI namespace Microsoft.PowerToys.Settings.UI
@ -18,5 +20,15 @@ namespace Microsoft.PowerToys.Settings.UI
var coreWindowInterop = Interop.GetInterop(coreWindow); var coreWindowInterop = Interop.GetInterop(coreWindow);
NativeMethods.ShowWindow(coreWindowInterop.WindowHandle, Interop.SW_HIDE); NativeMethods.ShowWindow(coreWindowInterop.WindowHandle, Interop.SW_HIDE);
} }
public static bool IsDarkTheme()
{
var selectedTheme = SettingsRepository<GeneralSettings>.GetInstance(settingsUtils).SettingsConfig.Theme.ToUpper(CultureInfo.InvariantCulture);
var defaultTheme = new Windows.UI.ViewManagement.UISettings();
var uiTheme = defaultTheme.GetColorValue(Windows.UI.ViewManagement.UIColorType.Background).ToString(System.Globalization.CultureInfo.InvariantCulture);
return selectedTheme == "DARK" || (selectedTheme == "SYSTEM" && uiTheme == "#FF000000");
}
private static ISettingsUtils settingsUtils = new SettingsUtils();
} }
} }

View file

@ -13,23 +13,11 @@ namespace Microsoft.PowerToys.Settings.UI.Converters
{ {
public sealed class ModuleEnabledToForegroundConverter : IValueConverter public sealed class ModuleEnabledToForegroundConverter : IValueConverter
{ {
private readonly ISettingsUtils settingsUtils = new SettingsUtils();
private string selectedTheme = string.Empty;
public object Convert(object value, Type targetType, object parameter, string language) public object Convert(object value, Type targetType, object parameter, string language)
{ {
bool isEnabled = (bool)value; bool isEnabled = (bool)value;
var defaultTheme = new Windows.UI.ViewManagement.UISettings(); if (App.IsDarkTheme())
// Using InvariantCulture as this is an internal string and expected to be in hexadecimal
var uiTheme = defaultTheme.GetColorValue(Windows.UI.ViewManagement.UIColorType.Background).ToString(CultureInfo.InvariantCulture);
// Normalize strings to uppercase according to Fxcop
selectedTheme = SettingsRepository<GeneralSettings>.GetInstance(settingsUtils).SettingsConfig.Theme.ToUpperInvariant();
if (selectedTheme == "DARK" || (selectedTheme == "SYSTEM" && uiTheme == "#FF000000"))
{ {
// DARK // DARK
if (isEnabled) if (isEnabled)

View file

@ -291,9 +291,6 @@
<data name="PowerLauncher_IgnoreHotkeysInFullScreen.Content" xml:space="preserve"> <data name="PowerLauncher_IgnoreHotkeysInFullScreen.Content" xml:space="preserve">
<value>Ignore shortcuts in fullscreen mode</value> <value>Ignore shortcuts in fullscreen mode</value>
</data> </data>
<data name="PowerLauncher_DisableDriveDetectionWarning.Content" xml:space="preserve">
<value>Disable drive detection warning for the file search plugin</value>
</data>
<data name="PowerLauncher_ClearInputOnLaunch.Content" xml:space="preserve"> <data name="PowerLauncher_ClearInputOnLaunch.Content" xml:space="preserve">
<value>Clear the previous query on launch</value> <value>Clear the previous query on launch</value>
</data> </data>
@ -949,4 +946,35 @@
<data name="FancyZones_OverlappingZonesLabel.Text" xml:space="preserve"> <data name="FancyZones_OverlappingZonesLabel.Text" xml:space="preserve">
<value>When multiple zones overlap:</value> <value>When multiple zones overlap:</value>
</data> </data>
</root> <data name="PowerLauncher_Plugins.Text" xml:space="preserve">
<value>Plugins</value>
</data>
<data name="PowerLauncher_ActionKeyword.Text" xml:space="preserve">
<value>Direct activation phrase</value>
</data>
<data name="PowerLauncher_AuthoredBy.Text" xml:space="preserve">
<value>Authored by</value>
<comment>example: Authored by Microsoft</comment>
</data>
<data name="PowerLauncher_IncludeInGlobalResult.Content" xml:space="preserve">
<value>Include in global result</value>
</data>
<data name="PowerLauncher_EnablePluginToggle.AutomationProperties.Name" xml:space="preserve">
<value>Enable plugin</value>
</data>
<data name="Run_AdditionalOptions.Text" xml:space="preserve">
<value>Additional options</value>
</data>
<data name="Run_NotAccessibleWarning.Text" xml:space="preserve">
<value>Please define an activation phrase or allow this plugin for the global results to use it.</value>
</data>
<data name="Run_AllPluginsDisabled.Text" xml:space="preserve">
<value>PowerToys Run can't provide any results without plugins. Please enable at least one plugin.</value>
</data>
<data name="Run_NotAllowedActionKeyword.Text" xml:space="preserve">
<value>This activation phrase overrides the behavior of other plugins. Please change it to something else.</value>
</data>
<data name="Run_PluginUseDescription.Text" xml:space="preserve">
<value>You can include or remove each plugin from the global results, change the direct activation phrase and configure additional options.</value>
</data>
</root>

View file

@ -1,18 +1,22 @@
<Page <Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Views" xmlns:ViewModels="using:Microsoft.PowerToys.Settings.UI.Library.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls" xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
x:Class="Microsoft.PowerToys.Settings.UI.Views.PowerLauncherPage" x:Class="Microsoft.PowerToys.Settings.UI.Views.PowerLauncherPage"
xmlns:viewModel="using:Microsoft.PowerToys.Settings.UI.ViewModels"
xmlns:CustomControls="using:Microsoft.PowerToys.Settings.UI.Controls" xmlns:CustomControls="using:Microsoft.PowerToys.Settings.UI.Controls"
xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters"
mc:Ignorable="d" mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
AutomationProperties.LandmarkType="Main"> AutomationProperties.LandmarkType="Main">
<Page.Resources>
<converters:BoolToObjectConverter x:Key="BoolToVisibilityConverter" TrueValue="Visible" FalseValue="Collapsed"/>
<converters:BoolNegationConverter x:Key="BoolNegationConverter"/>
</Page.Resources>
<Grid RowSpacing="{StaticResource DefaultRowSpacing}"> <Grid RowSpacing="{StaticResource DefaultRowSpacing}" >
<VisualStateManager.VisualStateGroups> <VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="LayoutVisualStates"> <VisualStateGroup x:Name="LayoutVisualStates">
<VisualState x:Name="WideLayout"> <VisualState x:Name="WideLayout">
@ -144,15 +148,9 @@
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher}" IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher}"
/> />
<CheckBox x:Uid="PowerLauncher_DisableDriveDetectionWarning"
Margin="{StaticResource SmallTopMargin}"
IsChecked="{x:Bind Mode=TwoWay, Path=ViewModel.DisableDriveDetectionWarning}"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher}"
/>
<TextBlock x:Uid="Appearance_GroupSettings" <TextBlock x:Uid="Appearance_GroupSettings"
Style="{StaticResource SettingsGroupTitleStyle}" Style="{StaticResource SettingsGroupTitleStyle}"
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher, Converter={StaticResource ModuleEnabledToForegroundConverter}}" /> Foreground="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher, Converter={StaticResource ModuleEnabledToForegroundConverter}}" />
<!-- We cannot navigate to all the radio buttons using the arrow keys because of an XYNavigation issue in the RadioButtons control. <!-- We cannot navigate to all the radio buttons using the arrow keys because of an XYNavigation issue in the RadioButtons control.
The screen reader does not read the heading when we tab into a radio button, even though the LabeledBy automation property is set. The screen reader does not read the heading when we tab into a radio button, even though the LabeledBy automation property is set.
Link to the issue in the winui repository - https://github.com/microsoft/microsoft-ui-xaml/issues/3156 --> Link to the issue in the winui repository - https://github.com/microsoft/microsoft-ui-xaml/issues/3156 -->
@ -176,6 +174,158 @@
<TextBlock x:Uid="Windows_Color_Settings" /> <TextBlock x:Uid="Windows_Color_Settings" />
</HyperlinkButton> </HyperlinkButton>
</StackPanel> </StackPanel>
<TextBlock x:Uid="PowerLauncher_Plugins"
Style="{StaticResource SettingsGroupTitleStyle}"
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<TextBlock x:Uid="Run_PluginUseDescription"
FontSize="12"
Foreground="{ThemeResource SystemBaseMediumColor}"
TextWrapping="Wrap"/>
<TextBlock x:Uid="Run_AllPluginsDisabled"
FontSize="12"
Foreground="{ThemeResource SystemControlErrorTextForegroundBrush}"
Visibility="{x:Bind ViewModel.ShowAllPluginsDisabledWarning, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}"
TextWrapping="Wrap"
Margin="{StaticResource SmallTopMargin}"/>
<ListView ItemsSource="{x:Bind Path=ViewModel.Plugins, Mode=OneWay}"
IsItemClickEnabled="True"
SelectionChanged="PluginsListView_SelectionChanged"
x:Name="PluginsListView"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher}"
Margin="-12,12,0,0">
<ListView.Resources>
<SolidColorBrush x:Key="ListViewItemBackgroundSelected"
Color="{ThemeResource SystemChromeLowColor}" />
<SolidColorBrush x:Key="ListViewItemBackgroundSelectedPointerOver"
Color="{ThemeResource SystemChromeLowColor}" />
<SolidColorBrush x:Key="ListViewItemBackgroundSelectedPressed"
Color="{ThemeResource SystemChromeLowColor}" />
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
<Setter Property="VerticalContentAlignment"
Value="Stretch" />
<Setter Property="Padding"
Value="0,0,0,0" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="ViewModels:PowerLauncherPluginViewModel" x:DefaultBindMode="OneWay">
<StackPanel Orientation="Vertical" Background="Transparent"
Padding="0,12,0,12">
<Grid ColumnSpacing="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="52" />
</Grid.ColumnDefinitions>
<Image Source="{x:Bind IconPath}"
Width="36"
Opacity="{x:Bind DisabledOpacity, Mode=OneWay}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="12,0,12,0"
Height="36" />
<StackPanel Orientation="Vertical"
Grid.Column="1" Margin="0,0,12,0">
<TextBlock FontSize="18"
Text="{x:Bind Path=Name}"
Opacity="{x:Bind DisabledOpacity}"/>
<TextBlock FontSize="12"
Opacity="{x:Bind DisabledOpacity}"
Foreground="{ThemeResource SystemBaseMediumColor}"
Text="{x:Bind Description}"
TextWrapping="Wrap"/>
<TextBlock
x:Uid="Run_NotAccessibleWarning"
FontSize="12"
Foreground="{ThemeResource SystemControlErrorTextForegroundBrush}"
Visibility="{x:Bind ShowNotAccessibleWarning, Converter={StaticResource BoolToVisibilityConverter}}"
TextWrapping="Wrap" />
<TextBlock
x:Uid="Run_NotAllowedActionKeyword"
FontSize="12"
Foreground="{ThemeResource SystemControlErrorTextForegroundBrush}"
Visibility="{x:Bind ShowNotAllowedKeywordWarning, Converter={StaticResource BoolToVisibilityConverter}}"
TextWrapping="Wrap" />
</StackPanel>
<ToggleSwitch x:Uid="PowerLauncher_EnablePluginToggle"
x:Name="ToggleSwitch"
HorizontalAlignment="Center"
IsOn="{x:Bind Path=Disabled, Converter={StaticResource BoolNegationConverter}, Mode=TwoWay}"
Grid.Column="2" />
</Grid>
<StackPanel Margin="60,24,0,24"
x:Name="AdditionalInfoPanel"
Visibility="{x:Bind ShowAdditionalInfoPanel, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<CheckBox x:Uid="PowerLauncher_IncludeInGlobalResult"
IsChecked="{x:Bind Path=IsGlobal, Mode=TwoWay}"
IsEnabled="{x:Bind Enabled, Mode=OneWay}"/>
<TextBlock x:Uid="PowerLauncher_ActionKeyword"
x:Name="ActionKeywordHeaderTextBlock"
Margin="{StaticResource SmallTopMargin}"
Opacity="{x:Bind DisabledOpacity}"/>
<TextBox x:Uid="PowerLauncher_ActionKeyword"
Text="{x:Bind Path=ActionKeyword, Mode=TwoWay}"
Width="86"
Margin="0,6,0,0"
AutomationProperties.LabeledBy="{Binding ElementName=ActionKeywordHeaderTextBlock}"
HorizontalAlignment="Left"
IsEnabled="{x:Bind Enabled, Mode=OneWay}"/>
<TextBlock x:Name="AdditionalOptionsTextBlock"
x:Uid="Run_AdditionalOptions"
Margin="{StaticResource SmallTopMargin}"
Visibility="{x:Bind ShowAdditionalOptions, Converter={StaticResource BoolToVisibilityConverter}}"
Style="{StaticResource SettingsGroupTitleStyle}"
Opacity="{x:Bind DisabledOpacity}"/>
<ListView ItemsSource="{x:Bind Path=AdditionalOptions}"
SelectionMode="None"
IsEnabled="{x:Bind Enabled, Mode=OneWay}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
<Setter Property="VerticalContentAlignment"
Value="Stretch" />
<Setter Property="Padding"
Value="0,0,0,0" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="ViewModels:PluginAdditionalOptionViewModel">
<CheckBox Content="{x:Bind Path=DisplayLabel}"
IsChecked="{x:Bind Path=Value, Mode=TwoWay}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBlock FontSize="12"
Opacity="{x:Bind DisabledOpacity}"
Foreground="{ThemeResource SystemBaseMediumColor}"
HorizontalAlignment="Right"
Margin="0,0,12,0">
<Run x:Uid="PowerLauncher_AuthoredBy" />
<Run FontWeight="SemiBold" Text="{x:Bind Author}" />
</TextBlock>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel> </StackPanel>
<RelativePanel x:Name="SidePanel" <RelativePanel x:Name="SidePanel"
@ -229,4 +379,4 @@
</StackPanel> </StackPanel>
</RelativePanel> </RelativePanel>
</Grid> </Grid>
</Page> </Page>

View file

@ -4,9 +4,11 @@
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Globalization;
using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Utilities; using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using Microsoft.PowerToys.Settings.UI.Library.ViewModels; using Microsoft.PowerToys.Settings.UI.Library.ViewModels;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
namespace Microsoft.PowerToys.Settings.UI.Views namespace Microsoft.PowerToys.Settings.UI.Views
@ -22,7 +24,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
{ {
InitializeComponent(); InitializeComponent();
var settingsUtils = new SettingsUtils(); var settingsUtils = new SettingsUtils();
ViewModel = new PowerLauncherViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, (int)Windows.System.VirtualKey.Space); ViewModel = new PowerLauncherViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, (int)Windows.System.VirtualKey.Space, App.IsDarkTheme);
DataContext = ViewModel; DataContext = ViewModel;
var loader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView(); var loader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
@ -43,6 +45,15 @@ namespace Microsoft.PowerToys.Settings.UI.Views
Helpers.StartProcessHelper.Start(Helpers.StartProcessHelper.ColorsSettings); Helpers.StartProcessHelper.Start(Helpers.StartProcessHelper.ColorsSettings);
} }
private void PluginsListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedPlugin = (sender as ListView)?.SelectedItem;
foreach (var plugin in ViewModel.Plugins)
{
plugin.ShowAdditionalInfoPanel = plugin == selectedPlugin;
}
}
/* /*
public Tuple<string, string> SelectedSearchResultPreference public Tuple<string, string> SelectedSearchResultPreference
{ {