Skip to content

Fix clearing of results logic & minor adjustment to results update #3524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
64 changes: 38 additions & 26 deletions Flow.Launcher/ViewModel/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public partial class MainViewModel : BaseModel, ISavable, IDisposable

private bool _isQueryRunning;
private Query _lastQuery;
private bool _lastIsHomeQuery;
private bool _previousIsHomeQuery;
private string _queryTextBeforeLeaveResults;
private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results

Expand Down Expand Up @@ -1264,7 +1264,7 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b

App.API.LogDebug(ClassName, $"Start query with ActionKeyword <{query.ActionKeyword}> and RawQuery <{query.RawQuery}>");

var isHomeQuery = query.RawQuery == string.Empty;
var currentIsHomeQuery = query.RawQuery == string.Empty;

_updateSource?.Dispose();

Expand All @@ -1284,14 +1284,10 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b
// Update the query's IsReQuery property to true if this is a re-query
query.IsReQuery = isReQuery;

// handle the exclusiveness of plugin using action keyword
RemoveOldQueryResults(query, isHomeQuery);

_lastQuery = query;
_lastIsHomeQuery = isHomeQuery;


ICollection<PluginPair> plugins = Array.Empty<PluginPair>();
if (isHomeQuery)
if (currentIsHomeQuery)
{
if (Settings.ShowHomePage)
{
Expand Down Expand Up @@ -1347,7 +1343,7 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b
// plugins are ICollection, meaning LINQ will get the Count and preallocate Array

Task[] tasks;
if (isHomeQuery)
if (currentIsHomeQuery)
{
tasks = plugins.Select(plugin => plugin.Metadata.HomeDisabled switch
{
Expand Down Expand Up @@ -1397,7 +1393,7 @@ async Task QueryTaskAsync(PluginPair plugin, CancellationToken token)
{
App.API.LogDebug(ClassName, $"Wait for querying plugin <{plugin.Metadata.Name}>");

if (searchDelay && !isHomeQuery) // Do not delay for home query
if (searchDelay && !currentIsHomeQuery) // Do not delay for home query
{
var searchDelayTime = plugin.Metadata.SearchDelayTime ?? Settings.SearchDelayTime;

Expand All @@ -1410,7 +1406,7 @@ async Task QueryTaskAsync(PluginPair plugin, CancellationToken token)
// Task.Yield will force it to run in ThreadPool
await Task.Yield();

var results = isHomeQuery ?
var results = currentIsHomeQuery ?
await PluginManager.QueryHomeForPluginAsync(plugin, query, token) :
await PluginManager.QueryForPluginAsync(plugin, query, token);

Expand Down Expand Up @@ -1439,8 +1435,13 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) :

App.API.LogDebug(ClassName, $"Update results for plugin <{plugin.Metadata.Name}>");

// Indicate if to clear existing results so to show only ones from plugins with action keywords
var shouldClearExistingResults = ShouldClearExistingResults(query, currentIsHomeQuery);
_lastQuery = query;
_previousIsHomeQuery = currentIsHomeQuery;

if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, plugin.Metadata, query,
token, reSelect)))
token, reSelect, shouldClearExistingResults)))
{
App.API.LogError(ClassName, "Unable to add item to Result Update Queue");
}
Expand Down Expand Up @@ -1542,25 +1543,36 @@ private async Task BuildQueryAsync(IEnumerable<BaseBuiltinShortcutModel> builtIn
}
}

private void RemoveOldQueryResults(Query query, bool isHomeQuery)
/// <summary>
/// Determines whether the existing search results should be cleared based on the current query and the previous query type.
/// This is needed because of the design that treats plugins with action keywords and global action keywords separately. Results are gathered
/// either from plugins with matching action keywords or global action keyword, but not both. So when the current results are from plugins
/// with a matching action keyword and a new result set comes from a new query with the global action keyword, the existing results need to be cleared,
/// and vice versa. The same applies to home page query results.
///
/// There is no need to clear results from global action keyword if a new set of results comes along that is also from global action keywords.
/// This is because the removal of obsolete results is handled in ResultsViewModel.NewResults(ICollection<ResultsForUpdate>).
/// </summary>
/// <param name="query">The current query.</param>
/// <param name="currentIsHomeQuery">A flag indicating if the current query is a home query.</param>
/// <returns>True if the existing results should be cleared, false otherwise.</returns>
private bool ShouldClearExistingResults(Query query, bool currentIsHomeQuery)
{
// If last and current query are home query, we don't need to clear the results
if (_lastIsHomeQuery && isHomeQuery)
// If previous or current results are from home query, we need to clear them
if (_previousIsHomeQuery || currentIsHomeQuery)
{
return;
App.API.LogDebug(ClassName, $"Cleared old results");
return true;
}
// If last or current query is home query, we need to clear the results
else if (_lastIsHomeQuery || isHomeQuery)
{
App.API.LogDebug(ClassName, $"Remove old results");
Results.Clear();
}
// If last and current query are not home query, we need to check action keyword
else if (_lastQuery?.ActionKeyword != query?.ActionKeyword)

// If the last and current query are not home query type, we need to check the action keyword
if (_lastQuery?.ActionKeyword != query?.ActionKeyword)
{
App.API.LogDebug(ClassName, $"Remove old results");
Results.Clear();
App.API.LogDebug(ClassName, $"Cleared old results");
return true;
}

return false;
}

private Result ContextMenuTopMost(Result result)
Expand Down
3 changes: 2 additions & 1 deletion Flow.Launcher/ViewModel/ResultsForUpdate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ public record struct ResultsForUpdate(
PluginMetadata Metadata,
Query Query,
CancellationToken Token,
bool ReSelectFirstResult = true)
bool ReSelectFirstResult = true,
bool shouldClearExistingResults = false)
{
public string ID { get; } = Metadata.ID;
}
Expand Down
11 changes: 8 additions & 3 deletions Flow.Launcher/ViewModel/ResultsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,15 @@ private List<ResultViewModel> NewResults(ICollection<ResultsForUpdate> resultsFo
if (!resultsForUpdates.Any())
return Results;

var newResults = resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings));

if (resultsForUpdates.Any(x => x.shouldClearExistingResults))
return newResults.OrderByDescending(rv => rv.Result.Score).ToList();

return Results.Where(r => r?.Result != null && resultsForUpdates.All(u => u.ID != r.Result.PluginID))
.Concat(resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings)))
.OrderByDescending(rv => rv.Result.Score)
.ToList();
.Concat(newResults)
.OrderByDescending(rv => rv.Result.Score)
.ToList();
}
#endregion

Expand Down
Loading