diff --git a/Plugins/Wox.Plugin.PluginIndicator/Main.cs b/Plugins/Wox.Plugin.PluginIndicator/Main.cs index 5f9ec07be..54dcf007a 100644 --- a/Plugins/Wox.Plugin.PluginIndicator/Main.cs +++ b/Plugins/Wox.Plugin.PluginIndicator/Main.cs @@ -13,8 +13,7 @@ namespace Wox.Plugin.PluginIndicator var results = from keyword in PluginManager.NonGlobalPlugins.Keys where keyword.StartsWith(query.Terms[0]) let metadata = PluginManager.NonGlobalPlugins[keyword].Metadata - let disabled = PluginManager.Settings.Plugins[metadata.ID].Disabled - where !disabled + where !metadata.Disabled select new Result { Title = keyword, diff --git a/Plugins/Wox.Plugin.Sys/Images/checkupdate.png b/Plugins/Wox.Plugin.Sys/Images/checkupdate.png new file mode 100644 index 000000000..955f6fdbb Binary files /dev/null and b/Plugins/Wox.Plugin.Sys/Images/checkupdate.png differ diff --git a/Plugins/Wox.Plugin.Sys/Main.cs b/Plugins/Wox.Plugin.Sys/Main.cs index e888dbb37..f6be3a435 100644 --- a/Plugins/Wox.Plugin.Sys/Main.cs +++ b/Plugins/Wox.Plugin.Sys/Main.cs @@ -234,6 +234,20 @@ namespace Wox.Plugin.Sys context.API.GetTranslation("wox_plugin_sys_dlgtext_all_applicableplugins_reloaded")); return true; } + }, + new Result + { + Title = "Check For Update", + SubTitle = "Check for new Wox update", + IcoPath = "Images\\checkupdate.png", + Action = c => + { + Application.Current.MainWindow.Hide(); + context.API.CheckForNewUpdate(); + context.API.ShowMsg("Please wait...", + "Checking for new update"); + return true; + } } }); return results; diff --git a/Plugins/Wox.Plugin.Sys/Wox.Plugin.Sys.csproj b/Plugins/Wox.Plugin.Sys/Wox.Plugin.Sys.csproj index a2c1a9ee0..9fe2b0cbb 100644 --- a/Plugins/Wox.Plugin.Sys/Wox.Plugin.Sys.csproj +++ b/Plugins/Wox.Plugin.Sys/Wox.Plugin.Sys.csproj @@ -38,9 +38,15 @@ + + PreserveNewest + PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/README.md b/README.md index 2b9da637f..00069024a 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,22 @@ Features - Search for everything—applications, **uwp**, folders, files and more. - Use *pinyin* to search for programs / 支持用 **拼音** 搜索程序 - wyy / wangyiyun → 网易云音乐 -- Keyword plugin search - - search google with `g search_term` +- Keyword plugin search `g search_term` +- Search youtube, google, twitter and many more - Build custom themes at http://www.wox.one/theme/builder - Install plugins from http://www.wox.one/plugin +**New from this fork:** +- Portable mode +- Drastically improved search experience +- Search all subfolders and files +- Option to always run CMD or Powershell as administrator +- Run CMD, Powershell and programs as a different user +- Manage what programs should be loaded +- Highlighting of how results are matched during query search +- Open web search result as a tab or a new window +- Automatic update +- Reload/update plugin data Installation ------------ @@ -42,8 +53,8 @@ Versions marked as **pre-release** are unstable pre-release versions. - Requirements: - .net >= 4.5.2 - - [everything](https://www.voidtools.com/): `.exe` installer + use x64 if your windows is x64 + everything service is running - - [python3](https://www.python.org/downloads/): `.exe` installer + add it to `%PATH%` or set it in WoX settings + - If you want to integrate with [everything](https://www.voidtools.com/): `.exe` installer + use x64 if your windows is x64 + everything service is running. Supported version is 1.3.4.686 + - If you use python plugins, install [python3](https://www.python.org/downloads/): `.exe` installer + add it to `%PATH%` or set it in WoX settings Usage ----- diff --git a/Wox.Core/Plugin/PluginManager.cs b/Wox.Core/Plugin/PluginManager.cs index fc9afb740..0166690b7 100644 --- a/Wox.Core/Plugin/PluginManager.cs +++ b/Wox.Core/Plugin/PluginManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; @@ -92,21 +93,36 @@ namespace Wox.Core.Plugin Settings.UpdatePluginSettings(_metadatas); AllPlugins = PluginsLoader.Plugins(_metadatas, Settings); } + + /// + /// Call initialize for all plugins + /// + /// return the list of failed to init plugins or null for none public static void InitializePlugins(IPublicAPI api) { API = api; + var failedPlugins = new ConcurrentQueue(); Parallel.ForEach(AllPlugins, pair => { - var milliseconds = Stopwatch.Debug($"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>", () => + try { - pair.Plugin.Init(new PluginInitContext + var milliseconds = Stopwatch.Debug($"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>", () => { - CurrentPluginMetadata = pair.Metadata, - API = API + pair.Plugin.Init(new PluginInitContext + { + CurrentPluginMetadata = pair.Metadata, + API = API + }); }); - }); - pair.Metadata.InitTime += milliseconds; - Log.Info($"|PluginManager.InitializePlugins|Total init cost for <{pair.Metadata.Name}> is <{pair.Metadata.InitTime}ms>"); + pair.Metadata.InitTime += milliseconds; + Log.Info($"|PluginManager.InitializePlugins|Total init cost for <{pair.Metadata.Name}> is <{pair.Metadata.InitTime}ms>"); + } + catch (Exception e) + { + Log.Exception(nameof(PluginManager), $"Fail to Init plugin: {pair.Metadata.Name}", e); + pair.Metadata.Disabled = true; + failedPlugins.Enqueue(pair); + } }); _contextMenuPlugins = GetPluginsForInterface(); @@ -121,6 +137,11 @@ namespace Wox.Core.Plugin .ForEach(x => NonGlobalPlugins[x] = plugin); } + if (failedPlugins.Any()) + { + var failed = string.Join(",", failedPlugins.Select(x => x.Metadata.Name)); + API.ShowMsg($"Fail to Init Plugins", $"Plugins: {failed} - fail to load and would be disabled, please contact plugin creator for help", "", false); + } } public static void InstallPlugin(string path) @@ -128,35 +149,6 @@ namespace Wox.Core.Plugin PluginInstaller.Install(path); } - public static Query QueryInit(string text) //todo is that possible to move it into type Query? - { - // replace multiple white spaces with one white space - var terms = text.Split(new[] { Query.TermSeperater }, StringSplitOptions.RemoveEmptyEntries); - var rawQuery = string.Join(Query.TermSeperater, terms); - var actionKeyword = string.Empty; - var search = rawQuery; - var actionParameters = terms.ToList(); - if (terms.Length == 0) return null; - if (NonGlobalPlugins.ContainsKey(terms[0]) && - !Settings.Plugins[NonGlobalPlugins[terms[0]].Metadata.ID].Disabled) - { - actionKeyword = terms[0]; - actionParameters = terms.Skip(1).ToList(); - search = string.Join(Query.TermSeperater, actionParameters.ToArray()); - } - var query = new Query - { - Terms = terms, - RawQuery = rawQuery, - ActionKeyword = actionKeyword, - Search = search, - // Obsolete value initialisation - ActionName = actionKeyword, - ActionParameters = actionParameters - }; - return query; - } - public static List ValidPluginsForQuery(Query query) { if (NonGlobalPlugins.ContainsKey(query.ActionKeyword)) diff --git a/Wox.Core/Plugin/QueryBuilder.cs b/Wox.Core/Plugin/QueryBuilder.cs new file mode 100644 index 000000000..b01a93291 --- /dev/null +++ b/Wox.Core/Plugin/QueryBuilder.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Wox.Plugin; + +namespace Wox.Core.Plugin +{ + public static class QueryBuilder + { + public static Query Build(string text, Dictionary nonGlobalPlugins) + { + // replace multiple white spaces with one white space + var terms = text.Split(new[] { Query.TermSeperater }, StringSplitOptions.RemoveEmptyEntries); + if (terms.Length == 0) + { // nothing was typed + return null; + } + + var rawQuery = string.Join(Query.TermSeperater, terms); + string actionKeyword, search; + string possibleActionKeyword = terms[0]; + List actionParameters; + if (nonGlobalPlugins.TryGetValue(possibleActionKeyword, out var pluginPair) && !pluginPair.Metadata.Disabled) + { // use non global plugin for query + actionKeyword = possibleActionKeyword; + actionParameters = terms.Skip(1).ToList(); + search = actionParameters.Count > 0 ? rawQuery.Substring(actionKeyword.Length + 1) : string.Empty; + } + else + { // non action keyword + actionKeyword = string.Empty; + actionParameters = terms.ToList(); + search = rawQuery; + } + + var query = new Query + { + Terms = terms, + RawQuery = rawQuery, + ActionKeyword = actionKeyword, + Search = search, + // Obsolete value initialisation + ActionName = actionKeyword, + ActionParameters = actionParameters + }; + + return query; + } + } +} \ No newline at end of file diff --git a/Wox.Core/Updater.cs b/Wox.Core/Updater.cs index 971995f5e..9262d78f4 100644 --- a/Wox.Core/Updater.cs +++ b/Wox.Core/Updater.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Net; using System.Net.Http; @@ -10,9 +10,11 @@ using JetBrains.Annotations; using Squirrel; using Newtonsoft.Json; using Wox.Core.Resource; +using Wox.Plugin.SharedCommands; using Wox.Infrastructure; using Wox.Infrastructure.Http; using Wox.Infrastructure.Logger; +using System.IO; namespace Wox.Core { @@ -25,14 +27,14 @@ namespace Wox.Core GitHubRepository = gitHubRepository; } - public async Task UpdateApp() + public async Task UpdateApp(bool silentIfLatestVersion = true) { - UpdateManager m; - UpdateInfo u; + UpdateManager updateManager; + UpdateInfo newUpdateInfo; try { - m = await GitHubUpdateManager(GitHubRepository); + updateManager = await GitHubUpdateManager(GitHubRepository); } catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException) { @@ -43,42 +45,61 @@ namespace Wox.Core try { // UpdateApp CheckForUpdate will return value only if the app is squirrel installed - u = await m.CheckForUpdate().NonNull(); + newUpdateInfo = await updateManager.CheckForUpdate().NonNull(); } catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException) { Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to api.github.com.", e); - m.Dispose(); + updateManager.Dispose(); return; } - var fr = u.FutureReleaseEntry; - var cr = u.CurrentlyInstalledVersion; - Log.Info($"|Updater.UpdateApp|Future Release <{fr.Formatted()}>"); - if (fr.Version > cr.Version) + var newReleaseVersion = Version.Parse(newUpdateInfo.FutureReleaseEntry.Version.ToString()); + var currentVersion = Version.Parse(Constant.Version); + + Log.Info($"|Updater.UpdateApp|Future Release <{newUpdateInfo.FutureReleaseEntry.Formatted()}>"); + + if (newReleaseVersion <= currentVersion) { - try - { - await m.DownloadReleases(u.ReleasesToApply); - } - catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException) - { - Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e); - m.Dispose(); - return; - } - - await m.ApplyReleases(u); - await m.CreateUninstallerRegistryEntry(); - - var newVersionTips = this.NewVersinoTips(fr.Version.ToString()); - - MessageBox.Show(newVersionTips); - Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}"); + if (!silentIfLatestVersion) + MessageBox.Show("You already have the latest Wox version"); + updateManager.Dispose(); + return; } + try + { + await updateManager.DownloadReleases(newUpdateInfo.ReleasesToApply); + } + catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException) + { + Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e); + updateManager.Dispose(); + return; + } + + await updateManager.ApplyReleases(newUpdateInfo); + + if (Constant.IsPortableMode) + { + var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{Constant.PortableFolderName}"; + FilesFolders.Copy(Constant.PortableDataPath, targetDestination); + if (!FilesFolders.VerifyBothFolderFilesEqual(Constant.PortableDataPath, targetDestination)) + MessageBox.Show(string.Format("Wox was not able to move your user profile data to the new update version. Please manually" + + "move your profile data folder from {0} to {1}", Constant.PortableDataPath, targetDestination)); + } + else + { + await updateManager.CreateUninstallerRegistryEntry(); + } + + var newVersionTips = NewVersinoTips(newReleaseVersion.ToString()); + + MessageBox.Show(newVersionTips); + Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}"); + // always dispose UpdateManager - m.Dispose(); + updateManager.Dispose(); } [UsedImplicitly] diff --git a/Wox.Infrastructure/Logger/Log.cs b/Wox.Infrastructure/Logger/Log.cs index 10e8128c5..349920076 100644 --- a/Wox.Infrastructure/Logger/Log.cs +++ b/Wox.Infrastructure/Logger/Log.cs @@ -11,7 +11,7 @@ namespace Wox.Infrastructure.Logger { public const string DirectoryName = "Logs"; - public static string CurrentLogDirectory { get; private set; } + public static string CurrentLogDirectory { get; } static Log() { @@ -53,6 +53,14 @@ namespace Wox.Infrastructure.Logger [MethodImpl(MethodImplOptions.Synchronized)] public static void Exception(string className, string message, System.Exception exception, [CallerMemberName] string methodName = "") + { + var classNameWithMethod = CheckClassAndMessageAndReturnFullClassWithMethod(className, message, methodName); + + ExceptionInternal(classNameWithMethod, message, exception); + } + + private static string CheckClassAndMessageAndReturnFullClassWithMethod(string className, string message, + string methodName) { if (string.IsNullOrWhiteSpace(className)) { @@ -60,16 +68,17 @@ namespace Wox.Infrastructure.Logger } if (string.IsNullOrWhiteSpace(message)) - { // todo: not sure we really need that + { + // todo: not sure we really need that LogFaultyFormat($"Fail to specify a message during logging"); } if (!string.IsNullOrWhiteSpace(methodName)) { - className += "." + methodName; + return className + "." + methodName; } - ExceptionInternal(className, message, exception); + return className; } private static void ExceptionInternal(string classAndMethod, string message, System.Exception e) @@ -140,18 +149,48 @@ namespace Wox.Infrastructure.Logger LogInternal(message, LogLevel.Error); } + public static void Error(string className, string message, [CallerMemberName] string methodName = "") + { + LogInternal(LogLevel.Error, className, message, methodName); + } + + private static void LogInternal(LogLevel level, string className, string message, [CallerMemberName] string methodName = "") + { + var classNameWithMethod = CheckClassAndMessageAndReturnFullClassWithMethod(className, message, methodName); + + var logger = LogManager.GetLogger(classNameWithMethod); + + System.Diagnostics.Debug.WriteLine($"{level.Name}|{message}"); + logger.Log(level, message); + } + + public static void Debug(string className, string message, [CallerMemberName] string methodName = "") + { + LogInternal(LogLevel.Debug, className, message, methodName); + } + /// example: "|prefix|unprefixed" public static void Debug(string message) { LogInternal(message, LogLevel.Debug); } + public static void Info(string className, string message, [CallerMemberName] string methodName = "") + { + LogInternal(LogLevel.Info, className, message, methodName); + } + /// example: "|prefix|unprefixed" public static void Info(string message) { LogInternal(message, LogLevel.Info); } + public static void Warn(string className, string message, [CallerMemberName] string methodName = "") + { + LogInternal(LogLevel.Warn, className, message, methodName); + } + /// example: "|prefix|unprefixed" public static void Warn(string message) { diff --git a/Wox.Infrastructure/UserSettings/PluginSettings.cs b/Wox.Infrastructure/UserSettings/PluginSettings.cs index c47fe7c15..346d98e53 100644 --- a/Wox.Infrastructure/UserSettings/PluginSettings.cs +++ b/Wox.Infrastructure/UserSettings/PluginSettings.cs @@ -28,7 +28,7 @@ namespace Wox.Infrastructure.UserSettings { ID = metadata.ID, Name = metadata.Name, - ActionKeywords = metadata.ActionKeywords, + ActionKeywords = metadata.ActionKeywords, Disabled = metadata.Disabled }; } @@ -39,7 +39,11 @@ namespace Wox.Infrastructure.UserSettings { public string ID { get; set; } public string Name { get; set; } - public List ActionKeywords { get; set; } + public List ActionKeywords { get; set; } // a reference of the action keywords from plugin manager + + /// + /// Used only to save the state of the plugin in settings + /// public bool Disabled { get; set; } } } diff --git a/Wox.Infrastructure/Wox.cs b/Wox.Infrastructure/Wox.cs index 396ee0bb1..d09e7b904 100644 --- a/Wox.Infrastructure/Wox.cs +++ b/Wox.Infrastructure/Wox.cs @@ -7,12 +7,22 @@ namespace Wox.Infrastructure { public static class Constant { + public const string Wox = "Wox"; + public const string Plugins = "Plugins"; + + private static readonly Assembly Assembly = Assembly.GetExecutingAssembly(); + public static readonly string ProgramDirectory = Directory.GetParent(Assembly.Location.NonNull()).ToString(); + public static readonly string ExecutablePath = Path.Combine(ProgramDirectory, Wox + ".exe"); + + public static bool IsPortableMode; + public const string PortableFolderName = "UserData"; + public static string PortableDataPath = Path.Combine(ProgramDirectory, PortableFolderName); public static string DetermineDataDirectory() { - string portableDataPath = Path.Combine(ProgramDirectory, "UserData"); - if (Directory.Exists(portableDataPath)) + if (Directory.Exists(PortableDataPath)) { - return portableDataPath; + IsPortableMode = true; + return PortableDataPath; } else { @@ -20,12 +30,6 @@ namespace Wox.Infrastructure } } - public const string Wox = "Wox"; - public const string Plugins = "Plugins"; - - private static readonly Assembly Assembly = Assembly.GetExecutingAssembly(); - public static readonly string ProgramDirectory = Directory.GetParent(Assembly.Location.NonNull()).ToString(); - public static readonly string ExecutablePath = Path.Combine(ProgramDirectory, Wox + ".exe"); public static readonly string DataDirectory = DetermineDataDirectory(); public static readonly string PluginsDirectory = Path.Combine(DataDirectory, Plugins); public static readonly string PreinstalledDirectory = Path.Combine(ProgramDirectory, Plugins); diff --git a/Wox.Plugin/IPublicAPI.cs b/Wox.Plugin/IPublicAPI.cs index eb3f18fa7..754b76d36 100644 --- a/Wox.Plugin/IPublicAPI.cs +++ b/Wox.Plugin/IPublicAPI.cs @@ -70,13 +70,18 @@ namespace Wox.Plugin /// void ReloadAllPluginData(); + /// + /// Check for new Wox update + /// + void CheckForNewUpdate(); + /// /// Show message box /// /// Message title /// Message subtitle /// Message icon path (relative path to your plugin folder) - void ShowMsg(string title, string subTitle = "", string iconPath = ""); + void ShowMsg(string title, string subTitle = "", string iconPath = "", bool useMainWindowAsOwner = true); /// /// Open setting dialog diff --git a/Wox.Plugin/PluginMetadata.cs b/Wox.Plugin/PluginMetadata.cs index 20637ee48..78a036b3c 100644 --- a/Wox.Plugin/PluginMetadata.cs +++ b/Wox.Plugin/PluginMetadata.cs @@ -46,6 +46,9 @@ namespace Wox.Plugin [Obsolete("Use IcoPath")] public string FullIcoPath => IcoPath; + /// + /// Init time include both plugin load time and init time + /// [JsonIgnore] public long InitTime { get; set; } [JsonIgnore] diff --git a/Wox.Plugin/SharedCommands/FilesFolders.cs b/Wox.Plugin/SharedCommands/FilesFolders.cs new file mode 100644 index 000000000..584a83bc6 --- /dev/null +++ b/Wox.Plugin/SharedCommands/FilesFolders.cs @@ -0,0 +1,101 @@ +using System; +using System.IO; +using System.Windows; + +namespace Wox.Plugin.SharedCommands +{ + public static class FilesFolders + { + public static void Copy(this string sourcePath, string targetPath) + { + // Get the subdirectories for the specified directory. + DirectoryInfo dir = new DirectoryInfo(sourcePath); + + if (!dir.Exists) + { + throw new DirectoryNotFoundException( + "Source directory does not exist or could not be found: " + + sourcePath); + } + + try + { + DirectoryInfo[] dirs = dir.GetDirectories(); + // If the destination directory doesn't exist, create it. + if (!Directory.Exists(targetPath)) + { + Directory.CreateDirectory(targetPath); + } + + // Get the files in the directory and copy them to the new location. + FileInfo[] files = dir.GetFiles(); + foreach (FileInfo file in files) + { + string temppath = Path.Combine(targetPath, file.Name); + file.CopyTo(temppath, false); + } + + // Recursively copy subdirectories by calling itself on each subdirectory until there are no more to copy + foreach (DirectoryInfo subdir in dirs) + { + string temppath = Path.Combine(targetPath, subdir.Name); + Copy(subdir.FullName, temppath); + } + } + catch (Exception e) + { +#if DEBUG + throw e; +#else + MessageBox.Show(string.Format("Copying path {0} has failed, it will now be deleted for consistency", targetPath)); + RemoveFolder(targetPath); +#endif + } + + } + + public static bool VerifyBothFolderFilesEqual(this string fromPath, string toPath) + { + try + { + var fromDir = new DirectoryInfo(fromPath); + var toDir = new DirectoryInfo(toPath); + + if (fromDir.GetFiles("*", SearchOption.AllDirectories).Length != toDir.GetFiles("*", SearchOption.AllDirectories).Length) + return false; + + if (fromDir.GetDirectories("*", SearchOption.AllDirectories).Length != toDir.GetDirectories("*", SearchOption.AllDirectories).Length) + return false; + + return true; + } + catch (Exception e) + { +#if DEBUG + throw e; +#else + MessageBox.Show(string.Format("Unable to verify folders and files between {0} and {1}", fromPath, toPath)); + return false; +#endif + } + + } + + public static void RemoveFolder(this string path) + { + try + { + if (Directory.Exists(path)) + Directory.Delete(path, true); + } + catch (Exception e) + { +#if DEBUG + throw e; +#else + MessageBox.Show(string.Format("Not able to delete folder {0}, please go to the location and manually delete it", path)); +#endif + } + } + } +} diff --git a/Wox.Test/QueryBuilderTest.cs b/Wox.Test/QueryBuilderTest.cs new file mode 100644 index 000000000..0402d2ae8 --- /dev/null +++ b/Wox.Test/QueryBuilderTest.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using NUnit.Framework; +using Wox.Core.Plugin; +using Wox.Plugin; + +namespace Wox.Test +{ + public class QueryBuilderTest + { + [Test] + public void ExclusivePluginQueryTest() + { + var nonGlobalPlugins = new Dictionary + { + {">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List {">"}}}} + }; + + Query q = QueryBuilder.Build("> file.txt file2 file3", nonGlobalPlugins); + + Assert.AreEqual("file.txt file2 file3", q.Search); + Assert.AreEqual(">", q.ActionKeyword); + } + + [Test] + public void ExclusivePluginQueryIgnoreDisabledTest() + { + var nonGlobalPlugins = new Dictionary + { + {">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List {">"}, Disabled = true}}} + }; + + Query q = QueryBuilder.Build("> file.txt file2 file3", nonGlobalPlugins); + + Assert.AreEqual("> file.txt file2 file3", q.Search); + } + + [Test] + public void GenericPluginQueryTest() + { + Query q = QueryBuilder.Build("file.txt file2 file3", new Dictionary()); + + Assert.AreEqual("file.txt file2 file3", q.Search); + Assert.AreEqual("", q.ActionKeyword); + + Assert.AreEqual("file.txt", q.FirstSearch); + Assert.AreEqual("file2", q.SecondSearch); + Assert.AreEqual("file3", q.ThirdSearch); + Assert.AreEqual("file2 file3", q.SecondToEndSearch); + } + } +} diff --git a/Wox.Test/QueryTest.cs b/Wox.Test/QueryTest.cs deleted file mode 100644 index b7a0917ef..000000000 --- a/Wox.Test/QueryTest.cs +++ /dev/null @@ -1,33 +0,0 @@ -using NUnit.Framework; -using Wox.Core.Plugin; -using Wox.Plugin; - -namespace Wox.Test -{ - public class QueryTest - { - [Test] - [Ignore("Current query is tightly integrated with GUI, can't be tested.")] - public void ExclusivePluginQueryTest() - { - Query q = PluginManager.QueryInit("> file.txt file2 file3"); - - Assert.AreEqual(q.FirstSearch, "file.txt"); - Assert.AreEqual(q.SecondSearch, "file2"); - Assert.AreEqual(q.ThirdSearch, "file3"); - Assert.AreEqual(q.SecondToEndSearch, "file2 file3"); - } - - [Test] - [Ignore("Current query is tightly integrated with GUI, can't be tested.")] - public void GenericPluginQueryTest() - { - Query q = PluginManager.QueryInit("file.txt file2 file3"); - - Assert.AreEqual(q.FirstSearch, "file.txt"); - Assert.AreEqual(q.SecondSearch, "file2"); - Assert.AreEqual(q.ThirdSearch, "file3"); - Assert.AreEqual(q.SecondToEndSearch, "file2 file3"); - } - } -} diff --git a/Wox/PublicAPIInstance.cs b/Wox/PublicAPIInstance.cs index ab198d6bf..58915f87b 100644 --- a/Wox/PublicAPIInstance.cs +++ b/Wox/PublicAPIInstance.cs @@ -5,6 +5,7 @@ using System.Net; using System.Threading.Tasks; using System.Windows; using Squirrel; +using Wox.Core; using Wox.Core.Plugin; using Wox.Core.Resource; using Wox.Helper; @@ -65,6 +66,11 @@ namespace Wox UpdateManager.RestartApp(); } + public void CheckForNewUpdate() + { + _settingsVM.UpdateApp(); + } + public void SaveAppAllSettings() { _mainVM.Save(); @@ -91,12 +97,12 @@ namespace Wox _mainVM.MainWindowVisibility = Visibility.Visible; } - public void ShowMsg(string title, string subTitle = "", string iconPath = "") + public void ShowMsg(string title, string subTitle = "", string iconPath = "", bool useMainWindowAsOwner = true) { Application.Current.Dispatcher.Invoke(() => { - var m = new Msg { Owner = Application.Current.MainWindow }; - m.Show(title, subTitle, iconPath); + var msg = useMainWindowAsOwner ? new Msg {Owner = Application.Current.MainWindow} : new Msg(); + msg.Show(title, subTitle, iconPath); }); } diff --git a/Wox/SettingWindow.xaml b/Wox/SettingWindow.xaml index a6f23814f..1eddd8ab6 100644 --- a/Wox/SettingWindow.xaml +++ b/Wox/SettingWindow.xaml @@ -33,7 +33,8 @@ - + @@ -51,8 +52,7 @@ - + diff --git a/Wox/SettingWindow.xaml.cs b/Wox/SettingWindow.xaml.cs index 67d67351e..52addf362 100644 --- a/Wox/SettingWindow.xaml.cs +++ b/Wox/SettingWindow.xaml.cs @@ -215,7 +215,8 @@ namespace Wox private void OnPluginToggled(object sender, RoutedEventArgs e) { var id = _viewModel.SelectedPlugin.PluginPair.Metadata.ID; - _settings.PluginSettings.Plugins[id].Disabled = _viewModel.SelectedPlugin.PluginPair.Metadata.Disabled; + // used to sync the current status from the plugin manager into the setting to keep consistency after save + _settings.PluginSettings.Plugins[id].Disabled = _viewModel.SelectedPlugin.PluginPair.Metadata.Disabled; } private void OnPluginActionKeywordsClick(object sender, MouseButtonEventArgs e) diff --git a/Wox/ViewModel/MainViewModel.cs b/Wox/ViewModel/MainViewModel.cs index bd1314a27..acdd7c040 100644 --- a/Wox/ViewModel/MainViewModel.cs +++ b/Wox/ViewModel/MainViewModel.cs @@ -377,7 +377,7 @@ namespace Wox.ViewModel ProgressBarVisibility = Visibility.Hidden; _isQueryRunning = true; - var query = PluginManager.QueryInit(QueryText.Trim()); + var query = QueryBuilder.Build(QueryText.Trim(), PluginManager.NonGlobalPlugins); if (query != null) { // handle the exclusiveness of plugin using action keyword @@ -401,8 +401,7 @@ namespace Wox.ViewModel { Parallel.ForEach(plugins, parallelOptions, plugin => { - var config = _settings.PluginSettings.Plugins[plugin.Metadata.ID]; - if (!config.Disabled) + if (!plugin.Metadata.Disabled) { var results = PluginManager.QueryForPlugin(plugin, query); UpdateResultView(results, plugin.Metadata, query); diff --git a/Wox/ViewModel/SettingWindowViewModel.cs b/Wox/ViewModel/SettingWindowViewModel.cs index 923e456b0..504e7bdfa 100644 --- a/Wox/ViewModel/SettingWindowViewModel.cs +++ b/Wox/ViewModel/SettingWindowViewModel.cs @@ -44,7 +44,7 @@ namespace Wox.ViewModel public async void UpdateApp() { - await _updater.UpdateApp(); + await _updater.UpdateApp(false); } public void Save() @@ -150,26 +150,11 @@ namespace Wox.ViewModel { get { - var plugins = PluginManager.AllPlugins; - var settings = Settings.PluginSettings.Plugins; - plugins.Sort((a, b) => - { - var d1 = settings[a.Metadata.ID].Disabled; - var d2 = settings[b.Metadata.ID].Disabled; - if (d1 == d2) - { - return string.Compare(a.Metadata.Name, b.Metadata.Name, StringComparison.CurrentCulture); - } - else - { - return d1.CompareTo(d2); - } - }); - - var metadatas = plugins.Select(p => new PluginViewModel - { - PluginPair = p, - }).ToList(); + var metadatas = PluginManager.AllPlugins + .OrderBy(x => x.Metadata.Disabled) + .ThenBy(y => y.Metadata.Name) + .Select(p => new PluginViewModel { PluginPair = p}) + .ToList(); return metadatas; } }