mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Improve and fix query result update logic issue & provide access to exact query typed by user (#3502)
This commit is contained in:
parent
38c0fae064
commit
48f67b1886
13 changed files with 201 additions and 166 deletions
|
|
@ -100,11 +100,11 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
|
|
||||||
RPC = new JsonRpc(handler, new JsonRPCPublicAPI(Context.API));
|
RPC = new JsonRpc(handler, new JsonRPCPublicAPI(Context.API));
|
||||||
|
|
||||||
RPC.AddLocalRpcMethod("UpdateResults", new Action<string, JsonRPCQueryResponseModel>((rawQuery, response) =>
|
RPC.AddLocalRpcMethod("UpdateResults", new Action<string, JsonRPCQueryResponseModel>((trimmedQuery, response) =>
|
||||||
{
|
{
|
||||||
var results = ParseResults(response);
|
var results = ParseResults(response);
|
||||||
ResultsUpdated?.Invoke(this,
|
ResultsUpdated?.Invoke(this,
|
||||||
new ResultUpdatedEventArgs { Query = new Query() { RawQuery = rawQuery }, Results = results });
|
new ResultUpdatedEventArgs { Query = new Query() { TrimmedQuery = trimmedQuery }, Results = results });
|
||||||
}));
|
}));
|
||||||
RPC.SynchronizationContext = null;
|
RPC.SynchronizationContext = null;
|
||||||
RPC.StartListening();
|
RPC.StartListening();
|
||||||
|
|
|
||||||
|
|
@ -401,7 +401,7 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
{
|
{
|
||||||
Title = Localize.pluginStillInitializing(metadata.Name),
|
Title = Localize.pluginStillInitializing(metadata.Name),
|
||||||
SubTitle = Localize.pluginStillInitializingSubtitle(),
|
SubTitle = Localize.pluginStillInitializingSubtitle(),
|
||||||
AutoCompleteText = query.RawQuery,
|
AutoCompleteText = query.TrimmedQuery,
|
||||||
IcoPath = metadata.IcoPath,
|
IcoPath = metadata.IcoPath,
|
||||||
PluginDirectory = metadata.PluginDirectory,
|
PluginDirectory = metadata.PluginDirectory,
|
||||||
ActionKeywordAssigned = query.ActionKeyword,
|
ActionKeywordAssigned = query.ActionKeyword,
|
||||||
|
|
@ -443,7 +443,7 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
{
|
{
|
||||||
Title = Localize.pluginFailedToRespond(metadata.Name),
|
Title = Localize.pluginFailedToRespond(metadata.Name),
|
||||||
SubTitle = Localize.pluginFailedToRespondSubtitle(),
|
SubTitle = Localize.pluginFailedToRespondSubtitle(),
|
||||||
AutoCompleteText = query.RawQuery,
|
AutoCompleteText = query.TrimmedQuery,
|
||||||
IcoPath = Constant.ErrorIcon,
|
IcoPath = Constant.ErrorIcon,
|
||||||
PluginDirectory = metadata.PluginDirectory,
|
PluginDirectory = metadata.PluginDirectory,
|
||||||
ActionKeywordAssigned = query.ActionKeyword,
|
ActionKeywordAssigned = query.ActionKeyword,
|
||||||
|
|
@ -467,7 +467,7 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
{
|
{
|
||||||
Title = Localize.pluginStillInitializing(metadata.Name),
|
Title = Localize.pluginStillInitializing(metadata.Name),
|
||||||
SubTitle = Localize.pluginStillInitializingSubtitle(),
|
SubTitle = Localize.pluginStillInitializingSubtitle(),
|
||||||
AutoCompleteText = query.RawQuery,
|
AutoCompleteText = query.TrimmedQuery,
|
||||||
IcoPath = metadata.IcoPath,
|
IcoPath = metadata.IcoPath,
|
||||||
PluginDirectory = metadata.PluginDirectory,
|
PluginDirectory = metadata.PluginDirectory,
|
||||||
ActionKeywordAssigned = query.ActionKeyword,
|
ActionKeywordAssigned = query.ActionKeyword,
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,16 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
{
|
{
|
||||||
public static class QueryBuilder
|
public static class QueryBuilder
|
||||||
{
|
{
|
||||||
public static Query Build(string text, Dictionary<string, PluginPair> nonGlobalPlugins)
|
public static Query Build(string originalQuery, string trimmedQuery, Dictionary<string, PluginPair> nonGlobalPlugins)
|
||||||
{
|
{
|
||||||
// home query
|
// home query
|
||||||
if (string.IsNullOrEmpty(text))
|
if (string.IsNullOrEmpty(trimmedQuery))
|
||||||
{
|
{
|
||||||
return new Query()
|
return new Query()
|
||||||
{
|
{
|
||||||
Search = string.Empty,
|
Search = string.Empty,
|
||||||
RawQuery = string.Empty,
|
OriginalQuery = string.Empty,
|
||||||
|
TrimmedQuery = string.Empty,
|
||||||
SearchTerms = Array.Empty<string>(),
|
SearchTerms = Array.Empty<string>(),
|
||||||
ActionKeyword = string.Empty,
|
ActionKeyword = string.Empty,
|
||||||
IsHomeQuery = true
|
IsHomeQuery = true
|
||||||
|
|
@ -22,14 +23,13 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace multiple white spaces with one white space
|
// replace multiple white spaces with one white space
|
||||||
var terms = text.Split(Query.TermSeparator, StringSplitOptions.RemoveEmptyEntries);
|
var terms = trimmedQuery.Split(Query.TermSeparator, StringSplitOptions.RemoveEmptyEntries);
|
||||||
if (terms.Length == 0)
|
if (terms.Length == 0)
|
||||||
{
|
{
|
||||||
// nothing was typed
|
// nothing was typed
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var rawQuery = text;
|
|
||||||
string actionKeyword, search;
|
string actionKeyword, search;
|
||||||
string possibleActionKeyword = terms[0];
|
string possibleActionKeyword = terms[0];
|
||||||
string[] searchTerms;
|
string[] searchTerms;
|
||||||
|
|
@ -38,21 +38,22 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
{
|
{
|
||||||
// use non global plugin for query
|
// use non global plugin for query
|
||||||
actionKeyword = possibleActionKeyword;
|
actionKeyword = possibleActionKeyword;
|
||||||
search = terms.Length > 1 ? rawQuery[(actionKeyword.Length + 1)..].TrimStart() : string.Empty;
|
search = terms.Length > 1 ? trimmedQuery[(actionKeyword.Length + 1)..].TrimStart() : string.Empty;
|
||||||
searchTerms = terms[1..];
|
searchTerms = terms[1..];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// non action keyword
|
// non action keyword
|
||||||
actionKeyword = string.Empty;
|
actionKeyword = string.Empty;
|
||||||
search = rawQuery.TrimStart();
|
search = trimmedQuery.TrimStart();
|
||||||
searchTerms = terms;
|
searchTerms = terms;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Query()
|
return new Query()
|
||||||
{
|
{
|
||||||
Search = search,
|
Search = search,
|
||||||
RawQuery = rawQuery,
|
OriginalQuery = originalQuery,
|
||||||
|
TrimmedQuery = trimmedQuery,
|
||||||
SearchTerms = searchTerms,
|
SearchTerms = searchTerms,
|
||||||
ActionKeyword = actionKeyword,
|
ActionKeyword = actionKeyword,
|
||||||
IsHomeQuery = false
|
IsHomeQuery = false
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Text.Json.Serialization;
|
using System;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin
|
namespace Flow.Launcher.Plugin
|
||||||
{
|
{
|
||||||
|
|
@ -8,11 +9,29 @@ namespace Flow.Launcher.Plugin
|
||||||
public class Query
|
public class Query
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raw query, this includes action keyword if it has.
|
/// Original query, exactly how the user has typed into the search box.
|
||||||
/// It has handled buildin custom query shortkeys and build-in shortcuts, and it trims the whitespace.
|
/// We don't recommend using this property directly. You should always use Search property.
|
||||||
/// We didn't recommend use this property directly. You should always use Search property.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string RawQuery { get; internal init; }
|
public string OriginalQuery { get; internal init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raw query, this includes action keyword if it has.
|
||||||
|
/// It has handled built-in custom query hotkeys and built-in shortcuts, and it trims the whitespace.
|
||||||
|
/// We don't recommend using this property directly. You should always use Search property.
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("RawQuery is renamed to TrimmedQuery. This property will be removed. Update the code to use TrimmedQuery instead.")]
|
||||||
|
public string RawQuery {
|
||||||
|
get => TrimmedQuery;
|
||||||
|
internal init { TrimmedQuery = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Original query but with trimmed whitespace. Includes action keyword.
|
||||||
|
/// It has handled built-in custom query hotkeys and build-in shortcuts.
|
||||||
|
/// If you need the exact original query from the search box, use OriginalQuery property instead.
|
||||||
|
/// We don't recommend using this property directly. You should always use Search property.
|
||||||
|
/// </summary>
|
||||||
|
public string TrimmedQuery { get; internal init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the query was forced to execute again.
|
/// Determines whether the query was forced to execute again.
|
||||||
|
|
@ -28,7 +47,7 @@ namespace Flow.Launcher.Plugin
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Search part of a query.
|
/// Search part of a query.
|
||||||
/// This will not include action keyword if exclusive plugin gets it, otherwise it should be same as RawQuery.
|
/// This will not include action keyword if exclusive plugin gets it, otherwise it should be same as TrimmedQuery.
|
||||||
/// Since we allow user to switch a exclusive plugin to generic plugin,
|
/// Since we allow user to switch a exclusive plugin to generic plugin,
|
||||||
/// so this property will always give you the "real" query part of the query
|
/// so this property will always give you the "real" query part of the query
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -103,6 +122,6 @@ namespace Flow.Launcher.Plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString() => RawQuery;
|
public override string ToString() => TrimmedQuery;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,9 @@ namespace Flow.Launcher.Test
|
||||||
{">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List<string> {">"}}}}
|
{">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List<string> {">"}}}}
|
||||||
};
|
};
|
||||||
|
|
||||||
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", nonGlobalPlugins);
|
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", "> ping google.com -n 20 -6", nonGlobalPlugins);
|
||||||
|
|
||||||
ClassicAssert.AreEqual("> ping google.com -n 20 -6", q.RawQuery);
|
ClassicAssert.AreEqual("> ping google.com -n 20 -6", q.TrimmedQuery);
|
||||||
ClassicAssert.AreEqual("ping google.com -n 20 -6", q.Search, "Search should not start with the ActionKeyword.");
|
ClassicAssert.AreEqual("ping google.com -n 20 -6", q.Search, "Search should not start with the ActionKeyword.");
|
||||||
ClassicAssert.AreEqual(">", q.ActionKeyword);
|
ClassicAssert.AreEqual(">", q.ActionKeyword);
|
||||||
|
|
||||||
|
|
@ -39,10 +39,10 @@ namespace Flow.Launcher.Test
|
||||||
{">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List<string> {">"}, Disabled = true}}}
|
{">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List<string> {">"}, Disabled = true}}}
|
||||||
};
|
};
|
||||||
|
|
||||||
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", nonGlobalPlugins);
|
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", "> ping google.com -n 20 -6", nonGlobalPlugins);
|
||||||
|
|
||||||
ClassicAssert.AreEqual("> ping google.com -n 20 -6", q.Search);
|
ClassicAssert.AreEqual("> ping google.com -n 20 -6", q.Search);
|
||||||
ClassicAssert.AreEqual(q.Search, q.RawQuery, "RawQuery should be equal to Search.");
|
ClassicAssert.AreEqual(q.Search, q.TrimmedQuery, "TrimmedQuery should be equal to Search.");
|
||||||
ClassicAssert.AreEqual(6, q.SearchTerms.Length, "The length of SearchTerms should match.");
|
ClassicAssert.AreEqual(6, q.SearchTerms.Length, "The length of SearchTerms should match.");
|
||||||
ClassicAssert.AreNotEqual(">", q.ActionKeyword, "ActionKeyword should not match that of a disabled plugin.");
|
ClassicAssert.AreNotEqual(">", q.ActionKeyword, "ActionKeyword should not match that of a disabled plugin.");
|
||||||
ClassicAssert.AreEqual("ping google.com -n 20 -6", q.SecondToEndSearch, "SecondToEndSearch should be trimmed of multiple whitespace characters");
|
ClassicAssert.AreEqual("ping google.com -n 20 -6", q.SecondToEndSearch, "SecondToEndSearch should be trimmed of multiple whitespace characters");
|
||||||
|
|
@ -51,7 +51,7 @@ namespace Flow.Launcher.Test
|
||||||
[Test]
|
[Test]
|
||||||
public void GenericPluginQueryTest()
|
public void GenericPluginQueryTest()
|
||||||
{
|
{
|
||||||
Query q = QueryBuilder.Build("file.txt file2 file3", new Dictionary<string, PluginPair>());
|
Query q = QueryBuilder.Build("file.txt file2 file3", "file.txt file2 file3", new Dictionary<string, PluginPair>());
|
||||||
|
|
||||||
ClassicAssert.AreEqual("file.txt file2 file3", q.Search);
|
ClassicAssert.AreEqual("file.txt file2 file3", q.Search);
|
||||||
ClassicAssert.AreEqual("", q.ActionKeyword);
|
ClassicAssert.AreEqual("", q.ActionKeyword);
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,11 @@ public static class ResultHelper
|
||||||
return await PopulateResultsAsync(item.PluginID, item.Query, item.Title, item.SubTitle, item.RecordKey);
|
return await PopulateResultsAsync(item.PluginID, item.Query, item.Title, item.SubTitle, item.RecordKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<Result?> PopulateResultsAsync(string pluginId, string rawQuery, string title, string subTitle, string recordKey)
|
public static async Task<Result?> PopulateResultsAsync(string pluginId, string trimmedQuery, string title, string subTitle, string recordKey)
|
||||||
{
|
{
|
||||||
var plugin = PluginManager.GetPluginForId(pluginId);
|
var plugin = PluginManager.GetPluginForId(pluginId);
|
||||||
if (plugin == null) return null;
|
if (plugin == null) return null;
|
||||||
var query = QueryBuilder.Build(rawQuery, PluginManager.GetNonGlobalPlugins());
|
var query = QueryBuilder.Build(trimmedQuery, trimmedQuery, PluginManager.GetNonGlobalPlugins());
|
||||||
if (query == null) return null;
|
if (query == null) return null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -477,7 +477,7 @@ namespace Flow.Launcher
|
||||||
&& QueryTextBox.CaretIndex == QueryTextBox.Text.Length)
|
&& QueryTextBox.CaretIndex == QueryTextBox.Text.Length)
|
||||||
{
|
{
|
||||||
var queryWithoutActionKeyword =
|
var queryWithoutActionKeyword =
|
||||||
QueryBuilder.Build(QueryTextBox.Text.Trim(), PluginManager.GetNonGlobalPlugins())?.Search;
|
QueryBuilder.Build(QueryTextBox.Text, QueryTextBox.Text.Trim(), PluginManager.GetNonGlobalPlugins())?.Search;
|
||||||
|
|
||||||
if (FilesFolders.IsLocationPathString(queryWithoutActionKeyword))
|
if (FilesFolders.IsLocationPathString(queryWithoutActionKeyword))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
|
@ -9,7 +10,7 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
public partial class ResultListBox
|
public partial class ResultListBox
|
||||||
{
|
{
|
||||||
protected object _lock = new object();
|
protected Lock _lock = new();
|
||||||
private Point _lastpos;
|
private Point _lastpos;
|
||||||
private ListBoxItem curItem = null;
|
private ListBoxItem curItem = null;
|
||||||
public ResultListBox()
|
public ResultListBox()
|
||||||
|
|
@ -88,12 +89,11 @@ namespace Flow.Launcher
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Point _start;
|
||||||
private Point start;
|
private string _path;
|
||||||
private string path;
|
private string _trimmedQuery;
|
||||||
private string query;
|
|
||||||
// this method is called by the UI thread, which is single threaded, so we can be sloppy with locking
|
// this method is called by the UI thread, which is single threaded, so we can be sloppy with locking
|
||||||
private bool isDragging;
|
private bool _isDragging;
|
||||||
|
|
||||||
private void ResultList_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
private void ResultList_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
@ -104,53 +104,55 @@ namespace Flow.Launcher
|
||||||
Result:
|
Result:
|
||||||
{
|
{
|
||||||
CopyText: { } copyText,
|
CopyText: { } copyText,
|
||||||
OriginQuery.RawQuery: { } rawQuery
|
OriginQuery.TrimmedQuery: { } trimmedQuery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}) return;
|
}) return;
|
||||||
|
|
||||||
path = copyText;
|
_path = copyText;
|
||||||
query = rawQuery;
|
_trimmedQuery = trimmedQuery;
|
||||||
start = e.GetPosition(null);
|
_start = e.GetPosition(null);
|
||||||
isDragging = true;
|
_isDragging = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResultList_MouseMove(object sender, MouseEventArgs e)
|
private void ResultList_MouseMove(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.LeftButton != MouseButtonState.Pressed || !isDragging)
|
if (e.LeftButton != MouseButtonState.Pressed || !_isDragging)
|
||||||
{
|
{
|
||||||
start = default;
|
_start = default;
|
||||||
path = string.Empty;
|
_path = string.Empty;
|
||||||
query = string.Empty;
|
_trimmedQuery = string.Empty;
|
||||||
isDragging = false;
|
_isDragging = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!File.Exists(path) && !Directory.Exists(path))
|
if (!File.Exists(_path) && !Directory.Exists(_path))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Point mousePosition = e.GetPosition(null);
|
Point mousePosition = e.GetPosition(null);
|
||||||
Vector diff = this.start - mousePosition;
|
Vector diff = _start - mousePosition;
|
||||||
|
|
||||||
if (Math.Abs(diff.X) < SystemParameters.MinimumHorizontalDragDistance
|
if (Math.Abs(diff.X) < SystemParameters.MinimumHorizontalDragDistance
|
||||||
|| Math.Abs(diff.Y) < SystemParameters.MinimumVerticalDragDistance)
|
|| Math.Abs(diff.Y) < SystemParameters.MinimumVerticalDragDistance)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
isDragging = false;
|
_isDragging = false;
|
||||||
|
|
||||||
App.API.HideMainWindow();
|
App.API.HideMainWindow();
|
||||||
|
|
||||||
var data = new DataObject(DataFormats.FileDrop, new[]
|
var data = new DataObject(DataFormats.FileDrop, new[]
|
||||||
{
|
{
|
||||||
path
|
_path
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reassigning query to a new variable because for some reason
|
// Reassigning query to a new variable because for some reason
|
||||||
// after DragDrop.DoDragDrop call, 'query' loses its content, i.e. becomes empty string
|
// after DragDrop.DoDragDrop call, 'query' loses its content, i.e. becomes empty string
|
||||||
var rawQuery = query;
|
var trimmedQuery = _trimmedQuery;
|
||||||
var effect = DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Move | DragDropEffects.Copy);
|
var effect = DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Move | DragDropEffects.Copy);
|
||||||
if (effect == DragDropEffects.Move)
|
if (effect == DragDropEffects.Move)
|
||||||
App.API.ChangeQuery(rawQuery, true);
|
App.API.ChangeQuery(trimmedQuery, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResultListBox_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
private void ResultListBox_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })
|
if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })
|
||||||
|
|
@ -158,6 +160,7 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
RightClickResultCommand?.Execute(result.Result);
|
RightClickResultCommand?.Execute(result.Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResultListBox_OnPreviewMouseUp(object sender, MouseButtonEventArgs e)
|
private void ResultListBox_OnPreviewMouseUp(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })
|
if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,13 @@ public class LastOpenedHistoryItem
|
||||||
return Title == r.Title
|
return Title == r.Title
|
||||||
&& SubTitle == r.SubTitle
|
&& SubTitle == r.SubTitle
|
||||||
&& PluginID == r.PluginID
|
&& PluginID == r.PluginID
|
||||||
&& Query == r.OriginQuery.RawQuery;
|
&& Query == r.OriginQuery.TrimmedQuery;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return RecordKey == r.RecordKey
|
return RecordKey == r.RecordKey
|
||||||
&& PluginID == r.PluginID
|
&& PluginID == r.PluginID
|
||||||
&& Query == r.OriginQuery.RawQuery;
|
&& Query == r.OriginQuery.TrimmedQuery;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ namespace Flow.Launcher.Storage
|
||||||
|
|
||||||
public void Add(Result result)
|
public void Add(Result result)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(result.OriginQuery.RawQuery)) return;
|
if (string.IsNullOrEmpty(result.OriginQuery.TrimmedQuery)) return;
|
||||||
if (string.IsNullOrEmpty(result.PluginID)) return;
|
if (string.IsNullOrEmpty(result.PluginID)) return;
|
||||||
|
|
||||||
// Maintain the max history limit
|
// Maintain the max history limit
|
||||||
|
|
@ -57,7 +57,7 @@ namespace Flow.Launcher.Storage
|
||||||
Title = result.Title,
|
Title = result.Title,
|
||||||
SubTitle = result.SubTitle,
|
SubTitle = result.SubTitle,
|
||||||
PluginID = result.PluginID,
|
PluginID = result.PluginID,
|
||||||
Query = result.OriginQuery.RawQuery,
|
Query = result.OriginQuery.TrimmedQuery,
|
||||||
RecordKey = result.RecordKey,
|
RecordKey = result.RecordKey,
|
||||||
ExecutedDateTime = DateTime.Now
|
ExecutedDateTime = DateTime.Now
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ namespace Flow.Launcher.Storage
|
||||||
|
|
||||||
internal bool IsTopMost(Result result)
|
internal bool IsTopMost(Result result)
|
||||||
{
|
{
|
||||||
if (records.IsEmpty || !records.TryGetValue(result.OriginQuery.RawQuery, out var value))
|
if (records.IsEmpty || !records.TryGetValue(result.OriginQuery.TrimmedQuery, out var value))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +124,7 @@ namespace Flow.Launcher.Storage
|
||||||
|
|
||||||
internal void Remove(Result result)
|
internal void Remove(Result result)
|
||||||
{
|
{
|
||||||
records.Remove(result.OriginQuery.RawQuery, out _);
|
records.Remove(result.OriginQuery.TrimmedQuery, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddOrUpdate(Result result)
|
internal void AddOrUpdate(Result result)
|
||||||
|
|
@ -136,7 +136,7 @@ namespace Flow.Launcher.Storage
|
||||||
SubTitle = result.SubTitle,
|
SubTitle = result.SubTitle,
|
||||||
RecordKey = result.RecordKey
|
RecordKey = result.RecordKey
|
||||||
};
|
};
|
||||||
records.AddOrUpdate(result.OriginQuery.RawQuery, record, (key, oldValue) => record);
|
records.AddOrUpdate(result.OriginQuery.TrimmedQuery, record, (key, oldValue) => record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,7 +154,7 @@ namespace Flow.Launcher.Storage
|
||||||
// origin query is null when user select the context menu item directly of one item from query list
|
// origin query is null when user select the context menu item directly of one item from query list
|
||||||
// in this case, we do not need to check if the result is top most
|
// in this case, we do not need to check if the result is top most
|
||||||
if (records.IsEmpty || result.OriginQuery == null ||
|
if (records.IsEmpty || result.OriginQuery == null ||
|
||||||
!records.TryGetValue(result.OriginQuery.RawQuery, out var value))
|
!records.TryGetValue(result.OriginQuery.TrimmedQuery, out var value))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -168,7 +168,7 @@ namespace Flow.Launcher.Storage
|
||||||
// origin query is null when user select the context menu item directly of one item from query list
|
// origin query is null when user select the context menu item directly of one item from query list
|
||||||
// in this case, we do not need to check if the result is top most
|
// in this case, we do not need to check if the result is top most
|
||||||
if (records.IsEmpty || result.OriginQuery == null ||
|
if (records.IsEmpty || result.OriginQuery == null ||
|
||||||
!records.TryGetValue(result.OriginQuery.RawQuery, out var value))
|
!records.TryGetValue(result.OriginQuery.TrimmedQuery, out var value))
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +194,7 @@ namespace Flow.Launcher.Storage
|
||||||
// origin query is null when user select the context menu item directly of one item from query list
|
// origin query is null when user select the context menu item directly of one item from query list
|
||||||
// in this case, we do not need to remove the record
|
// in this case, we do not need to remove the record
|
||||||
if (result.OriginQuery == null ||
|
if (result.OriginQuery == null ||
|
||||||
!records.TryGetValue(result.OriginQuery.RawQuery, out var value))
|
!records.TryGetValue(result.OriginQuery.TrimmedQuery, out var value))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -204,12 +204,12 @@ namespace Flow.Launcher.Storage
|
||||||
if (queue.IsEmpty)
|
if (queue.IsEmpty)
|
||||||
{
|
{
|
||||||
// if the queue is empty, remove the queue from the dictionary
|
// if the queue is empty, remove the queue from the dictionary
|
||||||
records.TryRemove(result.OriginQuery.RawQuery, out _);
|
records.TryRemove(result.OriginQuery.TrimmedQuery, out _);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// change the queue in the dictionary
|
// change the queue in the dictionary
|
||||||
records[result.OriginQuery.RawQuery] = queue;
|
records[result.OriginQuery.TrimmedQuery] = queue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -229,19 +229,19 @@ namespace Flow.Launcher.Storage
|
||||||
SubTitle = result.SubTitle,
|
SubTitle = result.SubTitle,
|
||||||
RecordKey = result.RecordKey
|
RecordKey = result.RecordKey
|
||||||
};
|
};
|
||||||
if (!records.TryGetValue(result.OriginQuery.RawQuery, out var value))
|
if (!records.TryGetValue(result.OriginQuery.TrimmedQuery, out var value))
|
||||||
{
|
{
|
||||||
// create a new queue if it does not exist
|
// create a new queue if it does not exist
|
||||||
value = new ConcurrentQueue<Record>();
|
value = new ConcurrentQueue<Record>();
|
||||||
value.Enqueue(record);
|
value.Enqueue(record);
|
||||||
records.TryAdd(result.OriginQuery.RawQuery, value);
|
records.TryAdd(result.OriginQuery.TrimmedQuery, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// add or update the record in the queue
|
// add or update the record in the queue
|
||||||
var queue = new ConcurrentQueue<Record>(value.Where(r => !r.Equals(result))); // make sure we don't have duplicates
|
var queue = new ConcurrentQueue<Record>(value.Where(r => !r.Equals(result))); // make sure we don't have duplicates
|
||||||
queue.Enqueue(record);
|
queue.Enqueue(record);
|
||||||
records[result.OriginQuery.RawQuery] = queue;
|
records[result.OriginQuery.TrimmedQuery] = queue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,10 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
private static readonly string ClassName = nameof(MainViewModel);
|
private static readonly string ClassName = nameof(MainViewModel);
|
||||||
|
|
||||||
private bool _isQueryRunning;
|
|
||||||
private Query _lastQuery;
|
private Query _lastQuery;
|
||||||
private bool _previousIsHomeQuery;
|
private bool _previousIsHomeQuery;
|
||||||
|
private Query _progressQuery; // Used for QueryResultAsync
|
||||||
|
private Query _updateQuery; // Used for ResultsUpdated
|
||||||
private string _queryTextBeforeLeaveResults;
|
private string _queryTextBeforeLeaveResults;
|
||||||
private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results
|
private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results
|
||||||
|
|
||||||
|
|
@ -283,7 +284,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
plugin.ResultsUpdated += (s, e) =>
|
plugin.ResultsUpdated += (s, e) =>
|
||||||
{
|
{
|
||||||
if (e.Query.RawQuery != QueryText || e.Token.IsCancellationRequested)
|
if (_updateQuery == null || e.Query.OriginalQuery != _updateQuery.OriginalQuery || e.Token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -442,7 +443,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void Backspace(object index)
|
private void Backspace(object index)
|
||||||
{
|
{
|
||||||
var query = QueryBuilder.Build(QueryText.Trim(), PluginManager.GetNonGlobalPlugins());
|
var query = QueryBuilder.Build(QueryText, QueryText.Trim(), PluginManager.GetNonGlobalPlugins());
|
||||||
|
|
||||||
// GetPreviousExistingDirectory does not require trailing '\', otherwise will return empty string
|
// GetPreviousExistingDirectory does not require trailing '\', otherwise will return empty string
|
||||||
var path = FilesFolders.GetPreviousExistingDirectory((_) => true, query.Search.TrimEnd('\\'));
|
var path = FilesFolders.GetPreviousExistingDirectory((_) => true, query.Search.TrimEnd('\\'));
|
||||||
|
|
@ -1327,7 +1328,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
Title = Localize.executeQuery(h.Query),
|
Title = Localize.executeQuery(h.Query),
|
||||||
SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime),
|
SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime),
|
||||||
IcoPath = Constant.HistoryIcon,
|
IcoPath = Constant.HistoryIcon,
|
||||||
OriginQuery = new Query { RawQuery = h.Query },
|
OriginQuery = new Query { TrimmedQuery = h.Query },
|
||||||
Action = _ =>
|
Action = _ =>
|
||||||
{
|
{
|
||||||
App.API.BackToQueryResults();
|
App.API.BackToQueryResults();
|
||||||
|
|
@ -1350,7 +1351,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
h.Title,
|
h.Title,
|
||||||
SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime),
|
SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime),
|
||||||
IcoPath = Constant.HistoryIcon,
|
IcoPath = Constant.HistoryIcon,
|
||||||
OriginQuery = new Query { RawQuery = h.Query },
|
OriginQuery = new Query { TrimmedQuery = h.Query },
|
||||||
AsyncAction = async c =>
|
AsyncAction = async c =>
|
||||||
{
|
{
|
||||||
var reflectResult = await ResultHelper.PopulateResultsAsync(h);
|
var reflectResult = await ResultHelper.PopulateResultsAsync(h);
|
||||||
|
|
@ -1391,7 +1392,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
App.API.LogDebug(ClassName, $"Start query with ActionKeyword <{query.ActionKeyword}> and RawQuery <{query.RawQuery}>");
|
App.API.LogDebug(ClassName, $"Start query with ActionKeyword <{query.ActionKeyword}> and TrimmedQuery <{query.TrimmedQuery}>");
|
||||||
|
|
||||||
var currentIsHomeQuery = query.IsHomeQuery;
|
var currentIsHomeQuery = query.IsHomeQuery;
|
||||||
var currentIsDialogJump = _isDialogJump;
|
var currentIsDialogJump = _isDialogJump;
|
||||||
|
|
@ -1403,69 +1404,73 @@ namespace Flow.Launcher.ViewModel
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateSource?.Dispose();
|
try
|
||||||
|
|
||||||
var currentUpdateSource = new CancellationTokenSource();
|
|
||||||
_updateSource = currentUpdateSource;
|
|
||||||
var currentCancellationToken = _updateSource.Token;
|
|
||||||
_updateToken = currentCancellationToken;
|
|
||||||
|
|
||||||
ProgressBarVisibility = Visibility.Hidden;
|
|
||||||
_isQueryRunning = true;
|
|
||||||
|
|
||||||
// Switch to ThreadPool thread
|
|
||||||
await TaskScheduler.Default;
|
|
||||||
|
|
||||||
if (currentCancellationToken.IsCancellationRequested) return;
|
|
||||||
|
|
||||||
// Update the query's IsReQuery property to true if this is a re-query
|
|
||||||
query.IsReQuery = isReQuery;
|
|
||||||
|
|
||||||
ICollection<PluginPair> plugins = Array.Empty<PluginPair>();
|
|
||||||
if (currentIsHomeQuery)
|
|
||||||
{
|
{
|
||||||
if (Settings.ShowHomePage)
|
_updateSource?.Dispose();
|
||||||
{
|
|
||||||
plugins = PluginManager.ValidPluginsForHomeQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginIconPath = null;
|
var currentUpdateSource = new CancellationTokenSource();
|
||||||
PluginIconSource = null;
|
_updateSource = currentUpdateSource;
|
||||||
SearchIconVisibility = Visibility.Visible;
|
var currentCancellationToken = _updateSource.Token;
|
||||||
}
|
_updateToken = currentCancellationToken;
|
||||||
else
|
|
||||||
{
|
|
||||||
plugins = PluginManager.ValidPluginsForQuery(query, currentIsDialogJump);
|
|
||||||
|
|
||||||
if (plugins.Count == 1)
|
ProgressBarVisibility = Visibility.Hidden;
|
||||||
{
|
|
||||||
PluginIconPath = plugins.Single().Metadata.IcoPath;
|
_progressQuery = query;
|
||||||
PluginIconSource = await App.API.LoadImageAsync(PluginIconPath);
|
_updateQuery = query;
|
||||||
SearchIconVisibility = Visibility.Hidden;
|
|
||||||
}
|
// Switch to ThreadPool thread
|
||||||
else
|
await TaskScheduler.Default;
|
||||||
|
|
||||||
|
if (currentCancellationToken.IsCancellationRequested) return;
|
||||||
|
|
||||||
|
// Update the query's IsReQuery property to true if this is a re-query
|
||||||
|
query.IsReQuery = isReQuery;
|
||||||
|
|
||||||
|
ICollection<PluginPair> plugins = Array.Empty<PluginPair>();
|
||||||
|
if (currentIsHomeQuery)
|
||||||
{
|
{
|
||||||
|
if (Settings.ShowHomePage)
|
||||||
|
{
|
||||||
|
plugins = PluginManager.ValidPluginsForHomeQuery();
|
||||||
|
}
|
||||||
|
|
||||||
PluginIconPath = null;
|
PluginIconPath = null;
|
||||||
PluginIconSource = null;
|
PluginIconSource = null;
|
||||||
SearchIconVisibility = Visibility.Visible;
|
SearchIconVisibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
plugins = PluginManager.ValidPluginsForQuery(query, currentIsDialogJump);
|
||||||
|
|
||||||
App.API.LogDebug(ClassName, $"Valid <{plugins.Count}> plugins: {string.Join(" ", plugins.Select(x => $"<{x.Metadata.Name}>"))}");
|
if (plugins.Count == 1)
|
||||||
|
{
|
||||||
|
PluginIconPath = plugins.Single().Metadata.IcoPath;
|
||||||
|
PluginIconSource = await App.API.LoadImageAsync(PluginIconPath);
|
||||||
|
SearchIconVisibility = Visibility.Hidden;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PluginIconPath = null;
|
||||||
|
PluginIconSource = null;
|
||||||
|
SearchIconVisibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Do not wait for performance improvement
|
App.API.LogDebug(ClassName, $"Valid <{plugins.Count}> plugins: {string.Join(" ", plugins.Select(x => $"<{x.Metadata.Name}>"))}");
|
||||||
/*if (string.IsNullOrEmpty(query.ActionKeyword))
|
|
||||||
{
|
|
||||||
// Wait 15 millisecond for query change in global query
|
|
||||||
// if query changes, return so that it won't be calculated
|
|
||||||
await Task.Delay(15, currentCancellationToken);
|
|
||||||
if (currentCancellationToken.IsCancellationRequested) return;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
_ = Task.Delay(200, currentCancellationToken).ContinueWith(_ =>
|
// Do not wait for performance improvement
|
||||||
|
/*if (string.IsNullOrEmpty(query.ActionKeyword))
|
||||||
|
{
|
||||||
|
// Wait 15 millisecond for query change in global query
|
||||||
|
// if query changes, return so that it won't be calculated
|
||||||
|
await Task.Delay(15, currentCancellationToken);
|
||||||
|
if (currentCancellationToken.IsCancellationRequested) return;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
_ = Task.Delay(200, currentCancellationToken).ContinueWith(_ =>
|
||||||
{
|
{
|
||||||
// start the progress bar if query takes more than 200 ms and this is the current running query and it didn't finish yet
|
// start the progress bar if query takes more than 200 ms and this is the current running query and it didn't finish yet
|
||||||
if (_isQueryRunning)
|
if (_progressQuery != null && _progressQuery.OriginalQuery == query.OriginalQuery)
|
||||||
{
|
{
|
||||||
ProgressBarVisibility = Visibility.Visible;
|
ProgressBarVisibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
|
|
@ -1474,58 +1479,65 @@ namespace Flow.Launcher.ViewModel
|
||||||
TaskContinuationOptions.NotOnCanceled,
|
TaskContinuationOptions.NotOnCanceled,
|
||||||
TaskScheduler.Default);
|
TaskScheduler.Default);
|
||||||
|
|
||||||
// plugins are ICollection, meaning LINQ will get the Count and preallocate Array
|
// plugins are ICollection, meaning LINQ will get the Count and preallocate Array
|
||||||
|
|
||||||
Task[] tasks;
|
Task[] tasks;
|
||||||
if (currentIsHomeQuery)
|
if (currentIsHomeQuery)
|
||||||
{
|
|
||||||
if (ShouldClearExistingResultsForNonQuery(plugins))
|
|
||||||
{
|
{
|
||||||
Results.Clear();
|
if (ShouldClearExistingResultsForNonQuery(plugins))
|
||||||
App.API.LogDebug(ClassName, $"Existing results are cleared for non-query");
|
{
|
||||||
|
// there are no update tasks and so we can directly return
|
||||||
|
ClearResults();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks = plugins.Select(plugin => plugin.Metadata.HomeDisabled switch
|
||||||
|
{
|
||||||
|
false => QueryTaskAsync(plugin, currentCancellationToken),
|
||||||
|
true => Task.CompletedTask
|
||||||
|
}).ToArray();
|
||||||
|
|
||||||
|
// Query history results for home page firstly so it will be put on top of the results
|
||||||
|
if (Settings.ShowHistoryResultsForHomePage)
|
||||||
|
{
|
||||||
|
QueryHistoryTask(currentCancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch
|
||||||
|
{
|
||||||
|
false => QueryTaskAsync(plugin, currentCancellationToken),
|
||||||
|
true => Task.CompletedTask
|
||||||
|
}).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks = plugins.Select(plugin => plugin.Metadata.HomeDisabled switch
|
try
|
||||||
{
|
{
|
||||||
false => QueryTaskAsync(plugin, currentCancellationToken),
|
// Check the code, WhenAll will translate all type of IEnumerable or Collection to Array, so make an array at first
|
||||||
true => Task.CompletedTask
|
await Task.WhenAll(tasks);
|
||||||
}).ToArray();
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
// Query history results for home page firstly so it will be put on top of the results
|
if (currentCancellationToken.IsCancellationRequested) return;
|
||||||
if (Settings.ShowHistoryResultsForHomePage)
|
|
||||||
|
// this should happen once after all queries are done so progress bar should continue
|
||||||
|
// until the end of all querying
|
||||||
|
_progressQuery = null;
|
||||||
|
|
||||||
|
if (!currentCancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
QueryHistoryTask(currentCancellationToken);
|
// update to hidden if this is still the current query
|
||||||
|
ProgressBarVisibility = Visibility.Hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
finally
|
||||||
{
|
{
|
||||||
tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch
|
// this make sures progress query is null when this query is canceled
|
||||||
{
|
_progressQuery = null;
|
||||||
false => QueryTaskAsync(plugin, currentCancellationToken),
|
|
||||||
true => Task.CompletedTask
|
|
||||||
}).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Check the code, WhenAll will translate all type of IEnumerable or Collection to Array, so make an array at first
|
|
||||||
await Task.WhenAll(tasks);
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
// nothing to do here
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentCancellationToken.IsCancellationRequested) return;
|
|
||||||
|
|
||||||
// this should happen once after all queries are done so progress bar should continue
|
|
||||||
// until the end of all querying
|
|
||||||
_isQueryRunning = false;
|
|
||||||
|
|
||||||
if (!currentCancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
// update to hidden if this is still the current query
|
|
||||||
ProgressBarVisibility = Visibility.Hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local function
|
// Local function
|
||||||
|
|
@ -1625,7 +1637,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(queryText))
|
if (string.IsNullOrWhiteSpace(queryText))
|
||||||
{
|
{
|
||||||
return QueryBuilder.Build(string.Empty, PluginManager.GetNonGlobalPlugins());
|
return QueryBuilder.Build(string.Empty, string.Empty, PluginManager.GetNonGlobalPlugins());
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryBuilder = new StringBuilder(queryText);
|
var queryBuilder = new StringBuilder(queryText);
|
||||||
|
|
@ -1645,7 +1657,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
// Applying builtin shortcuts
|
// Applying builtin shortcuts
|
||||||
await BuildQueryAsync(builtInShortcuts, queryBuilder, queryBuilderTmp);
|
await BuildQueryAsync(builtInShortcuts, queryBuilder, queryBuilderTmp);
|
||||||
|
|
||||||
return QueryBuilder.Build(queryBuilder.ToString().Trim(), PluginManager.GetNonGlobalPlugins());
|
return QueryBuilder.Build(queryText, queryBuilder.ToString().Trim(), PluginManager.GetNonGlobalPlugins());
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task BuildQueryAsync(IEnumerable<BaseBuiltinShortcutModel> builtInShortcuts,
|
private async Task BuildQueryAsync(IEnumerable<BaseBuiltinShortcutModel> builtInShortcuts,
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
||||||
Action = c =>
|
Action = c =>
|
||||||
{
|
{
|
||||||
Settings.EnableEverythingContentSearch = true;
|
Settings.EnableEverythingContentSearch = true;
|
||||||
Context.API.ChangeQuery(query.RawQuery, true);
|
Context.API.ChangeQuery(query.TrimmedQuery, true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue