Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -72,14 +73,16 @@ private async ValueTask<bool> ClickToInstallEverythingAsync(ActionContext _)
}
}

public async IAsyncEnumerable<SearchResult> SearchAsync(string search, [EnumeratorCancellation] CancellationToken token)
public async IAsyncEnumerable<SearchResult> SearchAsync(string search, [EnumeratorCancellation] CancellationToken token, IEnumerable<ResultType> allowedResultTypes = null)
{
await ThrowIfEverythingNotAvailableAsync(token);

if (token.IsCancellationRequested)
yield break;

var option = new EverythingSearchOption(search,
var searchKeyword = BuildSearchKeywordWithTypeFilter(search, allowedResultTypes);

var option = new EverythingSearchOption(searchKeyword,
Settings.SortOption,
MaxCount: Settings.MaxResult,
IsFullPathSearch: Settings.EverythingSearchFullPath,
Expand All @@ -89,6 +92,33 @@ public async IAsyncEnumerable<SearchResult> SearchAsync(string search, [Enumerat
yield return result;
}

private static string BuildSearchKeywordWithTypeFilter(string search, IEnumerable<ResultType> allowedResultTypes)
{
if (allowedResultTypes == null)
return search;

var typesList = allowedResultTypes as IList<ResultType> ?? allowedResultTypes.ToList();
if (typesList.Count == 0 || typesList.Count == 3)
return search; // No filtering needed

var hasFile = typesList.Contains(ResultType.File);
var hasFolder = typesList.Contains(ResultType.Folder);
var hasVolume = typesList.Contains(ResultType.Volume);

var filter = (hasFile, hasFolder, hasVolume) switch
{
(true, false, false) => "file:",
(false, true, false) => "folder:",
(false, false, true) => "volume:",
(true, true, false) => "<file:|folder:>",
(true, false, true) => "<file:|volume:>",
(false, true, true) => "<folder:|volume:>",
_ => null
};

return filter == null ? search : $"{filter} {search}";
}

public async IAsyncEnumerable<SearchResult> ContentSearchAsync(string plainSearch, string contentSearch,
[EnumeratorCancellation] CancellationToken token)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,18 @@

namespace Flow.Launcher.Plugin.Explorer.Search.IProvider
{
/// <summary>
/// Provides functionality for searching indexed items.
/// </summary>
public interface IIndexProvider
{
public IAsyncEnumerable<SearchResult> SearchAsync(string search, CancellationToken token);
/// <summary>
/// Asynchronously searches for items matching the specified search criteria.
/// </summary>
/// <param name="search">The search query string.</param>
/// <param name="token">The cancellation token to cancel the search operation.</param>
/// <param name="allowedResultTypes">Optional collection of result types to filter the search results. If null, all result types are included.</param>
/// <returns>An asynchronous enumerable of <see cref="SearchResult"/> objects matching the search criteria.</returns>
public IAsyncEnumerable<SearchResult> SearchAsync(string search, CancellationToken token, IEnumerable<ResultType> allowedResultTypes = null);
}
}
22 changes: 20 additions & 2 deletions Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@

case false
when CanUseIndexSearchByActionKeywords(activeActionKeywords):
searchResults = Settings.IndexProvider.SearchAsync(query.Search, token);
searchResults = Settings.IndexProvider.SearchAsync(query.Search, token, GetAllowedResultTypeByUsedActionKeyword(activeActionKeywords));
engineName = Enum.GetName(Settings.IndexSearchEngine);
break;
default:
Expand All @@ -150,7 +150,11 @@
{
if (search.Type == ResultType.File && IsExcludedFile(search))
continue;

// TODO: Optimize filtering by action keyword at the provider level to reduce unnecessary searches.
// 1. Path search and content search may not need filtering as they are specific enough.
// 2. Index search can be optimized by passing allowed result types to the provider to limit the search scope.
// 3. Quick access link filtering is already handled separately.
//
if (IsResultTypeFilteredByActionKeyword(search.Type, actions))
continue;

Expand Down Expand Up @@ -204,7 +208,7 @@
if (EnvironmentVariables.IsEnvironmentVariableSearch(querySearch))
return EnvironmentVariables.GetEnvironmentStringPathSuggestions(querySearch, query, Context);

// Query is a location path with a full environment variable, eg. %appdata%\somefolder\, c:\users\%USERNAME%\downloads

Check warning on line 211 in Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`somefolder` is not a recognized word. (unrecognized-spelling)
var needToExpand = EnvironmentVariables.HasEnvironmentVar(querySearch);
var path = needToExpand ? Environment.ExpandEnvironmentVariables(querySearch) : querySearch;

Expand Down Expand Up @@ -329,6 +333,20 @@
return true;
}

private List<ResultType> GetAllowedResultTypeByUsedActionKeyword(Dictionary<ActionKeyword, string> activeActionKeywords)
{
List<ActionKeyword> activeKeywords = activeActionKeywords.Keys.ToList();
var allowedResultTypes = new List<ResultType>();
foreach (var actionKeyword in activeKeywords)
{
if (_allowedTypesByActionKeyword.TryGetValue(actionKeyword, out var resultTypes))
{
allowedResultTypes.AddRange(resultTypes);
}
}
return allowedResultTypes.Distinct().ToList();
}

private bool CanUseIndexSearchByActionKeywords(Dictionary<ActionKeyword, string> actions)
{
var keysToUseIndexSearch = new[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
}
catch (COMException)
{
// Occurs when the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin

Check warning on line 40 in Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`WSearch` is not a recognized word. (unrecognized-spelling)
// Thrown by QueryConstructor.CreateQueryHelper()
return HandledEngineNotAvailableExceptionAsync();
}
Expand All @@ -56,7 +56,7 @@
}
catch (COMException)
{
// Occurs when the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin

Check warning on line 59 in Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`WSearch` is not a recognized word. (unrecognized-spelling)

Check warning on line 59 in Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`WSearch` is not a recognized word. (unrecognized-spelling)
// Thrown by QueryConstructor.CreateQueryHelper()
return HandledEngineNotAvailableExceptionAsync();
}
Expand All @@ -77,14 +77,15 @@
}
catch (COMException)
{
// Occurs when the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin

Check warning on line 80 in Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`WSearch` is not a recognized word. (unrecognized-spelling)

Check warning on line 80 in Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`WSearch` is not a recognized word. (unrecognized-spelling)
// Thrown by QueryConstructor.CreateQueryHelper()
return HandledEngineNotAvailableExceptionAsync();
}
}

public IAsyncEnumerable<SearchResult> SearchAsync(string search, CancellationToken token)
public IAsyncEnumerable<SearchResult> SearchAsync(string search, CancellationToken token, IEnumerable<ResultType> allowedResultTypes = null)
{
// TODO: result type filter
return WindowsIndexFilesAndFoldersSearchAsync(search, token: token);
}

Expand Down
Loading