diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs
index 3b25e8382..5286f85c7 100644
--- a/Flow.Launcher.Test/Plugins/ExplorerTest.cs
+++ b/Flow.Launcher.Test/Plugins/ExplorerTest.cs
@@ -73,7 +73,7 @@ namespace Flow.Launcher.Test.Plugins
var queryConstructor = new QueryConstructor(new Settings());
//When
- var queryString = queryConstructor.QueryForTopLevelDirectorySearch(folderPath);
+ var queryString = queryConstructor.Directory(folderPath);
// Then
Assert.IsTrue(queryString == expectedString,
@@ -93,7 +93,7 @@ namespace Flow.Launcher.Test.Plugins
var queryConstructor = new QueryConstructor(new Settings());
//When
- var queryString = queryConstructor.QueryForTopLevelDirectorySearch(userSearchString);
+ var queryString = queryConstructor.Directory(userSearchString);
// Then
Assert.IsTrue(queryString == expectedString,
@@ -125,7 +125,7 @@ namespace Flow.Launcher.Test.Plugins
public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryWhereRestrictionsShouldUseScopeString(string expectedString)
{
//When
- var resultString = QueryConstructor.QueryWhereRestrictionsForAllFilesAndFoldersSearch;
+ var resultString = QueryConstructor.RestrictionsForAllFilesAndFoldersSearch;
// Then
Assert.IsTrue(resultString == expectedString,
@@ -142,7 +142,7 @@ namespace Flow.Launcher.Test.Plugins
{
// Given
var queryConstructor = new QueryConstructor(new Settings());
- var baseQuery = queryConstructor.CreateBaseQuery();
+ var baseQuery = queryConstructor.BaseQueryHelper;
// system running this test could have different locale than the hard-coded 1033 LCID en-US.
var queryKeywordLocale = baseQuery.QueryKeywordLocale;
@@ -151,7 +151,7 @@ namespace Flow.Launcher.Test.Plugins
//When
- var resultString = queryConstructor.QueryForAllFilesAndFolders(userSearchString);
+ var resultString = queryConstructor.FilesAndFolders(userSearchString);
// Then
Assert.IsTrue(resultString == expectedString,
@@ -169,7 +169,7 @@ namespace Flow.Launcher.Test.Plugins
var queryConstructor = new QueryConstructor(new Settings());
//When
- var resultString = queryConstructor.QueryWhereRestrictionsForFileContentSearch(querySearchString);
+ var resultString = QueryConstructor.RestrictionsForFileContentSearch(querySearchString);
// Then
Assert.IsTrue(resultString == expectedString,
@@ -187,7 +187,7 @@ namespace Flow.Launcher.Test.Plugins
var queryConstructor = new QueryConstructor(new Settings());
//When
- var resultString = queryConstructor.QueryForFileContentSearch(userSearchString);
+ var resultString = queryConstructor.FileContent(userSearchString);
// Then
Assert.IsTrue(resultString == expectedString,
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
index f6d144404..2f2e7b9f6 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
@@ -51,4 +51,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs
index 9c9734967..e0f169207 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs
@@ -90,4 +90,4 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo
return results.OrderBy(r=>r.Type).ThenBy(r=>r.FullPath);
}
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs
index b1710a30a..553185c03 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs
@@ -193,4 +193,4 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs
index f22542ee2..a017d43c9 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs
@@ -3,10 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Flow.Launcher.Plugin.Explorer.Search.IProvider;
namespace Flow.Launcher.Plugin.Explorer.Search.Everything
{
- public class EverythingSearchManager : IIndexProvider, IContentIndexProvider, IPathEnumerable
+ public class EverythingSearchManager : IIndexProvider, IContentIndexProvider, IPathIndexProvider
{
private Settings Settings { get; }
@@ -48,4 +49,4 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
token);
}
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/IPathEnumerable.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IPathEnumerable.cs
deleted file mode 100644
index 57425c02b..000000000
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/IPathEnumerable.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Collections;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Flow.Launcher.Plugin.Explorer.Search
-{
- public interface IPathEnumerable
- {
- public IAsyncEnumerable EnumerateAsync(string path, string search, bool recursive, CancellationToken token);
- }
-}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/IContentIndexProvider.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IContentIndexProvider.cs
similarity index 77%
rename from Plugins/Flow.Launcher.Plugin.Explorer/Search/IContentIndexProvider.cs
rename to Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IContentIndexProvider.cs
index 7e2506f9a..7b8960b37 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/IContentIndexProvider.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IContentIndexProvider.cs
@@ -1,11 +1,10 @@
using System.Collections.Generic;
using System.Threading;
-using System.Threading.Tasks;
-namespace Flow.Launcher.Plugin.Explorer.Search
+namespace Flow.Launcher.Plugin.Explorer.Search.IProvider
{
public interface IContentIndexProvider
{
public IAsyncEnumerable ContentSearchAsync(string plainSearch, string contentSearch, CancellationToken token = default);
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/IIndexProvider.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IIndexProvider.cs
similarity index 73%
rename from Plugins/Flow.Launcher.Plugin.Explorer/Search/IIndexProvider.cs
rename to Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IIndexProvider.cs
index dfb07f9c4..9909b18d8 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/IIndexProvider.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IIndexProvider.cs
@@ -1,11 +1,10 @@
using System.Collections.Generic;
using System.Threading;
-using System.Threading.Tasks;
-namespace Flow.Launcher.Plugin.Explorer.Search
+namespace Flow.Launcher.Plugin.Explorer.Search.IProvider
{
public interface IIndexProvider
{
public IAsyncEnumerable SearchAsync(string search, CancellationToken token);
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IPathIndexProvider.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IPathIndexProvider.cs
new file mode 100644
index 000000000..56d735687
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IPathIndexProvider.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.IProvider
+{
+ public interface IPathIndexProvider
+ {
+ public IAsyncEnumerable EnumerateAsync(string path, string search, bool recursive, CancellationToken token);
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs
index 35ba0bafb..03cc4ae89 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs
@@ -210,4 +210,4 @@ namespace Flow.Launcher.Plugin.Explorer.Search
Folder,
File
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
index edea70025..c6432e599 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
@@ -55,30 +55,39 @@ namespace Flow.Launcher.Plugin.Explorer.Search
results.UnionWith(quickAccessLinks);
}
-
- IAsyncEnumerable searchResults;
-
- if (ActionKeywordMatch(query, Settings.ActionKeyword.FileContentSearchActionKeyword))
- {
- // A backdoor to prevent everything to do content search
- if (Settings.ContentIndexProvider is EverythingSearchManager && !Settings.EnableEverythingContentSearch)
- {
- return EverythingContentSearchResult(query);
- }
- searchResults = Settings.ContentIndexProvider.ContentSearchAsync("", query.Search, token);
- }
else
{
- searchResults = Settings.IndexProvider.SearchAsync(query.Search, token);
+ return new List();
}
+ IAsyncEnumerable searchResults = null;
- if (ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword) ||
- ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword))
+ bool isPathSearch = query.Search.IsLocationPathString();
+
+ switch (isPathSearch)
{
- results.UnionWith(await PathSearchAsync(query, token).ConfigureAwait(false));
+ case true
+ when (ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword)
+ || ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword)):
+ results.UnionWith(await PathSearchAsync(query, token).ConfigureAwait(false));
+ return results.ToList();
+ break;
+ case false when ActionKeywordMatch(query, Settings.ActionKeyword.FileContentSearchActionKeyword):
+ {
+ // A backdoor to prevent everything to do content search
+ if (Settings.ContentIndexProvider is EverythingSearchManager && !Settings.EnableEverythingContentSearch)
+ {
+ return EverythingContentSearchResult(query);
+ }
+ searchResults = Settings.ContentIndexProvider.ContentSearchAsync("", query.Search, token);
+ break;
+ }
+ case false:
+ searchResults = Settings.IndexProvider.SearchAsync(query.Search, token);
+ break;
}
+
if (searchResults == null)
{
return results.ToList();
@@ -154,7 +163,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
if (!FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath).LocationExists())
return results.ToList();
- var useIndexSearch = Settings.IndexSearchEngine is Settings.IndexSearchEngineOption.WindowsIndex
+ var useIndexSearch = Settings.IndexSearchEngine is Settings.IndexSearchEngineOption.WindowsIndex
&& UseWindowsIndexForDirectorySearch(locationPath);
results.Add(ResultManager.CreateOpenCurrentFolderResult(locationPath, useIndexSearch));
@@ -172,7 +181,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search
query.Search[..recursiveIndicatorIndex],
query.Search[(recursiveIndicatorIndex + 1)..],
true,
- token).ToListAsync(cancellationToken: token)
+ token)
+ .ToListAsync(cancellationToken: token)
.ConfigureAwait(false);
}
@@ -207,7 +217,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
}
public static bool IsFileContentSearch(string actionKeyword) => actionKeyword == Settings.FileContentSearchActionKeyword;
-
+
private bool UseWindowsIndexForDirectorySearch(string locationPath)
{
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchResult.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchResult.cs
index 815c6b7b0..eee88b957 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchResult.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchResult.cs
@@ -2,13 +2,14 @@
namespace Flow.Launcher.Plugin.Explorer.Search
{
- public struct SearchResult
+ public record struct SearchResult
{
public string FullPath { get; init; }
public ResultType Type { get; init; }
+ public int Score { get; init; }
public bool WindowsIndexed { get; init; }
public bool ShowIndexState { get; init; }
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/QueryConstructor.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/QueryConstructor.cs
index 96fb01d7e..3c04c624f 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/QueryConstructor.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/QueryConstructor.cs
@@ -4,21 +4,25 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
{
public class QueryConstructor
{
- private readonly Settings settings;
+ private Settings Settings { get; }
private const string SystemIndex = "SystemIndex";
+ public CSearchQueryHelper BaseQueryHelper { get; }
+
public QueryConstructor(Settings settings)
{
- this.settings = settings;
+ Settings = settings;
+ BaseQueryHelper = CreateBaseQuery();
}
- public CSearchQueryHelper CreateBaseQuery()
+
+ private CSearchQueryHelper CreateBaseQuery()
{
var baseQuery = CreateQueryHelper();
// Set the number of results we want. Don't set this property if all results are needed.
- baseQuery.QueryMaxResults = settings.MaxResult;
+ baseQuery.QueryMaxResults = Settings.MaxResult;
// Set list of columns we want to display, getting the path presently
baseQuery.QuerySelectColumns = "System.FileName, System.ItemUrl, System.ItemType";
@@ -32,7 +36,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
return baseQuery;
}
- internal CSearchQueryHelper CreateQueryHelper()
+ internal static CSearchQueryHelper CreateQueryHelper()
{
// This uses the Microsoft.Search.Interop assembly
var manager = new CSearchManager();
@@ -42,18 +46,19 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
// Get the ISearchQueryHelper which will help us to translate AQS --> SQL necessary to query the indexer
var queryHelper = catalogManager.GetQueryHelper();
-
+
return queryHelper;
}
+ private static string TopLevelDirectoryConstraint(string path) => $"directory='file:{path}'";
+ private static string RecursiveDirectoryConstraint(string path) => $"scope='file:{path}'";
+
///
/// Set the required WHERE clause restriction to search on the first level of a specified directory.
///
public string QueryWhereRestrictionsForTopLevelDirectorySearch(string path)
{
- var searchDepth = $"directory='file:";
-
- return QueryWhereRestrictionsFromLocationPath(path, searchDepth);
+ return QueryWhereRestrictionsFromLocationPath(path, "directory='file:");
}
///
@@ -61,9 +66,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
///
public string QueryWhereRestrictionsForTopLevelDirectoryAllFilesAndFoldersSearch(string path)
{
- var searchDepth = $"scope='file:";
-
- return QueryWhereRestrictionsFromLocationPath(path, searchDepth);
+ return QueryWhereRestrictionsFromLocationPath(path, "directory='scope:");
}
private string QueryWhereRestrictionsFromLocationPath(string path, string searchDepth)
@@ -73,70 +76,72 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
var indexOfSeparator = path.LastIndexOf(Constants.DirectorySeperator);
- var itemName = path.Substring(indexOfSeparator + 1);
+ var itemName = path[(indexOfSeparator + 1)..];
if (itemName.StartsWith(Constants.AllFilesFolderSearchWildcard))
- itemName = itemName.Substring(1);
+ itemName = itemName[1..];
var previousLevelDirectory = path.Substring(0, indexOfSeparator);
if (string.IsNullOrEmpty(itemName))
return $"{searchDepth}{previousLevelDirectory}'";
- return $"(System.FileName LIKE '{itemName}%' OR CONTAINS(System.FileName,'\"{itemName}*\"',1033)) AND {searchDepth}{previousLevelDirectory}'";
+ return $"(System.FileName LIKE '{itemName}%' OR CONTAINS({FileName},'\"{itemName}*\"',1033)) AND {searchDepth}{previousLevelDirectory}'";
}
///
/// Search will be performed on all folders and files on the first level of a specified directory.
///
- public string QueryForTopLevelDirectorySearch(string path)
+ public string Directory(string path, string searchString = "", bool recursive = false)
{
- string query = "SELECT TOP " + settings.MaxResult + $" {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE ";
+ var queryConstraint = searchString is "" ? "" : $"AND ({FileName} LIKE '{searchString}%' OR CONTAINS({FileName},'\"{searchString}*\"'))";
- if (path.LastIndexOf(Constants.AllFilesFolderSearchWildcard) > path.LastIndexOf(Constants.DirectorySeperator))
- return query + QueryWhereRestrictionsForTopLevelDirectoryAllFilesAndFoldersSearch(path) + QueryOrderByFileNameRestriction;
+ var scopeConstraint = recursive
+ ? RecursiveDirectoryConstraint(path)
+ : TopLevelDirectoryConstraint(path);
- return query + QueryWhereRestrictionsForTopLevelDirectorySearch(path) + QueryOrderByFileNameRestriction;
+ string query = $"SELECT TOP {Settings.MaxResult} {BaseQueryHelper.QuerySelectColumns} FROM {SystemIndex} WHERE {scopeConstraint} {queryConstraint} ORDER BY {FileName}";
+
+ return query;
}
///
/// Search will be performed on all folders and files based on user's search keywords.
///
- public string QueryForAllFilesAndFolders(string userSearchString)
+ public string FilesAndFolders(string userSearchString)
{
if (string.IsNullOrEmpty(userSearchString))
userSearchString = "*";
-
+
// Generate SQL from constructed parameters, converting the userSearchString from AQS->WHERE clause
- return CreateBaseQuery().GenerateSQLFromUserQuery(userSearchString) + " AND " + QueryWhereRestrictionsForAllFilesAndFoldersSearch
- + QueryOrderByFileNameRestriction;
+ return $"{BaseQueryHelper.GenerateSQLFromUserQuery(userSearchString)} AND {RestrictionsForAllFilesAndFoldersSearch} ORDER BY {FileName}";
}
///
/// Set the required WHERE clause restriction to search for all files and folders.
///
- public const string QueryWhereRestrictionsForAllFilesAndFoldersSearch = "scope='file:'";
+ public const string RestrictionsForAllFilesAndFoldersSearch = "scope='file:'";
- public const string QueryOrderByFileNameRestriction = " ORDER BY System.FileName";
+ ///
+ /// Order identifier: file name
+ ///
+ public const string FileName = "System.FileName";
///
/// Search will be performed on all indexed file contents for the specified search keywords.
///
- public string QueryForFileContentSearch(string userSearchString)
+ public string FileContent(string userSearchString)
{
- string query = "SELECT TOP " + settings.MaxResult + $" {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE ";
+ string query =
+ $"SELECT TOP {Settings.MaxResult} {BaseQueryHelper.QuerySelectColumns} FROM {SystemIndex} WHERE {RestrictionsForFileContentSearch(userSearchString)} AND {RestrictionsForAllFilesAndFoldersSearch} ORDER BY {FileName}";
- return query + QueryWhereRestrictionsForFileContentSearch(userSearchString) + " AND " + QueryWhereRestrictionsForAllFilesAndFoldersSearch
- + QueryOrderByFileNameRestriction;
+ return query;
}
///
/// Set the required WHERE clause restriction to search within file content.
///
- public string QueryWhereRestrictionsForFileContentSearch(string searchQuery)
- {
- return $"FREETEXT('{searchQuery}')";
- }
+ public static string RestrictionsForFileContentSearch(string searchQuery) => $"FREETEXT('{searchQuery}')";
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndex.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndex.cs
index 6a6d8cdb8..60e5ac741 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndex.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndex.cs
@@ -18,7 +18,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
{
// Reserved keywords in oleDB
- private const string ReservedStringPattern = @"^[`\@\#\^,\&\/\\\$\%_;\[\]]+$";
+ private static Regex _reservedPatternMatcher = new(@"^[`\@\#\^,\&\/\\\$\%_;\[\]]+$", RegexOptions.Compiled);
private static async IAsyncEnumerable ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, [EnumeratorCancellation] CancellationToken token)
{
@@ -28,31 +28,42 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
await using var command = new OleDbCommand(indexQueryString, conn);
// Results return as an OleDbDataReader.
- await using var dataReaderResults = await command.ExecuteReaderAsync(token) as OleDbDataReader;
+ OleDbDataReader dataReaderAttempt;
+ try
+ {
+ dataReaderAttempt = await command.ExecuteReaderAsync(token) as OleDbDataReader;
+ }
+ catch (OleDbException e)
+ {
+ Log.Exception($"|WindowsIndex.ExecuteWindowsIndexSearchAsync|Failed to execute windows index search query: {indexQueryString}", e);
+ yield break;
+ }
+ await using var dataReader = dataReaderAttempt;
token.ThrowIfCancellationRequested();
- if (dataReaderResults is not { HasRows: true })
+ if (dataReader is not { HasRows: true })
{
yield break;
}
- while (await dataReaderResults.ReadAsync(token))
+
+ while (await dataReader.ReadAsync(token))
{
token.ThrowIfCancellationRequested();
- if (dataReaderResults.GetValue(0) == DBNull.Value || dataReaderResults.GetValue(1) == DBNull.Value)
+ if (dataReader.GetValue(0) == DBNull.Value || dataReader.GetValue(1) == DBNull.Value)
{
continue;
}
// # is URI syntax for the fragment component, need to be encoded so LocalPath returns complete path
- var encodedFragmentPath = dataReaderResults
+ var encodedFragmentPath = dataReader
.GetString(1)
.Replace("#", "%23", StringComparison.OrdinalIgnoreCase);
var path = new Uri(encodedFragmentPath).LocalPath;
- yield return new SearchResult()
+ yield return new SearchResult
{
FullPath = path,
- Type = dataReaderResults.GetString(2) == "Directory" ? ResultType.Folder : ResultType.File,
+ Type = dataReader.GetString(2) == "Directory" ? ResultType.Folder : ResultType.File,
WindowsIndexed = true
};
}
@@ -60,22 +71,18 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
// Initial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection.
}
- internal static IAsyncEnumerable WindowsIndexSearchAsync(string searchString,
- Func createQueryHelper,
- Func constructQuery,
- IEnumerable exclusionList,
+
+
+ internal static IAsyncEnumerable WindowsIndexSearchAsync(string connectionString,
+ string search,
CancellationToken token)
{
- var regexMatch = Regex.Match(searchString, ReservedStringPattern);
-
- if (regexMatch.Success)
- return AsyncEnumerable.Empty();
-
- var constructedQuery = constructQuery(searchString);
-
- return ExecuteWindowsIndexSearchAsync(constructedQuery, createQueryHelper().ConnectionString, token);
+ return _reservedPatternMatcher.IsMatch(search)
+ ? AsyncEnumerable.Empty()
+ : ExecuteWindowsIndexSearchAsync(search, connectionString, token);
}
+ // TODO: Move to General Search Manager
private static void RemoveResultsInExclusionList(List results, IReadOnlyList exclusionList, CancellationToken token)
{
var indexExclusionListCount = exclusionList.Count;
@@ -102,6 +109,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
}
}
+ // TODO: Use a custom exception to handle this
private static List ResultForWindexSearchOff(string rawQuery)
{
var api = SearchManager.Context.API;
@@ -160,4 +168,4 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
#endif
}
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs
index 2b170afc4..6203df60e 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs
@@ -2,19 +2,24 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Flow.Launcher.Plugin.Explorer.Search.IProvider;
+using Microsoft.Search.Interop;
namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
{
- public class WindowsIndexSearchManager : IIndexProvider, IContentIndexProvider, IPathEnumerable
+ public class WindowsIndexSearchManager : IIndexProvider, IContentIndexProvider, IPathIndexProvider
{
private Settings Settings { get; }
private QueryConstructor QueryConstructor { get; }
+
+ private CSearchQueryHelper QueryHelper { get; }
public WindowsIndexSearchManager(Settings settings)
{
Settings = settings;
QueryConstructor = new QueryConstructor(Settings);
+ QueryHelper = QueryConstructor.CreateQueryHelper();
}
-
+
private IAsyncEnumerable WindowsIndexFileContentSearchAsync(string querySearchString,
CancellationToken token)
{
@@ -22,39 +27,35 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
return AsyncEnumerable.Empty();
return WindowsIndex.WindowsIndexSearchAsync(
- querySearchString,
- QueryConstructor.CreateQueryHelper,
- QueryConstructor.QueryForFileContentSearch,
- Settings.IndexSearchExcludedSubdirectoryPaths,
+ QueryHelper.ConnectionString,
+ QueryConstructor.FileContent(querySearchString),
token);
}
private IAsyncEnumerable WindowsIndexFilesAndFoldersSearchAsync(string querySearchString,
- CancellationToken token)
+ CancellationToken token = default)
{
return WindowsIndex.WindowsIndexSearchAsync(
- querySearchString,
- QueryConstructor.CreateQueryHelper,
- QueryConstructor.QueryForAllFilesAndFolders,
- Settings.IndexSearchExcludedSubdirectoryPaths,
+ QueryHelper.ConnectionString,
+ QueryConstructor.FilesAndFolders(querySearchString),
token);
}
- private IAsyncEnumerable WindowsIndexTopLevelFolderSearchAsync(string path,string search,
+ private IAsyncEnumerable WindowsIndexTopLevelFolderSearchAsync(string search,
+ string path,
+ bool recursive,
CancellationToken token)
{
var queryConstructor = new QueryConstructor(Settings);
return WindowsIndex.WindowsIndexSearchAsync(
- path,
- queryConstructor.CreateQueryHelper,
- queryConstructor.QueryForTopLevelDirectorySearch,
- Settings.IndexSearchExcludedSubdirectoryPaths,
+ QueryConstructor.CreateQueryHelper().ConnectionString,
+ queryConstructor.Directory(path, search, recursive),
token);
}
public IAsyncEnumerable SearchAsync(string search, CancellationToken token)
{
- return WindowsIndexFilesAndFoldersSearchAsync(search, token);
+ return WindowsIndexFilesAndFoldersSearchAsync(search, token: token);
}
public IAsyncEnumerable ContentSearchAsync(string plainSearch, string contentSearch, CancellationToken token)
{
@@ -62,7 +63,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
}
public IAsyncEnumerable EnumerateAsync(string path, string search, bool recursive, CancellationToken token)
{
- return recursive ? WindowsIndexFilesAndFoldersSearchAsync(search, token) : WindowsIndexTopLevelFolderSearchAsync(path, search, token);
+ return WindowsIndexTopLevelFolderSearchAsync(search, path, recursive, token);
}
}
-}
\ 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 0b2c8eea2..eb67af3a6 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
@@ -9,6 +9,7 @@ using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text.Json.Serialization;
+using Flow.Launcher.Plugin.Explorer.Search.IProvider;
namespace Flow.Launcher.Plugin.Explorer
{
@@ -65,7 +66,7 @@ namespace Flow.Launcher.Plugin.Explorer
#region SearchEngine
- public PathEnumerationEngineOption PathEnumerationEngine { get; set; }
+ public PathEnumerationEngineOption PathEnumerationEngine { get; set; } = PathEnumerationEngineOption.WindowsIndex;
private EverythingSearchManager EverythingManagerInstance => _everythingManagerInstance ??= new EverythingSearchManager(this);
private WindowsIndexSearchManager WindowsIndexSearchManager => _windowsIndexSearchManager ??= new WindowsIndexSearchManager(this);
@@ -81,7 +82,7 @@ namespace Flow.Launcher.Plugin.Explorer
};
[JsonIgnore]
- public IPathEnumerable PathEnumerator => PathEnumerationEngine switch
+ public IPathIndexProvider PathEnumerator => PathEnumerationEngine switch
{
PathEnumerationEngineOption.Everything => EverythingManagerInstance,
PathEnumerationEngineOption.WindowsIndex => WindowsIndexSearchManager,
@@ -192,4 +193,4 @@ namespace Flow.Launcher.Plugin.Explorer
_ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyword enabled status not defined")
};
}
-}
\ No newline at end of file
+}