Skip to content

Commit 6799b87

Browse files
authored
Merge pull request #3399 from Jack251970/empty_query
Support Querying Results When Query Text is Empty
2 parents e4ecea0 + 7083849 commit 6799b87

File tree

16 files changed

+433
-76
lines changed

16 files changed

+433
-76
lines changed

Flow.Launcher.Core/Plugin/PluginManager.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public static class PluginManager
2525
private static readonly string ClassName = nameof(PluginManager);
2626

2727
private static IEnumerable<PluginPair> _contextMenuPlugins;
28+
private static IEnumerable<PluginPair> _homePlugins;
2829

2930
public static List<PluginPair> AllPlugins { get; private set; }
3031
public static readonly HashSet<PluginPair> GlobalPlugins = new();
@@ -220,13 +221,16 @@ public static async Task InitializePluginsAsync()
220221
{
221222
API.LogException(ClassName, $"Fail to Init plugin: {pair.Metadata.Name}", e);
222223
pair.Metadata.Disabled = true;
224+
pair.Metadata.HomeDisabled = true;
223225
failedPlugins.Enqueue(pair);
224226
}
225227
}));
226228

227229
await Task.WhenAll(InitTasks);
228230

229231
_contextMenuPlugins = GetPluginsForInterface<IContextMenu>();
232+
_homePlugins = GetPluginsForInterface<IAsyncHomeQuery>();
233+
230234
foreach (var plugin in AllPlugins)
231235
{
232236
// set distinct on each plugin's action keywords helps only firing global(*) and action keywords once where a plugin
@@ -274,6 +278,11 @@ public static ICollection<PluginPair> ValidPluginsForQuery(Query query)
274278
};
275279
}
276280

281+
public static ICollection<PluginPair> ValidPluginsForHomeQuery()
282+
{
283+
return _homePlugins.ToList();
284+
}
285+
277286
public static async Task<List<Result>> QueryForPluginAsync(PluginPair pair, Query query, CancellationToken token)
278287
{
279288
var results = new List<Result>();
@@ -318,6 +327,36 @@ public static async Task<List<Result>> QueryForPluginAsync(PluginPair pair, Quer
318327
return results;
319328
}
320329

330+
public static async Task<List<Result>> QueryHomeForPluginAsync(PluginPair pair, Query query, CancellationToken token)
331+
{
332+
var results = new List<Result>();
333+
var metadata = pair.Metadata;
334+
335+
try
336+
{
337+
var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
338+
async () => results = await ((IAsyncHomeQuery)pair.Plugin).HomeQueryAsync(token).ConfigureAwait(false));
339+
340+
token.ThrowIfCancellationRequested();
341+
if (results == null)
342+
return null;
343+
UpdatePluginMetadata(results, metadata, query);
344+
345+
token.ThrowIfCancellationRequested();
346+
}
347+
catch (OperationCanceledException)
348+
{
349+
// null will be fine since the results will only be added into queue if the token hasn't been cancelled
350+
return null;
351+
}
352+
catch (Exception e)
353+
{
354+
API.LogException(ClassName, $"Failed to query home for plugin: {metadata.Name}", e);
355+
return null;
356+
}
357+
return results;
358+
}
359+
321360
public static void UpdatePluginMetadata(IReadOnlyList<Result> results, PluginMetadata metadata, Query query)
322361
{
323362
foreach (var r in results)
@@ -378,6 +417,11 @@ public static List<Result> GetContextMenusForPlugin(Result result)
378417
return results;
379418
}
380419

420+
public static bool IsHomePlugin(string id)
421+
{
422+
return _homePlugins.Any(p => p.Metadata.ID == id);
423+
}
424+
381425
public static bool ActionKeywordRegistered(string actionKeyword)
382426
{
383427
// this method is only checking for action keywords (defined as not '*') registration

Flow.Launcher.Core/Plugin/QueryBuilder.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,23 @@ public static class QueryBuilder
88
{
99
public static Query Build(string text, Dictionary<string, PluginPair> nonGlobalPlugins)
1010
{
11+
// home query
12+
if (string.IsNullOrEmpty(text))
13+
{
14+
return new Query()
15+
{
16+
Search = string.Empty,
17+
RawQuery = string.Empty,
18+
SearchTerms = Array.Empty<string>(),
19+
ActionKeyword = string.Empty
20+
};
21+
}
22+
1123
// replace multiple white spaces with one white space
1224
var terms = text.Split(Query.TermSeparator, StringSplitOptions.RemoveEmptyEntries);
1325
if (terms.Length == 0)
14-
{ // nothing was typed
26+
{
27+
// nothing was typed
1528
return null;
1629
}
1730

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

2336
if (nonGlobalPlugins.TryGetValue(possibleActionKeyword, out var pluginPair) && !pluginPair.Metadata.Disabled)
24-
{ // use non global plugin for query
37+
{
38+
// use non global plugin for query
2539
actionKeyword = possibleActionKeyword;
2640
search = terms.Length > 1 ? rawQuery[(actionKeyword.Length + 1)..].TrimStart() : string.Empty;
2741
searchTerms = terms[1..];
2842
}
2943
else
30-
{ // non action keyword
44+
{
45+
// non action keyword
3146
actionKeyword = string.Empty;
3247
search = rawQuery.TrimStart();
3348
searchTerms = terms;

Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public void UpdatePluginSettings(List<PluginMetadata> metadatas)
6767
metadata.Disabled = settings.Disabled;
6868
metadata.Priority = settings.Priority;
6969
metadata.SearchDelayTime = settings.SearchDelayTime;
70+
metadata.HomeDisabled = settings.HomeDisabled;
7071
}
7172
else
7273
{
@@ -79,6 +80,7 @@ public void UpdatePluginSettings(List<PluginMetadata> metadatas)
7980
DefaultActionKeywords = metadata.ActionKeywords, // metadata provides default values
8081
ActionKeywords = metadata.ActionKeywords, // use default value
8182
Disabled = metadata.Disabled,
83+
HomeDisabled = metadata.HomeDisabled,
8284
Priority = metadata.Priority,
8385
DefaultSearchDelayTime = metadata.SearchDelayTime, // metadata provides default values
8486
SearchDelayTime = metadata.SearchDelayTime, // use default value
@@ -128,5 +130,6 @@ public class Plugin
128130
/// Used only to save the state of the plugin in settings
129131
/// </summary>
130132
public bool Disabled { get; set; }
133+
public bool HomeDisabled { get; set; }
131134
}
132135
}

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,24 @@ public string PlaceholderText
158158
}
159159
}
160160
}
161+
162+
private bool _showHomePage { get; set; } = true;
163+
public bool ShowHomePage
164+
{
165+
get => _showHomePage;
166+
set
167+
{
168+
if (_showHomePage != value)
169+
{
170+
_showHomePage = value;
171+
OnPropertyChanged();
172+
}
173+
}
174+
}
175+
176+
public bool ShowHistoryResultsForHomePage { get; set; } = false;
177+
public int MaxHistoryResultsToShowForHomePage { get; set; } = 5;
178+
161179
public int CustomExplorerIndex { get; set; } = 0;
162180

163181
[JsonIgnore]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System.Collections.Generic;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace Flow.Launcher.Plugin
6+
{
7+
/// <summary>
8+
/// Asynchronous Query Model for Flow Launcher When Query Text is Empty
9+
/// </summary>
10+
public interface IAsyncHomeQuery : IFeatures
11+
{
12+
/// <summary>
13+
/// Asynchronous Querying When Query Text is Empty
14+
/// </summary>
15+
/// <para>
16+
/// If the Querying method requires high IO transmission
17+
/// or performing CPU intense jobs (performing better with cancellation), please use this IAsyncHomeQuery interface
18+
/// </para>
19+
/// <param name="token">Cancel when querying job is obsolete</param>
20+
/// <returns></returns>
21+
Task<List<Result>> HomeQueryAsync(CancellationToken token);
22+
}
23+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.Collections.Generic;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace Flow.Launcher.Plugin
6+
{
7+
/// <summary>
8+
/// Synchronous Query Model for Flow Launcher When Query Text is Empty
9+
/// <para>
10+
/// If the Querying method requires high IO transmission
11+
/// or performing CPU intense jobs (performing better with cancellation), please try the IAsyncHomeQuery interface
12+
/// </para>
13+
/// </summary>
14+
public interface IHomeQuery : IAsyncHomeQuery
15+
{
16+
/// <summary>
17+
/// Querying When Query Text is Empty
18+
/// <para>
19+
/// This method will be called within a Task.Run,
20+
/// so please avoid synchronously wait for long.
21+
/// </para>
22+
/// </summary>
23+
/// <returns></returns>
24+
List<Result> HomeQuery();
25+
26+
Task<List<Result>> IAsyncHomeQuery.HomeQueryAsync(CancellationToken token) => Task.Run(HomeQuery);
27+
}
28+
}

Flow.Launcher.Plugin/PluginMetadata.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ public class PluginMetadata : BaseModel
5050
/// </summary>
5151
public bool Disabled { get; set; }
5252

53+
/// <summary>
54+
/// Whether plugin is disabled in home query.
55+
/// </summary>
56+
public bool HomeDisabled { get; set; }
57+
5358
/// <summary>
5459
/// Plugin execute file path.
5560
/// </summary>

Flow.Launcher/Languages/en.xaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@
126126
<system:String x:Key="KoreanImeOpenLinkButton">Open</system:String>
127127
<system:String x:Key="KoreanImeRegistry">Use Previous Korean IME</system:String>
128128
<system:String x:Key="KoreanImeRegistryTooltip">You can change the Previous Korean IME settings directly from here</system:String>
129+
<system:String x:Key="homePage">Home Page</system:String>
130+
<system:String x:Key="homePageToolTip">Show home page results when query text is empty.</system:String>
131+
<system:String x:Key="historyResultsForHomePage">Show History Results in Home Page</system:String>
132+
<system:String x:Key="historyResultsCountForHomePage">Maximum History Results Shown in Home Page</system:String>
133+
<system:String x:Key="homeToggleBoxToolTip">This can only be edited if plugin supports Home feature and Home Page is enabled.</system:String>
129134

130135
<!-- Setting Plugin -->
131136
<system:String x:Key="searchplugin">Search Plugin</system:String>
@@ -148,6 +153,7 @@
148153
<system:String x:Key="DisplayModeOnOff">Enabled</system:String>
149154
<system:String x:Key="DisplayModePriority">Priority</system:String>
150155
<system:String x:Key="DisplayModeSearchDelay">Search Delay</system:String>
156+
<system:String x:Key="DisplayModeHomeOnOff">Home Page</system:String>
151157
<system:String x:Key="currentPriority">Current Priority</system:String>
152158
<system:String x:Key="newPriority">New Priority</system:String>
153159
<system:String x:Key="priority">Priority</system:String>
@@ -401,6 +407,10 @@
401407
<system:String x:Key="searchDelayTimeTitle">Search Delay Time Setting</system:String>
402408
<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>
403409

410+
<!-- Search Delay Settings Dialog -->
411+
<system:String x:Key="homeTitle">Home Page</system:String>
412+
<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>
413+
404414
<!-- Custom Query Hotkey Dialog -->
405415
<system:String x:Key="customeQueryHotkeyTitle">Custom Query Hotkey</system:String>
406416
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>

Flow.Launcher/MainWindow.xaml.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,12 @@ private async void OnLoaded(object sender, RoutedEventArgs _)
277277
case nameof(Settings.SettingWindowFont):
278278
InitializeContextMenu();
279279
break;
280+
case nameof(Settings.ShowHomePage):
281+
if (_viewModel.QueryResultsSelected() && string.IsNullOrEmpty(_viewModel.QueryText))
282+
{
283+
_viewModel.QueryResults();
284+
}
285+
break;
280286
}
281287
};
282288

@@ -292,6 +298,12 @@ private async void OnLoaded(object sender, RoutedEventArgs _)
292298
DependencyPropertyDescriptor
293299
.FromProperty(VisibilityProperty, typeof(StackPanel))
294300
.AddValueChanged(History, (s, e) => UpdateClockPanelVisibility());
301+
302+
// Initialize query state
303+
if (_settings.ShowHomePage && string.IsNullOrEmpty(_viewModel.QueryText))
304+
{
305+
_viewModel.QueryResults();
306+
}
295307
}
296308

297309
private async void OnClosing(object sender, CancelEventArgs e)

Flow.Launcher/Resources/Controls/InstalledPluginDisplay.xaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,19 @@
100100
ToolTipService.InitialShowDelay="0"
101101
ToolTipService.ShowOnDisabled="True"
102102
Value="{Binding PluginSearchDelayTime, Mode=TwoWay}" />
103-
104103
</StackPanel>
105104

106105
<!-- Put OnOffControl after PriorityControl & SearchDelayControl so that it can display correctly -->
106+
<ui:ToggleSwitch
107+
x:Name="HomeOnOffControl"
108+
Margin="0 0 8 0"
109+
IsEnabled="{Binding HomeEnabled}"
110+
IsOn="{Binding PluginHomeState}"
111+
OffContent="{DynamicResource disable}"
112+
OnContent="{DynamicResource enable}"
113+
ToolTip="{DynamicResource homeToggleBoxToolTip}"
114+
Visibility="{Binding DataContext.IsHomeOnOffSelected, RelativeSource={RelativeSource AncestorType=ListBox}, Converter={StaticResource BooleanToVisibilityConverter}}" />
115+
107116
<ui:ToggleSwitch
108117
x:Name="OnOffControl"
109118
Margin="0 0 8 0"

Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,22 @@ public int SearchDelayTimeValue
154154
{
155155
Settings.SearchDelayTime = value;
156156
OnPropertyChanged();
157-
OnPropertyChanged(nameof(SearchDelayTimeDisplay));
158157
}
159158
}
160159
}
161-
public string SearchDelayTimeDisplay => $"{SearchDelayTimeValue}ms";
160+
161+
public int MaxHistoryResultsToShowValue
162+
{
163+
get => Settings.MaxHistoryResultsToShowForHomePage;
164+
set
165+
{
166+
if (Settings.MaxHistoryResultsToShowForHomePage != value)
167+
{
168+
Settings.MaxHistoryResultsToShowForHomePage = value;
169+
OnPropertyChanged();
170+
}
171+
}
172+
}
162173

163174
private void UpdateEnumDropdownLocalizations()
164175
{

0 commit comments

Comments
 (0)