Skip to content

Commit 48f67b1

Browse files
authored
Improve and fix query result update logic issue & provide access to exact query typed by user (#3502)
1 parent 38c0fae commit 48f67b1

File tree

13 files changed

+194
-159
lines changed

13 files changed

+194
-159
lines changed

Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,11 @@ private void SetupJsonRPC()
100100

101101
RPC = new JsonRpc(handler, new JsonRPCPublicAPI(Context.API));
102102

103-
RPC.AddLocalRpcMethod("UpdateResults", new Action<string, JsonRPCQueryResponseModel>((rawQuery, response) =>
103+
RPC.AddLocalRpcMethod("UpdateResults", new Action<string, JsonRPCQueryResponseModel>((trimmedQuery, response) =>
104104
{
105105
var results = ParseResults(response);
106106
ResultsUpdated?.Invoke(this,
107-
new ResultUpdatedEventArgs { Query = new Query() { RawQuery = rawQuery }, Results = results });
107+
new ResultUpdatedEventArgs { Query = new Query() { TrimmedQuery = trimmedQuery }, Results = results });
108108
}));
109109
RPC.SynchronizationContext = null;
110110
RPC.StartListening();

Flow.Launcher.Core/Plugin/PluginManager.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ public static async Task<List<Result>> QueryForPluginAsync(PluginPair pair, Quer
401401
{
402402
Title = Localize.pluginStillInitializing(metadata.Name),
403403
SubTitle = Localize.pluginStillInitializingSubtitle(),
404-
AutoCompleteText = query.RawQuery,
404+
AutoCompleteText = query.TrimmedQuery,
405405
IcoPath = metadata.IcoPath,
406406
PluginDirectory = metadata.PluginDirectory,
407407
ActionKeywordAssigned = query.ActionKeyword,
@@ -443,7 +443,7 @@ public static async Task<List<Result>> QueryForPluginAsync(PluginPair pair, Quer
443443
{
444444
Title = Localize.pluginFailedToRespond(metadata.Name),
445445
SubTitle = Localize.pluginFailedToRespondSubtitle(),
446-
AutoCompleteText = query.RawQuery,
446+
AutoCompleteText = query.TrimmedQuery,
447447
IcoPath = Constant.ErrorIcon,
448448
PluginDirectory = metadata.PluginDirectory,
449449
ActionKeywordAssigned = query.ActionKeyword,
@@ -467,7 +467,7 @@ public static async Task<List<Result>> QueryHomeForPluginAsync(PluginPair pair,
467467
{
468468
Title = Localize.pluginStillInitializing(metadata.Name),
469469
SubTitle = Localize.pluginStillInitializingSubtitle(),
470-
AutoCompleteText = query.RawQuery,
470+
AutoCompleteText = query.TrimmedQuery,
471471
IcoPath = metadata.IcoPath,
472472
PluginDirectory = metadata.PluginDirectory,
473473
ActionKeywordAssigned = query.ActionKeyword,

Flow.Launcher.Core/Plugin/QueryBuilder.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,30 @@ namespace Flow.Launcher.Core.Plugin
66
{
77
public static class QueryBuilder
88
{
9-
public static Query Build(string text, Dictionary<string, PluginPair> nonGlobalPlugins)
9+
public static Query Build(string originalQuery, string trimmedQuery, Dictionary<string, PluginPair> nonGlobalPlugins)
1010
{
1111
// home query
12-
if (string.IsNullOrEmpty(text))
12+
if (string.IsNullOrEmpty(trimmedQuery))
1313
{
1414
return new Query()
1515
{
1616
Search = string.Empty,
17-
RawQuery = string.Empty,
17+
OriginalQuery = string.Empty,
18+
TrimmedQuery = string.Empty,
1819
SearchTerms = Array.Empty<string>(),
1920
ActionKeyword = string.Empty,
2021
IsHomeQuery = true
2122
};
2223
}
2324

2425
// replace multiple white spaces with one white space
25-
var terms = text.Split(Query.TermSeparator, StringSplitOptions.RemoveEmptyEntries);
26+
var terms = trimmedQuery.Split(Query.TermSeparator, StringSplitOptions.RemoveEmptyEntries);
2627
if (terms.Length == 0)
2728
{
2829
// nothing was typed
2930
return null;
3031
}
3132

32-
var rawQuery = text;
3333
string actionKeyword, search;
3434
string possibleActionKeyword = terms[0];
3535
string[] searchTerms;
@@ -38,21 +38,22 @@ public static Query Build(string text, Dictionary<string, PluginPair> nonGlobalP
3838
{
3939
// use non global plugin for query
4040
actionKeyword = possibleActionKeyword;
41-
search = terms.Length > 1 ? rawQuery[(actionKeyword.Length + 1)..].TrimStart() : string.Empty;
41+
search = terms.Length > 1 ? trimmedQuery[(actionKeyword.Length + 1)..].TrimStart() : string.Empty;
4242
searchTerms = terms[1..];
4343
}
4444
else
4545
{
4646
// non action keyword
4747
actionKeyword = string.Empty;
48-
search = rawQuery.TrimStart();
48+
search = trimmedQuery.TrimStart();
4949
searchTerms = terms;
5050
}
5151

5252
return new Query()
5353
{
5454
Search = search,
55-
RawQuery = rawQuery,
55+
OriginalQuery = originalQuery,
56+
TrimmedQuery = trimmedQuery,
5657
SearchTerms = searchTerms,
5758
ActionKeyword = actionKeyword,
5859
IsHomeQuery = false

Flow.Launcher.Plugin/Query.cs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Text.Json.Serialization;
1+
using System;
2+
using System.Text.Json.Serialization;
23

34
namespace Flow.Launcher.Plugin
45
{
@@ -7,12 +8,30 @@ namespace Flow.Launcher.Plugin
78
/// </summary>
89
public class Query
910
{
11+
/// <summary>
12+
/// Original query, exactly how the user has typed into the search box.
13+
/// We don't recommend using this property directly. You should always use Search property.
14+
/// </summary>
15+
public string OriginalQuery { get; internal init; }
16+
1017
/// <summary>
1118
/// Raw query, this includes action keyword if it has.
12-
/// It has handled buildin custom query shortkeys and build-in shortcuts, and it trims the whitespace.
13-
/// We didn't recommend use this property directly. You should always use Search property.
19+
/// It has handled built-in custom query hotkeys and built-in shortcuts, and it trims the whitespace.
20+
/// We don't recommend using this property directly. You should always use Search property.
21+
/// </summary>
22+
[Obsolete("RawQuery is renamed to TrimmedQuery. This property will be removed. Update the code to use TrimmedQuery instead.")]
23+
public string RawQuery {
24+
get => TrimmedQuery;
25+
internal init { TrimmedQuery = value; }
26+
}
27+
28+
/// <summary>
29+
/// Original query but with trimmed whitespace. Includes action keyword.
30+
/// It has handled built-in custom query hotkeys and build-in shortcuts.
31+
/// If you need the exact original query from the search box, use OriginalQuery property instead.
32+
/// We don't recommend using this property directly. You should always use Search property.
1433
/// </summary>
15-
public string RawQuery { get; internal init; }
34+
public string TrimmedQuery { get; internal init; }
1635

1736
/// <summary>
1837
/// Determines whether the query was forced to execute again.
@@ -28,7 +47,7 @@ public class Query
2847

2948
/// <summary>
3049
/// Search part of a query.
31-
/// This will not include action keyword if exclusive plugin gets it, otherwise it should be same as RawQuery.
50+
/// This will not include action keyword if exclusive plugin gets it, otherwise it should be same as TrimmedQuery.
3251
/// Since we allow user to switch a exclusive plugin to generic plugin,
3352
/// so this property will always give you the "real" query part of the query
3453
/// </summary>
@@ -103,6 +122,6 @@ private string SplitSearch(int index)
103122
}
104123

105124
/// <inheritdoc />
106-
public override string ToString() => RawQuery;
125+
public override string ToString() => TrimmedQuery;
107126
}
108127
}

Flow.Launcher.Test/QueryBuilderTest.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ public void ExclusivePluginQueryTest()
1616
{">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List<string> {">"}}}}
1717
};
1818

19-
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", nonGlobalPlugins);
19+
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", "> ping google.com -n 20 -6", nonGlobalPlugins);
2020

21-
ClassicAssert.AreEqual("> ping google.com -n 20 -6", q.RawQuery);
21+
ClassicAssert.AreEqual("> ping google.com -n 20 -6", q.TrimmedQuery);
2222
ClassicAssert.AreEqual("ping google.com -n 20 -6", q.Search, "Search should not start with the ActionKeyword.");
2323
ClassicAssert.AreEqual(">", q.ActionKeyword);
2424

@@ -39,10 +39,10 @@ public void ExclusivePluginQueryIgnoreDisabledTest()
3939
{">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List<string> {">"}, Disabled = true}}}
4040
};
4141

42-
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", nonGlobalPlugins);
42+
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", "> ping google.com -n 20 -6", nonGlobalPlugins);
4343

4444
ClassicAssert.AreEqual("> ping google.com -n 20 -6", q.Search);
45-
ClassicAssert.AreEqual(q.Search, q.RawQuery, "RawQuery should be equal to Search.");
45+
ClassicAssert.AreEqual(q.Search, q.TrimmedQuery, "TrimmedQuery should be equal to Search.");
4646
ClassicAssert.AreEqual(6, q.SearchTerms.Length, "The length of SearchTerms should match.");
4747
ClassicAssert.AreNotEqual(">", q.ActionKeyword, "ActionKeyword should not match that of a disabled plugin.");
4848
ClassicAssert.AreEqual("ping google.com -n 20 -6", q.SecondToEndSearch, "SecondToEndSearch should be trimmed of multiple whitespace characters");
@@ -51,7 +51,7 @@ public void ExclusivePluginQueryIgnoreDisabledTest()
5151
[Test]
5252
public void GenericPluginQueryTest()
5353
{
54-
Query q = QueryBuilder.Build("file.txt file2 file3", new Dictionary<string, PluginPair>());
54+
Query q = QueryBuilder.Build("file.txt file2 file3", "file.txt file2 file3", new Dictionary<string, PluginPair>());
5555

5656
ClassicAssert.AreEqual("file.txt file2 file3", q.Search);
5757
ClassicAssert.AreEqual("", q.ActionKeyword);

Flow.Launcher/Helper/ResultHelper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ public static class ResultHelper
1616
return await PopulateResultsAsync(item.PluginID, item.Query, item.Title, item.SubTitle, item.RecordKey);
1717
}
1818

19-
public static async Task<Result?> PopulateResultsAsync(string pluginId, string rawQuery, string title, string subTitle, string recordKey)
19+
public static async Task<Result?> PopulateResultsAsync(string pluginId, string trimmedQuery, string title, string subTitle, string recordKey)
2020
{
2121
var plugin = PluginManager.GetPluginForId(pluginId);
2222
if (plugin == null) return null;
23-
var query = QueryBuilder.Build(rawQuery, PluginManager.GetNonGlobalPlugins());
23+
var query = QueryBuilder.Build(trimmedQuery, trimmedQuery, PluginManager.GetNonGlobalPlugins());
2424
if (query == null) return null;
2525
try
2626
{

Flow.Launcher/MainWindow.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ private void OnKeyDown(object sender, KeyEventArgs e)
477477
&& QueryTextBox.CaretIndex == QueryTextBox.Text.Length)
478478
{
479479
var queryWithoutActionKeyword =
480-
QueryBuilder.Build(QueryTextBox.Text.Trim(), PluginManager.GetNonGlobalPlugins())?.Search;
480+
QueryBuilder.Build(QueryTextBox.Text, QueryTextBox.Text.Trim(), PluginManager.GetNonGlobalPlugins())?.Search;
481481

482482
if (FilesFolders.IsLocationPathString(queryWithoutActionKeyword))
483483
{

Flow.Launcher/ResultListBox.xaml.cs

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.IO;
3+
using System.Threading;
34
using System.Windows;
45
using System.Windows.Controls;
56
using System.Windows.Input;
@@ -9,7 +10,7 @@ namespace Flow.Launcher
910
{
1011
public partial class ResultListBox
1112
{
12-
protected object _lock = new object();
13+
protected Lock _lock = new();
1314
private Point _lastpos;
1415
private ListBoxItem curItem = null;
1516
public ResultListBox()
@@ -88,12 +89,11 @@ private void ListBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
8889
}
8990
}
9091

91-
92-
private Point start;
93-
private string path;
94-
private string query;
92+
private Point _start;
93+
private string _path;
94+
private string _trimmedQuery;
9595
// this method is called by the UI thread, which is single threaded, so we can be sloppy with locking
96-
private bool isDragging;
96+
private bool _isDragging;
9797

9898
private void ResultList_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
9999
{
@@ -104,60 +104,63 @@ private void ResultList_PreviewMouseLeftButtonDown(object sender, MouseButtonEve
104104
Result:
105105
{
106106
CopyText: { } copyText,
107-
OriginQuery.RawQuery: { } rawQuery
107+
OriginQuery.TrimmedQuery: { } trimmedQuery
108108
}
109109
}
110110
}) return;
111111

112-
path = copyText;
113-
query = rawQuery;
114-
start = e.GetPosition(null);
115-
isDragging = true;
112+
_path = copyText;
113+
_trimmedQuery = trimmedQuery;
114+
_start = e.GetPosition(null);
115+
_isDragging = true;
116116
}
117+
117118
private void ResultList_MouseMove(object sender, MouseEventArgs e)
118119
{
119-
if (e.LeftButton != MouseButtonState.Pressed || !isDragging)
120+
if (e.LeftButton != MouseButtonState.Pressed || !_isDragging)
120121
{
121-
start = default;
122-
path = string.Empty;
123-
query = string.Empty;
124-
isDragging = false;
122+
_start = default;
123+
_path = string.Empty;
124+
_trimmedQuery = string.Empty;
125+
_isDragging = false;
125126
return;
126127
}
127128

128-
if (!File.Exists(path) && !Directory.Exists(path))
129+
if (!File.Exists(_path) && !Directory.Exists(_path))
129130
return;
130131

131132
Point mousePosition = e.GetPosition(null);
132-
Vector diff = this.start - mousePosition;
133+
Vector diff = _start - mousePosition;
133134

134135
if (Math.Abs(diff.X) < SystemParameters.MinimumHorizontalDragDistance
135136
|| Math.Abs(diff.Y) < SystemParameters.MinimumVerticalDragDistance)
136137
return;
137138

138-
isDragging = false;
139+
_isDragging = false;
139140

140141
App.API.HideMainWindow();
141142

142143
var data = new DataObject(DataFormats.FileDrop, new[]
143144
{
144-
path
145+
_path
145146
});
146147

147148
// Reassigning query to a new variable because for some reason
148149
// after DragDrop.DoDragDrop call, 'query' loses its content, i.e. becomes empty string
149-
var rawQuery = query;
150+
var trimmedQuery = _trimmedQuery;
150151
var effect = DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Move | DragDropEffects.Copy);
151152
if (effect == DragDropEffects.Move)
152-
App.API.ChangeQuery(rawQuery, true);
153+
App.API.ChangeQuery(trimmedQuery, true);
153154
}
155+
154156
private void ResultListBox_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
155157
{
156158
if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })
157159
return;
158160

159161
RightClickResultCommand?.Execute(result.Result);
160162
}
163+
161164
private void ResultListBox_OnPreviewMouseUp(object sender, MouseButtonEventArgs e)
162165
{
163166
if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })

Flow.Launcher/Storage/LastOpenedHistoryItem.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ public bool Equals(Result r)
1919
return Title == r.Title
2020
&& SubTitle == r.SubTitle
2121
&& PluginID == r.PluginID
22-
&& Query == r.OriginQuery.RawQuery;
22+
&& Query == r.OriginQuery.TrimmedQuery;
2323
}
2424
else
2525
{
2626
return RecordKey == r.RecordKey
2727
&& PluginID == r.PluginID
28-
&& Query == r.OriginQuery.RawQuery;
28+
&& Query == r.OriginQuery.TrimmedQuery;
2929
}
3030
}
3131
}

Flow.Launcher/Storage/QueryHistory.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public void PopulateHistoryFromLegacyHistory()
3535

3636
public void Add(Result result)
3737
{
38-
if (string.IsNullOrEmpty(result.OriginQuery.RawQuery)) return;
38+
if (string.IsNullOrEmpty(result.OriginQuery.TrimmedQuery)) return;
3939
if (string.IsNullOrEmpty(result.PluginID)) return;
4040

4141
// Maintain the max history limit
@@ -57,7 +57,7 @@ public void Add(Result result)
5757
Title = result.Title,
5858
SubTitle = result.SubTitle,
5959
PluginID = result.PluginID,
60-
Query = result.OriginQuery.RawQuery,
60+
Query = result.OriginQuery.TrimmedQuery,
6161
RecordKey = result.RecordKey,
6262
ExecutedDateTime = DateTime.Now
6363
});

0 commit comments

Comments
 (0)