Skip to content

Support Querying Results When Query Text is Empty #3399

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 35 commits into from
May 5, 2025
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e0721aa
Add new interfaces
Jack251970 Mar 29, 2025
aa0f9b2
Update name
Jack251970 May 3, 2025
6a4fdcb
Merge branch 'dev' into empty_query
Jack251970 May 3, 2025
3089928
Support home query interface
Jack251970 May 3, 2025
0f09fea
Make async home query to be feature interface
Jack251970 May 3, 2025
17a0834
Support query for plugins with home query interface
Jack251970 May 3, 2025
54994dd
Initialize home query when window is loaded
Jack251970 May 3, 2025
e9ef26a
Change related setting names
Jack251970 May 3, 2025
e833333
Add ui in general page
Jack251970 May 3, 2025
d6704ed
Support history items
Jack251970 May 3, 2025
f2f4ebf
Support home state change & Add ui
Jack251970 May 3, 2025
96bb62a
Refresh interface when Home Page is changed
Jack251970 May 3, 2025
13cfbe5
Check query results
Jack251970 May 4, 2025
4500f1d
Fix history items context menu issue
Jack251970 May 4, 2025
19d7059
Add empty & global query for home page
Jack251970 May 4, 2025
4ed1dc3
Fix topmost issue in home page
Jack251970 May 4, 2025
35e4bfc
Improve code quality
Jack251970 May 4, 2025
ccb1bac
Merge branch 'dev' into empty_query
Jack251970 May 4, 2025
2ab007b
Fix typos
Jack251970 May 4, 2025
fe25764
Merge branch 'empty_query' of https://github.com/Jack251970/Flow.Laun…
Jack251970 May 4, 2025
eaea38c
Fix typos
Jack251970 May 4, 2025
78f606f
Fix typos
Jack251970 May 4, 2025
72bd1e6
Remove code comments with issues
Jack251970 May 4, 2025
0d9fb29
Improve code quality
Jack251970 May 4, 2025
67facb8
Use non-async version
Jack251970 May 4, 2025
21d6ec2
Use null to distinguish between home query and global query
Jack251970 May 4, 2025
28b8cb6
Improve distinguish between home query and global query
Jack251970 May 4, 2025
135b9b5
Merge branch 'dev' into empty_query
Jack251970 May 5, 2025
b9aa5a8
Change variable name for code quality
Jack251970 May 5, 2025
2713c5b
Add code comments
Jack251970 May 5, 2025
41211e8
Improve code comments
Jack251970 May 5, 2025
16404bc
Improve log information
Jack251970 May 5, 2025
36a4f41
Do not need to clear the result when last and current query are home …
Jack251970 May 5, 2025
0882378
Add Glyph for history items & topmost items
Jack251970 May 5, 2025
7083849
Remove unused codes
Jack251970 May 5, 2025
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
44 changes: 44 additions & 0 deletions Flow.Launcher.Core/Plugin/PluginManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public static class PluginManager
private static readonly string ClassName = nameof(PluginManager);

private static IEnumerable<PluginPair> _contextMenuPlugins;
private static IEnumerable<PluginPair> _homePlugins;

public static List<PluginPair> AllPlugins { get; private set; }
public static readonly HashSet<PluginPair> GlobalPlugins = new();
Expand Down Expand Up @@ -220,13 +221,16 @@ public static async Task InitializePluginsAsync()
{
API.LogException(ClassName, $"Fail to Init plugin: {pair.Metadata.Name}", e);
pair.Metadata.Disabled = true;
pair.Metadata.HomeDisabled = true;
failedPlugins.Enqueue(pair);
}
}));

await Task.WhenAll(InitTasks);

_contextMenuPlugins = GetPluginsForInterface<IContextMenu>();
_homePlugins = GetPluginsForInterface<IAsyncHomeQuery>();

foreach (var plugin in AllPlugins)
{
// set distinct on each plugin's action keywords helps only firing global(*) and action keywords once where a plugin
Expand Down Expand Up @@ -274,6 +278,11 @@ public static ICollection<PluginPair> ValidPluginsForQuery(Query query)
};
}

public static ICollection<PluginPair> ValidPluginsForHomeQuery()
{
return _homePlugins.ToList();
}

public static async Task<List<Result>> QueryForPluginAsync(PluginPair pair, Query query, CancellationToken token)
{
var results = new List<Result>();
Expand Down Expand Up @@ -318,6 +327,36 @@ public static async Task<List<Result>> QueryForPluginAsync(PluginPair pair, Quer
return results;
}

public static async Task<List<Result>> QueryHomeForPluginAsync(PluginPair pair, Query query, CancellationToken token)
{
var results = new List<Result>();
var metadata = pair.Metadata;

try
{
var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
async () => results = await ((IAsyncHomeQuery)pair.Plugin).HomeQueryAsync(token).ConfigureAwait(false));

token.ThrowIfCancellationRequested();
if (results == null)
return null;
UpdatePluginMetadata(results, metadata, query);

token.ThrowIfCancellationRequested();
}
catch (OperationCanceledException)
{
// null will be fine since the results will only be added into queue if the token hasn't been cancelled
return null;
}
catch (Exception e)
{
API.LogException(ClassName, $"Failed to query home for plugin: {metadata.Name}", e);
return null;
}
return results;
}

public static void UpdatePluginMetadata(IReadOnlyList<Result> results, PluginMetadata metadata, Query query)
{
foreach (var r in results)
Expand Down Expand Up @@ -378,6 +417,11 @@ public static List<Result> GetContextMenusForPlugin(Result result)
return results;
}

public static bool IsHomePlugin(string id)
{
return _homePlugins.Any(p => p.Metadata.ID == id);
}

public static bool ActionKeywordRegistered(string actionKeyword)
{
// this method is only checking for action keywords (defined as not '*') registration
Expand Down
21 changes: 18 additions & 3 deletions Flow.Launcher.Core/Plugin/QueryBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,23 @@ public static class QueryBuilder
{
public static Query Build(string text, Dictionary<string, PluginPair> nonGlobalPlugins)
{
// home query
if (string.IsNullOrEmpty(text))
{
return new Query()
{
Search = string.Empty,
RawQuery = string.Empty,
SearchTerms = Array.Empty<string>(),
ActionKeyword = string.Empty
};
}

// replace multiple white spaces with one white space
var terms = text.Split(Query.TermSeparator, StringSplitOptions.RemoveEmptyEntries);
if (terms.Length == 0)
{ // nothing was typed
{
// nothing was typed
return null;
}

Expand All @@ -21,13 +34,15 @@ public static Query Build(string text, Dictionary<string, PluginPair> nonGlobalP
string[] searchTerms;

if (nonGlobalPlugins.TryGetValue(possibleActionKeyword, out var pluginPair) && !pluginPair.Metadata.Disabled)
{ // use non global plugin for query
{
// use non global plugin for query
actionKeyword = possibleActionKeyword;
search = terms.Length > 1 ? rawQuery[(actionKeyword.Length + 1)..].TrimStart() : string.Empty;
searchTerms = terms[1..];
}
else
{ // non action keyword
{
// non action keyword
actionKeyword = string.Empty;
search = rawQuery.TrimStart();
searchTerms = terms;
Expand Down
3 changes: 3 additions & 0 deletions Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public void UpdatePluginSettings(List<PluginMetadata> metadatas)
metadata.Disabled = settings.Disabled;
metadata.Priority = settings.Priority;
metadata.SearchDelayTime = settings.SearchDelayTime;
metadata.HomeDisabled = settings.HomeDisabled;
}
else
{
Expand All @@ -79,6 +80,7 @@ public void UpdatePluginSettings(List<PluginMetadata> metadatas)
DefaultActionKeywords = metadata.ActionKeywords, // metadata provides default values
ActionKeywords = metadata.ActionKeywords, // use default value
Disabled = metadata.Disabled,
HomeDisabled = metadata.HomeDisabled,
Priority = metadata.Priority,
DefaultSearchDelayTime = metadata.SearchDelayTime, // metadata provides default values
SearchDelayTime = metadata.SearchDelayTime, // use default value
Expand Down Expand Up @@ -128,5 +130,6 @@ public class Plugin
/// Used only to save the state of the plugin in settings
/// </summary>
public bool Disabled { get; set; }
public bool HomeDisabled { get; set; }
}
}
18 changes: 18 additions & 0 deletions Flow.Launcher.Infrastructure/UserSettings/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,24 @@ public string PlaceholderText
}
}
}

private bool _showHomePage { get; set; } = true;
public bool ShowHomePage
{
get => _showHomePage;
set
{
if (_showHomePage != value)
{
_showHomePage = value;
OnPropertyChanged();
}
}
}

public bool ShowHistoryResultsForHomePage { get; set; } = false;
public int MaxHistoryResultsToShowForHomePage { get; set; } = 5;

public int CustomExplorerIndex { get; set; } = 0;

[JsonIgnore]
Expand Down
23 changes: 23 additions & 0 deletions Flow.Launcher.Plugin/Interfaces/IAsyncHomeQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Flow.Launcher.Plugin
{
/// <summary>
/// Asynchronous Query Model for Flow Launcher When Query Text is Empty
/// </summary>
public interface IAsyncHomeQuery : IFeatures
{
/// <summary>
/// Asynchronous Querying When Query Text is Empty
/// </summary>
/// <para>
/// If the Querying method requires high IO transmission
/// or performing CPU intense jobs (performing better with cancellation), please use this IAsyncHomeQuery interface
/// </para>
/// <param name="token">Cancel when querying job is obsolete</param>
/// <returns></returns>
Task<List<Result>> HomeQueryAsync(CancellationToken token);
}
}
28 changes: 28 additions & 0 deletions Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Flow.Launcher.Plugin
{
/// <summary>
/// Synchronous Query Model for Flow Launcher When Query Text is Empty
/// <para>
/// If the Querying method requires high IO transmission
/// or performing CPU intense jobs (performing better with cancellation), please try the IAsyncHomeQuery interface
/// </para>
/// </summary>
public interface IHomeQuery : IAsyncHomeQuery
{
/// <summary>
/// Querying When Query Text is Empty
/// <para>
/// This method will be called within a Task.Run,
/// so please avoid synchronously wait for long.
/// </para>
/// </summary>
/// <returns></returns>
List<Result> HomeQuery();

Task<List<Result>> IAsyncHomeQuery.HomeQueryAsync(CancellationToken token) => Task.Run(HomeQuery);
}
}
5 changes: 5 additions & 0 deletions Flow.Launcher.Plugin/PluginMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public class PluginMetadata : BaseModel
/// </summary>
public bool Disabled { get; set; }

/// <summary>
/// Whether plugin is disabled in home query.
/// </summary>
public bool HomeDisabled { get; set; }

/// <summary>
/// Plugin execute file path.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions Flow.Launcher/Languages/en.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@
<system:String x:Key="KoreanImeOpenLinkButton">Open</system:String>
<system:String x:Key="KoreanImeRegistry">Use Previous Korean IME</system:String>
<system:String x:Key="KoreanImeRegistryTooltip">You can change the Previous Korean IME settings directly from here</system:String>
<system:String x:Key="homePage">Home Page</system:String>
<system:String x:Key="homePageToolTip">Show home page results when query text is empty.</system:String>
<system:String x:Key="historyResultsForHomePage">Show History Results in Home Page</system:String>
<system:String x:Key="historyResultsCountForHomePage">Maximum History Results Shown in Home Page</system:String>
<system:String x:Key="homeToggleBoxToolTip">This can only be edited if plugin supports Home feature and Home Page is enabled.</system:String>

<!-- Setting Plugin -->
<system:String x:Key="searchplugin">Search Plugin</system:String>
Expand All @@ -148,6 +153,7 @@
<system:String x:Key="DisplayModeOnOff">Enabled</system:String>
<system:String x:Key="DisplayModePriority">Priority</system:String>
<system:String x:Key="DisplayModeSearchDelay">Search Delay</system:String>
<system:String x:Key="DisplayModeHomeOnOff">Home Page</system:String>
<system:String x:Key="currentPriority">Current Priority</system:String>
<system:String x:Key="newPriority">New Priority</system:String>
<system:String x:Key="priority">Priority</system:String>
Expand Down Expand Up @@ -401,6 +407,10 @@
<system:String x:Key="searchDelayTimeTitle">Search Delay Time Setting</system:String>
<system:String x:Key="searchDelayTimeTips">Input the search delay time in ms you like to use for the plugin. Input empty if you don't want to specify any, and the plugin will use default search delay time.</system:String>

<!-- Search Delay Settings Dialog -->
<system:String x:Key="homeTitle">Home Page</system:String>
<system:String x:Key="homeTips">Enable the plugin home page state if you like to show the plugin results when query is empty.</system:String>

<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Custom Query Hotkey</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
Expand Down
12 changes: 12 additions & 0 deletions Flow.Launcher/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,12 @@ private async void OnLoaded(object sender, RoutedEventArgs _)
case nameof(Settings.SettingWindowFont):
InitializeContextMenu();
break;
case nameof(Settings.ShowHomePage):
if (_viewModel.QueryResultsSelected() && string.IsNullOrEmpty(_viewModel.QueryText))
{
_viewModel.QueryResults();
}
break;
}
};

Expand All @@ -292,6 +298,12 @@ private async void OnLoaded(object sender, RoutedEventArgs _)
DependencyPropertyDescriptor
.FromProperty(VisibilityProperty, typeof(StackPanel))
.AddValueChanged(History, (s, e) => UpdateClockPanelVisibility());

// Initialize query state
if (_settings.ShowHomePage && string.IsNullOrEmpty(_viewModel.QueryText))
{
_viewModel.QueryResults();
}
}

private async void OnClosing(object sender, CancelEventArgs e)
Expand Down
11 changes: 10 additions & 1 deletion Flow.Launcher/Resources/Controls/InstalledPluginDisplay.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,19 @@
ToolTipService.InitialShowDelay="0"
ToolTipService.ShowOnDisabled="True"
Value="{Binding PluginSearchDelayTime, Mode=TwoWay}" />

</StackPanel>

<!-- Put OnOffControl after PriorityControl & SearchDelayControl so that it can display correctly -->
<ui:ToggleSwitch
x:Name="HomeOnOffControl"
Margin="0 0 8 0"
IsEnabled="{Binding HomeEnabled}"
IsOn="{Binding PluginHomeState}"
OffContent="{DynamicResource disable}"
OnContent="{DynamicResource enable}"
ToolTip="{DynamicResource homeToggleBoxToolTip}"
Visibility="{Binding DataContext.IsHomeOnOffSelected, RelativeSource={RelativeSource AncestorType=ListBox}, Converter={StaticResource BooleanToVisibilityConverter}}" />

<ui:ToggleSwitch
x:Name="OnOffControl"
Margin="0 0 8 0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,22 @@ public int SearchDelayTimeValue
{
Settings.SearchDelayTime = value;
OnPropertyChanged();
OnPropertyChanged(nameof(SearchDelayTimeDisplay));
}
}
}
public string SearchDelayTimeDisplay => $"{SearchDelayTimeValue}ms";

public int MaxHistoryResultsToShowValue
{
get => Settings.MaxHistoryResultsToShowForHomePage;
set
{
if (Settings.MaxHistoryResultsToShowForHomePage != value)
{
Settings.MaxHistoryResultsToShowForHomePage = value;
OnPropertyChanged();
}
}
}

private void UpdateEnumDropdownLocalizations()
{
Expand Down
Loading
Loading