diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml
index c40040df5be..43a34c8a6e5 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml
@@ -32,6 +32,7 @@
Add
General Setting
Customise Action Keywords
+ Exclude Quick Access results when using action keywords
Customise Quick Access
Quick Access Links
Everything Setting
@@ -58,6 +59,8 @@
File Content Search:
Index Search:
Quick Access:
+ Folder Search:
+ File Search:
Current Action Keyword
Done
Enabled
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
index d7b0690828a..235994cbacf 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
@@ -1,13 +1,14 @@
-using Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo;
-using Flow.Launcher.Plugin.Explorer.Search.Everything;
-using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
-using Flow.Launcher.Plugin.SharedCommands;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Flow.Launcher.Plugin.Explorer.Exceptions;
+using Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo;
+using Flow.Launcher.Plugin.Explorer.Search.Everything;
+using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
+using Flow.Launcher.Plugin.SharedCommands;
+using static Flow.Launcher.Plugin.Explorer.Settings;
using Path = System.IO.Path;
namespace Flow.Launcher.Plugin.Explorer.Search
@@ -47,45 +48,43 @@ public int GetHashCode(Result obj)
internal async Task> SearchAsync(Query query, CancellationToken token)
{
var results = new HashSet(PathEqualityComparator.Instance);
+ var keyword = query.ActionKeyword.Length == 0 ? Query.GlobalPluginWildcardSign : query.ActionKeyword;
+ var isPathSearch = query.Search.IsLocationPathString()
+ || EnvironmentVariables.IsEnvironmentVariableSearch(query.Search)
+ || EnvironmentVariables.HasEnvironmentVar(query.Search);
- // This allows the user to type the below action keywords and see/search the list of quick folder links
- if (ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword)
- || ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword)
- || ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword)
- || ActionKeywordMatch(query, Settings.ActionKeyword.IndexSearchActionKeyword)
- || ActionKeywordMatch(query, Settings.ActionKeyword.FileContentSearchActionKeyword))
+ // If action keyword is enabled and matched, get the active action keyword.
+ var activeActionKeyword = Settings.GetActiveActionKeyword(keyword);
+
+ // No action keyword matched - plugin should not handle this query, return empty results.
+ if (activeActionKeyword == null && !isPathSearch)
{
- if (string.IsNullOrEmpty(query.Search) && ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword))
- return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks);
+ return [];
}
- else
+
+ // If no action keyword matched but the query is a path search, set active action keyword to path search.
+ if (activeActionKeyword == null && isPathSearch) activeActionKeyword = ActionKeyword.PathSearchActionKeyword;
+
+ // This allows the user to type the below action keywords and see/search the list of quick folder links
+ if (string.IsNullOrEmpty(query.Search)
+ && activeActionKeyword.Equals(ActionKeyword.QuickAccessActionKeyword))
{
- // No action keyword matched- plugin should not handle this query, return empty results.
- return new List();
+ return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks);
}
IAsyncEnumerable searchResults;
- bool isPathSearch = query.Search.IsLocationPathString()
- || EnvironmentVariables.IsEnvironmentVariableSearch(query.Search)
- || EnvironmentVariables.HasEnvironmentVar(query.Search);
-
string engineName;
- switch (isPathSearch)
+ switch (activeActionKeyword.Equals(ActionKeyword.PathSearchActionKeyword))
{
- case true
- when ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword)
- || ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword):
-
+ case true:
results.UnionWith(await PathSearchAsync(query, token).ConfigureAwait(false));
-
- return results.ToList();
+ return [.. results];
case false
- when ActionKeywordMatch(query, Settings.ActionKeyword.FileContentSearchActionKeyword):
-
// Intentionally require enabling of Everything's content search due to its slowness
+ when activeActionKeyword.Equals(ActionKeyword.FileContentSearchActionKeyword):
if (Settings.ContentIndexProvider is EverythingSearchManager && !Settings.EnableEverythingContentSearch)
return EverythingContentSearchResult(query);
@@ -94,36 +93,31 @@ when ActionKeywordMatch(query, Settings.ActionKeyword.FileContentSearchActionKey
break;
case false
- when ActionKeywordMatch(query, Settings.ActionKeyword.IndexSearchActionKeyword)
- || ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword):
+ when activeActionKeyword.Equals(ActionKeyword.QuickAccessActionKeyword):
+ return QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);
+ default:
searchResults = Settings.IndexProvider.SearchAsync(query.Search, token);
engineName = Enum.GetName(Settings.IndexSearchEngine);
break;
-
- case true or false
- when ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword):
- return QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);
-
- default:
- return results.ToList();
}
// Merge Quick Access Link results for non-path searches.
- results.UnionWith(QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks));
-
+ MergeQuickAccessInResultsIfQueryMatch(results, query, activeActionKeyword);
try
{
await foreach (var search in searchResults.WithCancellation(token).ConfigureAwait(false))
- if (search.Type == ResultType.File && IsExcludedFile(search)) {
+ {
+ if (ShouldSkip(activeActionKeyword!.Value, search))
+ {
continue;
- } else {
- results.Add(ResultManager.CreateResult(query, search));
}
+ results.Add(ResultManager.CreateResult(query, search));
+ }
}
catch (OperationCanceledException)
{
- return new List();
+ return [];
}
catch (EngineNotAvailableException)
{
@@ -137,33 +131,13 @@ when ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword):
results.RemoveWhere(r => Settings.IndexSearchExcludedSubdirectoryPaths.Any(
excludedPath => FilesFolders.PathContains(excludedPath.Path, r.SubTitle, allowEqual: true)));
- return results.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.SearchActionKeywordEnabled &&
- keyword == Settings.SearchActionKeyword,
- Settings.ActionKeyword.PathSearchActionKeyword => Settings.PathSearchKeywordEnabled &&
- keyword == Settings.PathSearchActionKeyword,
- Settings.ActionKeyword.FileContentSearchActionKeyword => Settings.FileContentSearchKeywordEnabled &&
- keyword == Settings.FileContentSearchActionKeyword,
- Settings.ActionKeyword.IndexSearchActionKeyword => Settings.IndexSearchKeywordEnabled &&
- keyword == Settings.IndexSearchActionKeyword,
- Settings.ActionKeyword.QuickAccessActionKeyword => Settings.QuickAccessKeywordEnabled &&
- keyword == Settings.QuickAccessActionKeyword,
- _ => throw new ArgumentOutOfRangeException(nameof(allowedActionKeyword), allowedActionKeyword, "actionKeyword out of range")
- };
+ return [.. results];
}
private List EverythingContentSearchResult(Query query)
{
- return new List()
- {
+ return
+ [
new()
{
Title = Localize.flowlauncher_plugin_everything_enable_content_search(),
@@ -176,7 +150,7 @@ private List EverythingContentSearchResult(Query query)
return false;
}
}
- };
+ ];
}
private async Task> PathSearchAsync(Query query, CancellationToken token = default)
@@ -197,7 +171,7 @@ private async Task> PathSearchAsync(Query query, CancellationToken
// Check that actual location exists, otherwise directory search will throw directory not found exception
if (!FilesFolders.ReturnPreviousDirectoryIfIncompleteString(path).LocationExists())
- return results.ToList();
+ return [.. results];
var useIndexSearch = Settings.IndexSearchEngine is Settings.IndexSearchEngineOption.WindowsIndex
&& UseWindowsIndexForDirectorySearch(path);
@@ -209,7 +183,7 @@ private async Task> PathSearchAsync(Query query, CancellationToken
: ResultManager.CreateOpenCurrentFolderResult(retrievedDirectoryPath, query.ActionKeyword, useIndexSearch));
if (token.IsCancellationRequested)
- return new List();
+ return [];
IAsyncEnumerable directoryResult;
@@ -231,7 +205,7 @@ private async Task> PathSearchAsync(Query query, CancellationToken
}
if (token.IsCancellationRequested)
- return new List();
+ return [];
try
{
@@ -246,14 +220,14 @@ private async Task> PathSearchAsync(Query query, CancellationToken
}
- return results.ToList();
+ return [.. results];
}
public bool IsFileContentSearch(string actionKeyword) => actionKeyword == Settings.FileContentSearchActionKeyword;
public static bool UseIndexSearch(string path)
{
- if (Main.Settings.IndexSearchEngine is not Settings.IndexSearchEngineOption.WindowsIndex)
+ if (Main.Settings.IndexSearchEngine is not IndexSearchEngineOption.WindowsIndex)
return false;
// Check if the path is using windows index search
@@ -275,10 +249,48 @@ private bool UseWindowsIndexForDirectorySearch(string locationPath)
private bool IsExcludedFile(SearchResult result)
{
- string[] excludedFileTypes = Settings.ExcludedFileTypes.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+ string[] excludedFileTypes = Settings.ExcludedFileTypes.Split([','], StringSplitOptions.RemoveEmptyEntries);
string fileExtension = Path.GetExtension(result.FullPath).TrimStart('.');
return excludedFileTypes.Contains(fileExtension, StringComparer.OrdinalIgnoreCase);
}
+
+ private bool ShouldSkip(ActionKeyword actionKeywordActive, SearchResult search)
+ {
+ // Is excluded file type
+ if (search.Type == ResultType.File && IsExcludedFile(search))
+ {
+ return true;
+ }
+
+ // Action keyword specific filtering for folders
+ if (actionKeywordActive.Equals(ActionKeyword.FolderSearchActionKeyword)
+ && search.Type != ResultType.Folder)
+ {
+ return true;
+ }
+
+ // Action keyword specific filtering for files
+ if (actionKeywordActive.Equals(ActionKeyword.FileSearchActionKeyword)
+ && search.Type != ResultType.File)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private void MergeQuickAccessInResultsIfQueryMatch(HashSet results, Query query, ActionKeyword? activeActionKeyword)
+ {
+ if (activeActionKeyword != null
+ && activeActionKeyword != ActionKeyword.QuickAccessActionKeyword
+ && Settings.ExcludeQuickAccessFromActionKeywords)
+ {
+ return;
+ }
+
+ var quickAccessMatched = QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);
+ if (quickAccessMatched != null && quickAccessMatched.Count > 0) results.UnionWith(quickAccessMatched);
+ }
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
index 8d62531cd62..b4eda373797 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
@@ -1,12 +1,13 @@
-using Flow.Launcher.Plugin.Explorer.Search;
-using Flow.Launcher.Plugin.Explorer.Search.Everything;
-using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
-using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex;
-using System;
+using System;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text.Json.Serialization;
+using Flow.Launcher.Plugin.Explorer.Search;
+using Flow.Launcher.Plugin.Explorer.Search.Everything;
using Flow.Launcher.Plugin.Explorer.Search.IProvider;
+using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
+using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex;
namespace Flow.Launcher.Plugin.Explorer
{
@@ -58,6 +59,17 @@ public class Settings
public bool QuickAccessKeywordEnabled { get; set; }
+
+ public string FolderSearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;
+
+ public bool FolderSearchKeywordEnabled { get; set; }
+
+ public string FileSearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;
+
+ public bool FileSearchKeywordEnabled { get; set; }
+
+ public bool ExcludeQuickAccessFromActionKeywords { get; set; } = false;
+
public bool WarnWindowsSearchServiceOff { get; set; } = true;
public bool ShowFileSizeInPreviewPanel { get; set; } = true;
@@ -154,13 +166,15 @@ public enum ContentIndexSearchEngineOption
#endregion
- internal enum ActionKeyword
+ public enum ActionKeyword
{
SearchActionKeyword,
PathSearchActionKeyword,
FileContentSearchActionKeyword,
IndexSearchActionKeyword,
- QuickAccessActionKeyword
+ QuickAccessActionKeyword,
+ FolderSearchActionKeyword,
+ FileSearchActionKeyword,
}
internal string GetActionKeyword(ActionKeyword actionKeyword) => actionKeyword switch
@@ -170,6 +184,8 @@ internal enum ActionKeyword
ActionKeyword.FileContentSearchActionKeyword => FileContentSearchActionKeyword,
ActionKeyword.IndexSearchActionKeyword => IndexSearchActionKeyword,
ActionKeyword.QuickAccessActionKeyword => QuickAccessActionKeyword,
+ ActionKeyword.FolderSearchActionKeyword => FolderSearchActionKeyword,
+ ActionKeyword.FileSearchActionKeyword => FileSearchActionKeyword,
_ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyWord property not found")
};
@@ -180,6 +196,8 @@ internal enum ActionKeyword
ActionKeyword.FileContentSearchActionKeyword => FileContentSearchActionKeyword = keyword,
ActionKeyword.IndexSearchActionKeyword => IndexSearchActionKeyword = keyword,
ActionKeyword.QuickAccessActionKeyword => QuickAccessActionKeyword = keyword,
+ ActionKeyword.FolderSearchActionKeyword => FolderSearchActionKeyword = keyword,
+ ActionKeyword.FileSearchActionKeyword => FileSearchActionKeyword = keyword,
_ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyWord property not found")
};
@@ -190,6 +208,8 @@ internal enum ActionKeyword
ActionKeyword.IndexSearchActionKeyword => IndexSearchKeywordEnabled,
ActionKeyword.FileContentSearchActionKeyword => FileContentSearchKeywordEnabled,
ActionKeyword.QuickAccessActionKeyword => QuickAccessKeywordEnabled,
+ ActionKeyword.FolderSearchActionKeyword => FolderSearchKeywordEnabled,
+ ActionKeyword.FileSearchActionKeyword => FileSearchKeywordEnabled,
_ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyword enabled status not defined")
};
@@ -200,7 +220,22 @@ internal enum ActionKeyword
ActionKeyword.IndexSearchActionKeyword => IndexSearchKeywordEnabled = enable,
ActionKeyword.FileContentSearchActionKeyword => FileContentSearchKeywordEnabled = enable,
ActionKeyword.QuickAccessActionKeyword => QuickAccessKeywordEnabled = enable,
+ ActionKeyword.FolderSearchActionKeyword => FolderSearchKeywordEnabled = enable,
+ ActionKeyword.FileSearchActionKeyword => FileSearchKeywordEnabled = enable,
_ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyword enabled status not defined")
};
+
+ public ActionKeyword? GetActiveActionKeyword(string actionKeywordStr)
+ {
+ if (string.IsNullOrEmpty(actionKeywordStr)) return null;
+ foreach (var action in Enum.GetValues())
+ {
+ var keywordStr = GetActionKeyword(action);
+ if (string.IsNullOrEmpty(keywordStr)) continue;
+ var isEnabled = GetActionKeywordEnabled(action);
+ if (keywordStr == actionKeywordStr && isEnabled) return action;
+ }
+ return null;
+ }
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
index 2d46c6307cc..956c84db2c6 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
@@ -279,7 +279,11 @@ private void InitializeActionKeywordModels()
new(Settings.ActionKeyword.IndexSearchActionKeyword,
"plugin_explorer_actionkeywordview_indexsearch"),
new(Settings.ActionKeyword.QuickAccessActionKeyword,
- "plugin_explorer_actionkeywordview_quickaccess")
+ "plugin_explorer_actionkeywordview_quickaccess"),
+ new(Settings.ActionKeyword.FolderSearchActionKeyword,
+ "plugin_explorer_actionkeywordview_foldersearch"),
+ new(Settings.ActionKeyword.FileSearchActionKeyword,
+ "plugin_explorer_actionkeywordview_filesearch")
};
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml
index 79000e70055..40aaf2bf07d 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml
@@ -674,17 +674,27 @@
+
-
+
+
@@ -695,7 +705,7 @@