diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index a989327be..b23931fcf 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -10,6 +10,10 @@ Deletion successful Successfully deleted the {0} Assigning the global action keyword could bring up too many results during search. Please choose a specific action keyword + The required service for Windows Index Search does not appear to be running + To fix this, start the Windows Search service. Select here to remove this warning + The warning message has been switched off. As an alternative for searching files and folders, would you like to install Everything plugin?{0}{0}Select 'Yes' to install Everything plugin, or 'No' to return + Explorer Alternative Delete diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 2aa389f89..9995f45d3 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -12,14 +12,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search { public class SearchManager { - private readonly PluginInitContext context; + internal static PluginInitContext Context; - private readonly Settings settings; + internal static Settings Settings; public SearchManager(Settings settings, PluginInitContext context) { - this.context = context; - this.settings = settings; + Context = context; + Settings = settings; } private class PathEqualityComparator : IEqualityComparer @@ -71,14 +71,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search return allowedActionKeyword switch { - Settings.ActionKeyword.SearchActionKeyword => settings.SearchActionKeywordEnabled && - keyword == settings.SearchActionKeyword, - Settings.ActionKeyword.PathSearchActionKeyword => settings.PathSearchKeywordEnabled && - keyword == settings.PathSearchActionKeyword, + Settings.ActionKeyword.SearchActionKeyword => Settings.SearchActionKeywordEnabled && + keyword == Settings.SearchActionKeyword, + Settings.ActionKeyword.PathSearchActionKeyword => Settings.PathSearchKeywordEnabled && + keyword == Settings.PathSearchActionKeyword, Settings.ActionKeyword.FileContentSearchActionKeyword => keyword == - settings.FileContentSearchActionKeyword, - Settings.ActionKeyword.IndexSearchActionKeyword => settings.IndexOnlySearchKeywordEnabled && - keyword == settings.IndexSearchActionKeyword + Settings.FileContentSearchActionKeyword, + Settings.ActionKeyword.IndexSearchActionKeyword => Settings.IndexOnlySearchKeywordEnabled && + keyword == Settings.IndexSearchActionKeyword }; } @@ -88,18 +88,18 @@ namespace Flow.Launcher.Plugin.Explorer.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); + return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks); var results = new HashSet(PathEqualityComparator.Instance); - var quickaccessLinks = QuickAccess.AccessLinkListMatched(query, settings.QuickAccessLinks); + var quickaccessLinks = QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks); results.UnionWith(quickaccessLinks); var isEnvironmentVariable = EnvironmentVariables.IsEnvironmentVariableSearch(querySearch); if (isEnvironmentVariable) - return EnvironmentVariables.GetEnvironmentStringPathSuggestions(querySearch, query, context); + return EnvironmentVariables.GetEnvironmentStringPathSuggestions(querySearch, query, Context); // Query is a location path with a full environment variable, eg. %appdata%\somefolder\ var isEnvironmentVariablePath = querySearch[1..].Contains("%\\"); @@ -136,22 +136,23 @@ namespace Flow.Launcher.Plugin.Explorer.Search private async Task> WindowsIndexFileContentSearchAsync(Query query, string querySearchString, CancellationToken token) { - var queryConstructor = new QueryConstructor(settings); + var queryConstructor = new QueryConstructor(Settings); if (string.IsNullOrEmpty(querySearchString)) return new List(); - return await IndexSearch.WindowsIndexSearchAsync(querySearchString, - queryConstructor.CreateQueryHelper().ConnectionString, + return await IndexSearch.WindowsIndexSearchAsync( + querySearchString, + queryConstructor.CreateQueryHelper(), queryConstructor.QueryForFileContentSearch, - settings.IndexSearchExcludedSubdirectoryPaths, + Settings.IndexSearchExcludedSubdirectoryPaths, query, token).ConfigureAwait(false); } public bool IsFileContentSearch(string actionKeyword) { - return actionKeyword == settings.FileContentSearchActionKeyword; + return actionKeyword == Settings.FileContentSearchActionKeyword; } private List DirectoryInfoClassSearch(Query query, string querySearch, CancellationToken token) @@ -176,12 +177,13 @@ namespace Flow.Launcher.Plugin.Explorer.Search private async Task> WindowsIndexFilesAndFoldersSearchAsync(Query query, string querySearchString, CancellationToken token) { - var queryConstructor = new QueryConstructor(settings); + var queryConstructor = new QueryConstructor(Settings); - return await IndexSearch.WindowsIndexSearchAsync(querySearchString, - queryConstructor.CreateQueryHelper().ConnectionString, + return await IndexSearch.WindowsIndexSearchAsync( + querySearchString, + queryConstructor.CreateQueryHelper(), queryConstructor.QueryForAllFilesAndFolders, - settings.IndexSearchExcludedSubdirectoryPaths, + Settings.IndexSearchExcludedSubdirectoryPaths, query, token).ConfigureAwait(false); } @@ -189,12 +191,13 @@ namespace Flow.Launcher.Plugin.Explorer.Search private async Task> WindowsIndexTopLevelFolderSearchAsync(Query query, string path, CancellationToken token) { - var queryConstructor = new QueryConstructor(settings); + var queryConstructor = new QueryConstructor(Settings); - return await IndexSearch.WindowsIndexSearchAsync(path, - queryConstructor.CreateQueryHelper().ConnectionString, + return await IndexSearch.WindowsIndexSearchAsync( + path, + queryConstructor.CreateQueryHelper(), queryConstructor.QueryForTopLevelDirectorySearch, - settings.IndexSearchExcludedSubdirectoryPaths, + Settings.IndexSearchExcludedSubdirectoryPaths, query, token).ConfigureAwait(false); } @@ -203,10 +206,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search { var pathToDirectory = FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath); - if (!settings.UseWindowsIndexForDirectorySearch) + if (!Settings.UseWindowsIndexForDirectorySearch) return false; - if (settings.IndexSearchExcludedSubdirectoryPaths + if (Settings.IndexSearchExcludedSubdirectoryPaths .Any(x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(pathToDirectory) .StartsWith(x.Path, StringComparison.OrdinalIgnoreCase))) return false; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs index cfb564924..010a19b58 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs @@ -5,9 +5,11 @@ using System; using System.Collections.Generic; using System.Data.OleDb; using System.Linq; +using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using System.Windows; namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex { @@ -84,22 +86,36 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex return results; } - internal async static Task> WindowsIndexSearchAsync(string searchString, string connectionString, - Func constructQuery, - List exclusionList, - Query query, - CancellationToken token) + internal async static Task> WindowsIndexSearchAsync( + string searchString, + CSearchQueryHelper queryHelper, + Func constructQuery, + List exclusionList, + Query query, + CancellationToken token) { var regexMatch = Regex.Match(searchString, reservedStringPattern); if (regexMatch.Success) return new List(); + + try + { + var constructedQuery = constructQuery(searchString); - var constructedQuery = constructQuery(searchString); - return RemoveResultsInExclusionList( - await ExecuteWindowsIndexSearchAsync(constructedQuery, connectionString, query, token).ConfigureAwait(false), + return RemoveResultsInExclusionList( + await ExecuteWindowsIndexSearchAsync(constructedQuery, queryHelper.ConnectionString, query, token).ConfigureAwait(false), exclusionList, token); + } + catch (COMException) + { + // Occurs because the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin + if (!SearchManager.Settings.WarnWindowsSearchServiceOff) + return new List(); + + return ResultForWindexSearchOff(query.RawQuery); + } } private static List RemoveResultsInExclusionList(List results, List exclusionList, CancellationToken token) @@ -137,9 +153,66 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex internal static bool PathIsIndexed(string path) { - var csm = new CSearchManager(); - var indexManager = csm.GetCatalog("SystemIndex").GetCrawlScopeManager(); - return indexManager.IncludedInCrawlScope(path) > 0; + try + { + var csm = new CSearchManager(); + var indexManager = csm.GetCatalog("SystemIndex").GetCrawlScopeManager(); + return indexManager.IncludedInCrawlScope(path) > 0; + } + catch(COMException) + { + // Occurs because the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin + return false; + } + } + + private static List ResultForWindexSearchOff(string rawQuery) + { + var api = SearchManager.Context.API; + + return new List + { + new Result + { + Title = api.GetTranslation("plugin_explorer_windowsSearchServiceNotRunning"), + SubTitle = api.GetTranslation("plugin_explorer_windowsSearchServiceFix"), + Action = c => + { + SearchManager.Settings.WarnWindowsSearchServiceOff = false; + + var pluginsManagerPlugin= api.GetAllPlugins().FirstOrDefault(x => x.Metadata.ID == "9f8f9b14-2518-4907-b211-35ab6290dee7"); + + var actionKeywordCount = pluginsManagerPlugin.Metadata.ActionKeywords.Count; + + if (actionKeywordCount > 1) + LogException("PluginsManager's action keyword has increased to more than 1, this does not allow for determining the " + + "right action keyword. Explorer's code for managing Windows Search service not running exception needs to be updated", + new InvalidOperationException()); + + if (MessageBox.Show(string.Format(api.GetTranslation("plugin_explorer_alternative"), Environment.NewLine), + api.GetTranslation("plugin_explorer_alternative_title"), + MessageBoxButton.YesNo) == MessageBoxResult.Yes + && actionKeywordCount == 1) + { + api.ChangeQuery(string.Format("{0} install everything", pluginsManagerPlugin.Metadata.ActionKeywords[0])); + } + else + { + // Clears the warning message because same query string will not alter the displayed result list + api.ChangeQuery(string.Empty); + + api.ChangeQuery(rawQuery); + } + + var mainWindow = Application.Current.MainWindow; + mainWindow.Visibility = Visibility.Visible; + mainWindow.Focus(); + + return false; + }, + IcoPath = Constants.ExplorerIconImagePath + } + }; } private static void LogException(string message, Exception e) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 13f938dea..88656a401 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -1,4 +1,4 @@ -using Flow.Launcher.Plugin.Explorer.Search; +using Flow.Launcher.Plugin.Explorer.Search; using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption; using System; @@ -33,6 +33,8 @@ namespace Flow.Launcher.Plugin.Explorer public bool IndexOnlySearchKeywordEnabled { get; set; } + public bool WarnWindowsSearchServiceOff { get; set; } = true; + internal enum ActionKeyword { SearchActionKeyword, diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json index 5bd49949f..364674286 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json @@ -9,7 +9,7 @@ "Name": "Explorer", "Description": "Search and manage files and folders. Explorer utilises Windows Index Search", "Author": "Jeremy Wu", - "Version": "1.8.0", + "Version": "1.8.1", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll",