Let index provider filter result type

This commit is contained in:
VictoriousRaptor 2025-12-28 13:26:19 +08:00
parent 8092a440f4
commit 6fa719dde3
4 changed files with 65 additions and 6 deletions

View file

@ -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;
@ -72,14 +73,16 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
}
}
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,
@ -89,6 +92,33 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
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)
{

View file

@ -3,8 +3,18 @@ using System.Threading;
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);
}
}

View file

@ -132,7 +132,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
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:
@ -150,7 +150,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search
{
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;
@ -329,6 +333,20 @@ namespace Flow.Launcher.Plugin.Explorer.Search
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[]

View file

@ -83,8 +83,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
}
}
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);
}