diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 94ceb242e..8d2c6df24 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -252,6 +252,8 @@ namespace Flow.Launcher.Core.Plugin public static bool ActionKeywordRegistered(string actionKeyword) { + // this method is only checking for action keywords (defined as not '*') registration + // hence the actionKeyword != Query.GlobalPluginWildcardSign logic return actionKeyword != Query.GlobalPluginWildcardSign && NonGlobalPlugins.ContainsKey(actionKeyword); } @@ -276,7 +278,7 @@ namespace Flow.Launcher.Core.Plugin } /// - /// used to add action keyword for multiple action keyword plugin + /// used to remove action keyword for multiple action keyword plugin /// e.g. web search /// public static void RemoveActionKeyword(string id, string oldActionkeyword) diff --git a/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs b/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs index dd768afb4..abce8b41e 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs @@ -16,11 +16,13 @@ namespace Flow.Launcher.Infrastructure.UserSettings { var settings = Plugins[metadata.ID]; - // TODO: Remove. This is one off for 1.2.0 release. - // Introduced a new action keyword in Explorer, so need to update plugin setting in the UserData folder. - // This kind of plugin meta update should be handled by a dedicated method trigger by version bump. + // TODO: Remove. This is backwards compatibility for 1.8.0 release. + // Introduced two new action keywords in Explorer, so need to update plugin setting in the UserData folder. if (metadata.ID == "572be03c74c642baae319fc283e561a8" && metadata.ActionKeywords.Count != settings.ActionKeywords.Count) - settings.ActionKeywords = metadata.ActionKeywords; + { + settings.ActionKeywords.Add(Query.GlobalPluginWildcardSign); // for index search + settings.ActionKeywords.Add(Query.GlobalPluginWildcardSign); // for path search + } if (string.IsNullOrEmpty(settings.Version)) settings.Version = metadata.Version; diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index abe8d681b..4ee15b46d 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -547,26 +547,9 @@ namespace Flow.Launcher.ViewModel private void RemoveOldQueryResults(Query query) { - string lastKeyword = _lastQuery.ActionKeyword; - - string keyword = query.ActionKeyword; - if (string.IsNullOrEmpty(lastKeyword)) + if (_lastQuery.ActionKeyword != query.ActionKeyword) { - if (!string.IsNullOrEmpty(keyword)) - { - Results.KeepResultsFor(PluginManager.NonGlobalPlugins[keyword].Metadata); - } - } - else - { - if (string.IsNullOrEmpty(keyword)) - { - Results.KeepResultsExcept(PluginManager.NonGlobalPlugins[lastKeyword].Metadata); - } - else if (lastKeyword != keyword) - { - Results.KeepResultsFor(PluginManager.NonGlobalPlugins[keyword].Metadata); - } + Results.Clear(); } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index 9ba0da3f6..a989327be 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -19,8 +19,14 @@ Quick Access Links Index Search Excluded Paths Indexing Options - Search Activation: + Search: + Path Search: File Content Search: + Index Search: + Current Action Keyword: + Done + Enabled + When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword Explorer diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-cn.xaml index c4a2322b2..dac6e908b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-cn.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-cn.xaml @@ -20,6 +20,7 @@ 索引搜索排除的路径 索引选项 搜索激活: + 路径搜索激活: 文件内容搜索: diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs index 8204e755c..92b7c95a0 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs @@ -28,7 +28,7 @@ namespace Flow.Launcher.Plugin.Explorer return new ExplorerSettings(viewModel); } - public async Task InitAsync(PluginInitContext context) + public Task InitAsync(PluginInitContext context) { Context = context; @@ -47,6 +47,8 @@ namespace Flow.Launcher.Plugin.Explorer contextMenu = new ContextMenu(Context, Settings, viewModel); searchManager = new SearchManager(Settings, Context); ResultManager.Init(Context); + + return Task.CompletedTask; } public List LoadContextMenus(Result selectedResult) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs index 1e9815cb9..595ac3610 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs @@ -10,10 +10,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search { internal static bool IsEnvironmentVariableSearch(string search) { - return LoadEnvironmentStringPaths().Count > 0 - && search.StartsWith("%") + return search.StartsWith("%") && search != "%%" - && !search.Contains("\\"); + && !search.Contains("\\") && + LoadEnvironmentStringPaths().Count > 0; } internal static Dictionary LoadEnvironmentStringPaths() diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index e9b4b0fc1..6f3996b0d 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -26,6 +26,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search { private static PathEqualityComparator instance; public static PathEqualityComparator Instance => instance ??= new PathEqualityComparator(); + public bool Equals(Result x, Result y) { return x.SubTitle == y.SubTitle; @@ -39,21 +40,61 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal async Task> SearchAsync(Query query, CancellationToken token) { - var results = new HashSet(PathEqualityComparator.Instance); - var querySearch = query.Search; if (IsFileContentSearch(query.ActionKeyword)) return await WindowsIndexFileContentSearchAsync(query, querySearch, token).ConfigureAwait(false); + var result = new HashSet(PathEqualityComparator.Instance); + + if (ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword) || + ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword)) + { + result.UnionWith(await PathSearchAsync(query, token).ConfigureAwait(false)); + } + + if ((ActionKeywordMatch(query, Settings.ActionKeyword.IndexSearchActionKeyword) || + ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword)) && + querySearch.Length > 0 && + !querySearch.IsLocationPathString()) + { + result.UnionWith(await WindowsIndexFilesAndFoldersSearchAsync(query, querySearch, token) + .ConfigureAwait(false)); + } + + return result.ToList(); + } + + private bool ActionKeywordMatch(Query query, Settings.ActionKeyword allowedActionKeyword) + { + var keyword = query.ActionKeyword.Length == 0 ? Query.GlobalPluginWildcardSign : query.ActionKeyword; + + return allowedActionKeyword switch + { + Settings.ActionKeyword.SearchActionKeyword => settings.EnableSearchActionKeyword && + keyword == settings.SearchActionKeyword, + Settings.ActionKeyword.PathSearchActionKeyword => settings.EnabledPathSearchKeyword && + keyword == settings.PathSearchActionKeyword, + Settings.ActionKeyword.FileContentSearchActionKeyword => keyword == + settings.FileContentSearchActionKeyword, + Settings.ActionKeyword.IndexSearchActionKeyword => settings.EnabledIndexOnlySearchKeyword && + keyword == settings.IndexSearchActionKeyword + }; + } + + public async Task> PathSearchAsync(Query query, CancellationToken token = default) + { + var querySearch = query.Search; + // This allows the user to type the assigned action keyword and only see the list of quick folder links if (string.IsNullOrEmpty(query.Search)) return QuickAccess.AccessLinkListAll(query, settings.QuickAccessLinks); + var results = new HashSet(PathEqualityComparator.Instance); + var quickaccessLinks = QuickAccess.AccessLinkListMatched(query, settings.QuickAccessLinks); - if (quickaccessLinks.Count > 0) - results.UnionWith(quickaccessLinks); + results.UnionWith(quickaccessLinks); var isEnvironmentVariable = EnvironmentVariables.IsEnvironmentVariableSearch(querySearch); @@ -63,13 +104,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search // Query is a location path with a full environment variable, eg. %appdata%\somefolder\ var isEnvironmentVariablePath = querySearch[1..].Contains("%\\"); - if (!querySearch.IsLocationPathString() && !isEnvironmentVariablePath) - { - results.UnionWith(await WindowsIndexFilesAndFoldersSearchAsync(query, querySearch, token).ConfigureAwait(false)); - - return results.ToList(); - } - var locationPath = querySearch; if (isEnvironmentVariablePath) @@ -99,7 +133,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search return results.ToList(); } - private async Task> WindowsIndexFileContentSearchAsync(Query query, string querySearchString, CancellationToken token) + private async Task> WindowsIndexFileContentSearchAsync(Query query, string querySearchString, + CancellationToken token) { var queryConstructor = new QueryConstructor(settings); @@ -107,11 +142,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search return new List(); return await IndexSearch.WindowsIndexSearchAsync(querySearchString, - queryConstructor.CreateQueryHelper().ConnectionString, - queryConstructor.QueryForFileContentSearch, - settings.IndexSearchExcludedSubdirectoryPaths, - query, - token).ConfigureAwait(false); + queryConstructor.CreateQueryHelper().ConnectionString, + queryConstructor.QueryForFileContentSearch, + settings.IndexSearchExcludedSubdirectoryPaths, + query, + token).ConfigureAwait(false); } public bool IsFileContentSearch(string actionKeyword) @@ -138,28 +173,30 @@ namespace Flow.Launcher.Plugin.Explorer.Search return await windowsIndexSearch(query, querySearchString, token); } - private async Task> WindowsIndexFilesAndFoldersSearchAsync(Query query, string querySearchString, CancellationToken token) + private async Task> WindowsIndexFilesAndFoldersSearchAsync(Query query, string querySearchString, + CancellationToken token) { var queryConstructor = new QueryConstructor(settings); return await IndexSearch.WindowsIndexSearchAsync(querySearchString, - queryConstructor.CreateQueryHelper().ConnectionString, - queryConstructor.QueryForAllFilesAndFolders, - settings.IndexSearchExcludedSubdirectoryPaths, - query, - token).ConfigureAwait(false); + queryConstructor.CreateQueryHelper().ConnectionString, + queryConstructor.QueryForAllFilesAndFolders, + settings.IndexSearchExcludedSubdirectoryPaths, + query, + token).ConfigureAwait(false); } - private async Task> WindowsIndexTopLevelFolderSearchAsync(Query query, string path, CancellationToken token) + private async Task> WindowsIndexTopLevelFolderSearchAsync(Query query, string path, + CancellationToken token) { var queryConstructor = new QueryConstructor(settings); return await IndexSearch.WindowsIndexSearchAsync(path, - queryConstructor.CreateQueryHelper().ConnectionString, - queryConstructor.QueryForTopLevelDirectorySearch, - settings.IndexSearchExcludedSubdirectoryPaths, - query, - token).ConfigureAwait(false); + queryConstructor.CreateQueryHelper().ConnectionString, + queryConstructor.QueryForTopLevelDirectorySearch, + settings.IndexSearchExcludedSubdirectoryPaths, + query, + token).ConfigureAwait(false); } private bool UseWindowsIndexForDirectorySearch(string locationPath) @@ -170,11 +207,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search return false; if (settings.IndexSearchExcludedSubdirectoryPaths - .Any(x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(pathToDirectory) - .StartsWith(x.Path, StringComparison.OrdinalIgnoreCase))) + .Any(x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(pathToDirectory) + .StartsWith(x.Path, StringComparison.OrdinalIgnoreCase))) return false; return IndexSearch.PathIsIndexed(pathToDirectory); } } -} +} \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index a8eac986d..bd6fe7e20 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -1,6 +1,9 @@ using Flow.Launcher.Plugin.Explorer.Search; using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; +using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption; +using System; using System.Collections.Generic; +using System.IO; namespace Flow.Launcher.Plugin.Explorer { @@ -18,7 +21,57 @@ namespace Flow.Launcher.Plugin.Explorer public List IndexSearchExcludedSubdirectoryPaths { get; set; } = new List(); public string SearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign; + public bool EnableSearchActionKeyword { get; set; } = true; public string FileContentSearchActionKeyword { get; set; } = Constants.DefaultContentSearchActionKeyword; + + public string PathSearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign; + + public bool EnabledPathSearchKeyword { get; set; } + + public string IndexSearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign; + + public bool EnabledIndexOnlySearchKeyword { get; set; } + + internal enum ActionKeyword + { + SearchActionKeyword, + PathSearchActionKeyword, + FileContentSearchActionKeyword, + IndexSearchActionKeyword + } + + internal string GetActionKeyword(ActionKeyword actionKeyword) => actionKeyword switch + { + ActionKeyword.SearchActionKeyword => SearchActionKeyword, + ActionKeyword.PathSearchActionKeyword => PathSearchActionKeyword, + ActionKeyword.FileContentSearchActionKeyword => FileContentSearchActionKeyword, + ActionKeyword.IndexSearchActionKeyword => IndexSearchActionKeyword + }; + + internal void SetActionKeyword(ActionKeyword actionKeyword, string keyword) => _ = actionKeyword switch + { + ActionKeyword.SearchActionKeyword => SearchActionKeyword = keyword, + ActionKeyword.PathSearchActionKeyword => PathSearchActionKeyword = keyword, + ActionKeyword.FileContentSearchActionKeyword => FileContentSearchActionKeyword = keyword, + ActionKeyword.IndexSearchActionKeyword => IndexSearchActionKeyword = keyword, + _ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "Unexpected property") + }; + + internal bool? GetActionKeywordEnable(ActionKeyword actionKeyword) => actionKeyword switch + { + ActionKeyword.SearchActionKeyword => EnableSearchActionKeyword, + ActionKeyword.PathSearchActionKeyword => EnabledPathSearchKeyword, + ActionKeyword.IndexSearchActionKeyword => EnabledIndexOnlySearchKeyword, + _ => null + }; + + internal void SetActionKeywordEnable(ActionKeyword actionKeyword, bool enable) => _ = actionKeyword switch + { + ActionKeyword.SearchActionKeyword => EnableSearchActionKeyword = enable, + ActionKeyword.PathSearchActionKeyword => EnabledPathSearchKeyword = enable, + ActionKeyword.IndexSearchActionKeyword => EnabledIndexOnlySearchKeyword = enable, + _ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "Unexpected property") + }; } } \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index 92932bf4c..77ec5457b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -41,18 +41,15 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels Process.Start(psi); } - internal void UpdateActionKeyword(string newActionKeyword, string oldActionKeyword) + internal void UpdateActionKeyword(Settings.ActionKeyword modifiedActionKeyword, string newActionKeyword, string oldActionKeyword) { PluginManager.ReplaceActionKeyword(Context.CurrentPluginMetadata.ID, oldActionKeyword, newActionKeyword); - - if (Settings.FileContentSearchActionKeyword == oldActionKeyword) - Settings.FileContentSearchActionKeyword = newActionKeyword; - - if (Settings.SearchActionKeyword == oldActionKeyword) - Settings.SearchActionKeyword = newActionKeyword; } - internal bool IsActionKeywordAlreadyAssigned(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword); + internal bool IsActionKeywordAlreadyAssigned(string newActionKeyword) + { + return PluginManager.ActionKeywordRegistered(newActionKeyword); + } internal bool IsNewActionKeywordGlobal(string newActionKeyword) => newActionKeyword == Query.GlobalPluginWildcardSign; } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml index 0e1c7e872..19ff624b0 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml @@ -7,6 +7,7 @@ mc:Ignorable="d" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" + DataContext="{Binding RelativeSource={RelativeSource Self}}" Title="Action Keyword Setting" Height="200" Width="500"> @@ -16,21 +17,24 @@ + - + - - -