Skip to content

Commit fa0cd35

Browse files
committed
Support Path Enumeration (Part 1)
1 parent b671f56 commit fa0cd35

File tree

10 files changed

+129
-85
lines changed

10 files changed

+129
-85
lines changed

Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,20 @@ public static bool IsFastSortOption(SortOption sortOption)
101101
/// </summary>
102102
/// <param name="keyword">The key word.</param>
103103
/// <param name="token">when cancelled the current search will stop and exit (and would not reset)</param>
104+
/// <param name="parentPath">Search Within a parent folder</param>
105+
/// <param name="recursive">Search Within sub folder of the parent folder</param>
104106
/// <param name="sortOption">Sort By</param>
105107
/// <param name="offset">The offset.</param>
106108
/// <param name="maxCount">The max count.</param>
107109
/// <returns></returns>
108-
public static IEnumerable<SearchResult> SearchAsync(string keyword, CancellationToken token, SortOption sortOption = SortOption.NAME_ASCENDING, int offset = 0, int maxCount = 100)
110+
public static IEnumerable<SearchResult> SearchAsync(string keyword,
111+
CancellationToken token,
112+
SortOption sortOption = SortOption.NAME_ASCENDING,
113+
string parentPath = "",
114+
bool recursive = false,
115+
int offset = 0,
116+
int maxCount = 100)
109117
{
110-
if (string.IsNullOrEmpty(keyword))
111-
throw new ArgumentNullException(nameof(keyword));
112-
113118
if (offset < 0)
114119
throw new ArgumentOutOfRangeException(nameof(offset));
115120

@@ -124,6 +129,11 @@ public static IEnumerable<SearchResult> SearchAsync(string keyword, Cancellation
124129
keyword = keyword[1..];
125130
}
126131

132+
if (!string.IsNullOrEmpty(parentPath))
133+
{
134+
keyword += $" {(recursive ? "" : "parent:")}\"{parentPath}\"";
135+
}
136+
127137
EverythingApiDllImport.Everything_SetSearchW(keyword);
128138
EverythingApiDllImport.Everything_SetOffset(offset);
129139
EverythingApiDllImport.Everything_SetMax(maxCount);

Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace Flow.Launcher.Plugin.Explorer.Search.Everything
77
{
8-
public class EverythingSearchManager : IIndexProvider
8+
public class EverythingSearchManager : IIndexProvider, IContentIndexProvider, IPathEnumerable
99
{
1010
private Settings Settings { get; }
1111

@@ -15,13 +15,18 @@ public EverythingSearchManager(Settings settings)
1515
}
1616

1717

18-
public ValueTask<IEnumerable<SearchResult>> SearchAsync(Query query, CancellationToken token)
18+
public ValueTask<IEnumerable<SearchResult>> SearchAsync(string search, CancellationToken token)
1919
{
20-
return ValueTask.FromResult(EverythingApi.SearchAsync(query.Search, token, Settings.SortOption));
20+
return ValueTask.FromResult(EverythingApi.SearchAsync(search, token, Settings.SortOption));
2121
}
22-
public ValueTask<IEnumerable<SearchResult>> ContentSearchAsync(Query query, CancellationToken token)
22+
public ValueTask<IEnumerable<SearchResult>> ContentSearchAsync(string search, CancellationToken token)
2323
{
2424
return new ValueTask<IEnumerable<SearchResult>>(new List<SearchResult>());
2525
}
26+
public ValueTask<IEnumerable<SearchResult>> EnumerateAsync(string path, string search, bool recursive, CancellationToken token)
27+
{
28+
return new ValueTask<IEnumerable<SearchResult>>(
29+
EverythingApi.SearchAsync("", token, Settings.SortOption, path, recursive));
30+
}
2631
}
2732
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Collections.Generic;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace Flow.Launcher.Plugin.Explorer.Search
6+
{
7+
public interface IContentIndexProvider
8+
{
9+
public ValueTask<IEnumerable<SearchResult>> ContentSearchAsync(string search, CancellationToken token);
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Collections.Generic;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace Flow.Launcher.Plugin.Explorer.Search
6+
{
7+
public interface IIndexProvider
8+
{
9+
public ValueTask<IEnumerable<SearchResult>> SearchAsync(string search, CancellationToken token);
10+
}
11+
}
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
using System.Collections.Generic;
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
25

36
namespace Flow.Launcher.Plugin.Explorer.Search
47
{
58
public interface IPathEnumerable
69
{
7-
public IEnumerable<SearchResult> Enumerate(string path, bool recursive);
10+
public ValueTask<IEnumerable<SearchResult>> EnumerateAsync(string path, string search, bool recursive, CancellationToken token);
811
}
912
}

Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ internal async Task<List<Result>> SearchAsync(Query query, CancellationToken tok
6161

6262
if (IsFileContentSearch(query.ActionKeyword))
6363
{
64-
searchResults = await Settings.IndexProvider.ContentSearchAsync(query, token);
64+
searchResults = await Settings.ContentIndexProvider.ContentSearchAsync(query.Search, token);
6565
}
6666
else
6767
{
68-
searchResults = await Settings.IndexProvider.SearchAsync(query, token);
68+
searchResults = await Settings.IndexProvider.SearchAsync(query.Search, token);
6969
}
7070

7171
if (ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword) ||
@@ -120,12 +120,12 @@ public async Task<List<Result>> PathSearchAsync(Query query, CancellationToken t
120120
var isEnvironmentVariablePath = querySearch[1..].Contains("%\\");
121121

122122
var locationPath = querySearch;
123-
123+
124124
if (isEnvironmentVariablePath)
125125
locationPath = EnvironmentVariables.TranslateEnvironmentVariablePath(locationPath);
126126

127127
// Check that actual location exists, otherwise directory search will throw directory not found exception
128-
if (!FilesFolders.LocationExists(FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath)))
128+
if (!FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath).LocationExists())
129129
return results.ToList();
130130

131131
var useIndexSearch = UseWindowsIndexForDirectorySearch(locationPath);
@@ -134,16 +134,24 @@ public async Task<List<Result>> PathSearchAsync(Query query, CancellationToken t
134134

135135
token.ThrowIfCancellationRequested();
136136

137-
// var directoryResult = await TopLevelDirectorySearchBehaviourAsync(WindowsIndexTopLevelFolderSearchAsync,
138-
// DirectoryInfoClassSearch,
139-
// useIndexSearch,
140-
// query,
141-
// locationPath,
142-
// token).ConfigureAwait(false);
137+
IEnumerable<SearchResult> directoryResult;
138+
139+
if (query.Search.Contains('>'))
140+
{
141+
directoryResult =
142+
await Settings.PathEnumerator.EnumerateAsync(locationPath, "", false, token)
143+
.ConfigureAwait(false);
144+
}
145+
else
146+
{
147+
directoryResult = DirectoryInfoSearch.TopLevelDirectorySearch(query, query.Search, token);
148+
}
149+
150+
143151

144152
token.ThrowIfCancellationRequested();
145153

146-
// results.UnionWith(directoryResult);
154+
results.UnionWith(directoryResult.Select(searchResult => ResultManager.CreateResult(query, searchResult)));
147155

148156
return results.ToList();
149157
}
@@ -153,10 +161,6 @@ public bool IsFileContentSearch(string actionKeyword)
153161
return actionKeyword == Settings.FileContentSearchActionKeyword;
154162
}
155163

156-
private List<Result> DirectoryInfoClassSearch(Query query, string querySearch, CancellationToken token)
157-
{
158-
return DirectoryInfoSearch.TopLevelDirectorySearch(query, querySearch, token);
159-
}
160164

161165
public async Task<List<Result>> TopLevelDirectorySearchBehaviourAsync(
162166
Func<Query, string, CancellationToken, Task<List<Result>>> windowsIndexSearch,

Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IIndexProvider.cs

Lines changed: 0 additions & 13 deletions
This file was deleted.

Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndex.cs

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ internal static class WindowsIndex
1919
// Reserved keywords in oleDB
2020
private const string ReservedStringPattern = @"^[`\@\#\^,\&\/\\\$\%_;\[\]]+$";
2121

22-
private static async Task<List<SearchResult>> ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, Query query, CancellationToken token)
22+
private static async Task<List<SearchResult>> ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, CancellationToken token)
2323
{
2424
var results = new List<SearchResult>();
2525

@@ -82,7 +82,6 @@ internal static async ValueTask<List<SearchResult>> WindowsIndexSearchAsync(
8282
Func<CSearchQueryHelper> createQueryHelper,
8383
Func<string, string> constructQuery,
8484
List<AccessLink> exclusionList,
85-
Query query,
8685
CancellationToken token)
8786
{
8887
var regexMatch = Regex.Match(searchString, ReservedStringPattern);
@@ -93,40 +92,18 @@ internal static async ValueTask<List<SearchResult>> WindowsIndexSearchAsync(
9392
var constructedQuery = constructQuery(searchString);
9493

9594
return
96-
await ExecuteWindowsIndexSearchAsync(constructedQuery, createQueryHelper().ConnectionString, query, token);
95+
await ExecuteWindowsIndexSearchAsync(constructedQuery, createQueryHelper().ConnectionString, token);
9796
}
9897

99-
private static List<Result> RemoveResultsInExclusionList(List<Result> results, List<AccessLink> exclusionList, CancellationToken token)
98+
private static void RemoveResultsInExclusionList(List<SearchResult> results, IReadOnlyList<AccessLink> exclusionList, CancellationToken token)
10099
{
101100
var indexExclusionListCount = exclusionList.Count;
102101

103102
if (indexExclusionListCount == 0)
104-
return results;
105-
106-
var filteredResults = new List<Result>();
107-
108-
for (var index = 0; index < results.Count; index++)
109-
{
110-
token.ThrowIfCancellationRequested();
111-
112-
var excludeResult = false;
113-
114-
for (var i = 0; i < indexExclusionListCount; i++)
115-
{
116-
token.ThrowIfCancellationRequested();
117-
118-
if (results[index].SubTitle.StartsWith(exclusionList[i].Path, StringComparison.OrdinalIgnoreCase))
119-
{
120-
excludeResult = true;
121-
break;
122-
}
123-
}
124-
125-
if (!excludeResult)
126-
filteredResults.Add(results[index]);
127-
}
128-
129-
return filteredResults;
103+
return;
104+
results.RemoveAll(searchResult =>
105+
exclusionList.Any(exclude => searchResult.FullPath.StartsWith(exclude.Path, StringComparison.OrdinalIgnoreCase))
106+
);
130107
}
131108

132109
internal static bool PathIsIndexed(string path)

Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexManager.cs renamed to Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@
44

55
namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
66
{
7-
public class WindowsIndexManager : IIndexProvider
7+
public class WindowsIndexSearchManager : IIndexProvider, IContentIndexProvider, IPathEnumerable
88
{
99
private Settings Settings { get; }
1010
private QueryConstructor QueryConstructor { get; }
11-
public WindowsIndexManager(Settings settings)
11+
public WindowsIndexSearchManager(Settings settings)
1212
{
1313
Settings = settings;
1414
QueryConstructor = new QueryConstructor(Settings);
1515
}
1616

1717

18-
private async Task<List<SearchResult>> WindowsIndexFileContentSearchAsync(Query query, string querySearchString,
18+
private async Task<List<SearchResult>> WindowsIndexFileContentSearchAsync(string querySearchString,
1919
CancellationToken token)
2020
{
2121
if (string.IsNullOrEmpty(querySearchString))
@@ -26,26 +26,24 @@ private async Task<List<SearchResult>> WindowsIndexFileContentSearchAsync(Query
2626
QueryConstructor.CreateQueryHelper,
2727
QueryConstructor.QueryForFileContentSearch,
2828
Settings.IndexSearchExcludedSubdirectoryPaths,
29-
query,
3029
token).ConfigureAwait(false);
3130
}
3231

3332

3433

35-
private async Task<List<SearchResult>> WindowsIndexFilesAndFoldersSearchAsync(Query query, string querySearchString,
34+
private async Task<List<SearchResult>> WindowsIndexFilesAndFoldersSearchAsync(string querySearchString,
3635
CancellationToken token)
3736
{
3837
return await WindowsIndex.WindowsIndexSearchAsync(
3938
querySearchString,
4039
QueryConstructor.CreateQueryHelper,
4140
QueryConstructor.QueryForAllFilesAndFolders,
4241
Settings.IndexSearchExcludedSubdirectoryPaths,
43-
query,
4442
token).ConfigureAwait(false);
4543
}
4644

4745

48-
private async Task<List<SearchResult>> WindowsIndexTopLevelFolderSearchAsync(Query query, string path,
46+
private async Task<List<SearchResult>> WindowsIndexTopLevelFolderSearchAsync(string path,string search,
4947
CancellationToken token)
5048
{
5149
var queryConstructor = new QueryConstructor(Settings);
@@ -55,16 +53,21 @@ private async Task<List<SearchResult>> WindowsIndexTopLevelFolderSearchAsync(Que
5553
queryConstructor.CreateQueryHelper,
5654
queryConstructor.QueryForTopLevelDirectorySearch,
5755
Settings.IndexSearchExcludedSubdirectoryPaths,
58-
query,
5956
token).ConfigureAwait(false);
6057
}
61-
public ValueTask<IEnumerable<SearchResult>> SearchAsync(Query query, CancellationToken token)
58+
public async ValueTask<IEnumerable<SearchResult>> SearchAsync(string search, CancellationToken token)
6259
{
63-
return default;
60+
return await WindowsIndexFilesAndFoldersSearchAsync(search, token);
6461
}
65-
public ValueTask<IEnumerable<SearchResult>> ContentSearchAsync(Query query, CancellationToken token)
62+
public async ValueTask<IEnumerable<SearchResult>> ContentSearchAsync(string search, CancellationToken token)
6663
{
67-
return default;
64+
return await WindowsIndexFileContentSearchAsync(search, token);
65+
}
66+
public async ValueTask<IEnumerable<SearchResult>> EnumerateAsync(string path, string search, bool recursive, CancellationToken token)
67+
{
68+
if(recursive)
69+
return await WindowsIndexFilesAndFoldersSearchAsync(search, token).ConfigureAwait(false);
70+
return await WindowsIndexTopLevelFolderSearchAsync(path, search, token);
6871
}
6972
}
7073
}

0 commit comments

Comments
 (0)