diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs b/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs index 4cfa83382..1c0013db1 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs @@ -115,7 +115,7 @@ namespace Flow.Launcher.Core.Plugin foreach (var result in queryResponseModel.Result) { - result.Action = c => + result.AsyncAction = async c => { UpdateSettings(result.SettingsChange); @@ -133,15 +133,15 @@ namespace Flow.Launcher.Core.Plugin } else { - var actionResponse = Request(result.JsonRPCAction); + var actionResponse = await RequestAsync(result.JsonRPCAction); - if (string.IsNullOrEmpty(actionResponse)) + if (actionResponse.Length == 0) { return !result.JsonRPCAction.DontHideAfterAction; } - var jsonRpcRequestModel = - JsonSerializer.Deserialize(actionResponse, options); + var jsonRpcRequestModel = await + JsonSerializer.DeserializeAsync(actionResponse, options); if (jsonRpcRequestModel?.Method?.StartsWith("Flow.Launcher.") ?? false) { @@ -166,19 +166,20 @@ namespace Flow.Launcher.Core.Plugin private void ExecuteFlowLauncherAPI(string method, object[] parameters) { var parametersTypeArray = parameters.Select(param => param.GetType()).ToArray(); - MethodInfo methodInfo = PluginManager.API.GetType().GetMethod(method, parametersTypeArray); - if (methodInfo != null) + var methodInfo = typeof(IPublicAPI).GetMethod(method, parametersTypeArray); + if (methodInfo == null) + { + return; + } + try + { + methodInfo.Invoke(PluginManager.API, parameters); + } + catch (Exception) { - try - { - methodInfo.Invoke(PluginManager.API, parameters); - } - catch (Exception) - { #if (DEBUG) - throw; + throw; #endif - } } } @@ -241,7 +242,7 @@ namespace Flow.Launcher.Core.Plugin protected async Task ExecuteAsync(ProcessStartInfo startInfo, CancellationToken token = default) { Process process = null; - bool disposed = false; + using var exitTokenSource = new CancellationTokenSource(); try { process = Process.Start(startInfo); @@ -251,6 +252,7 @@ namespace Flow.Launcher.Core.Plugin return Stream.Null; } + await using var source = process.StandardOutput.BaseStream; var buffer = BufferManager.GetStream(); @@ -259,7 +261,7 @@ namespace Flow.Launcher.Core.Plugin { // ReSharper disable once AccessToModifiedClosure // Manually Check whether disposed - if (!disposed && !process.HasExited) + if (!exitTokenSource.IsCancellationRequested && !process.HasExited) process.Kill(); }); @@ -302,8 +304,8 @@ namespace Flow.Launcher.Core.Plugin } finally { + exitTokenSource.Cancel(); process?.Dispose(); - disposed = true; } } @@ -365,8 +367,7 @@ namespace Flow.Launcher.Core.Plugin var settingWindow = new UserControl(); var mainPanel = new StackPanel { - Margin = settingPanelMargin, - Orientation = Orientation.Vertical + Margin = settingPanelMargin, Orientation = Orientation.Vertical }; settingWindow.Content = mainPanel; @@ -374,8 +375,7 @@ namespace Flow.Launcher.Core.Plugin { var panel = new StackPanel { - Orientation = Orientation.Horizontal, - Margin = settingControlMargin + Orientation = Orientation.Horizontal, Margin = settingControlMargin }; var name = new TextBlock() { diff --git a/Flow.Launcher.Core/Plugin/QueryBuilder.cs b/Flow.Launcher.Core/Plugin/QueryBuilder.cs index ef387b693..a819f94b7 100644 --- a/Flow.Launcher.Core/Plugin/QueryBuilder.cs +++ b/Flow.Launcher.Core/Plugin/QueryBuilder.cs @@ -16,7 +16,7 @@ namespace Flow.Launcher.Core.Plugin return null; } - var rawQuery = string.Join(Query.TermSeparator, terms); + var rawQuery = text; string actionKeyword, search; string possibleActionKeyword = terms[0]; string[] searchTerms; @@ -24,13 +24,13 @@ namespace Flow.Launcher.Core.Plugin if (nonGlobalPlugins.TryGetValue(possibleActionKeyword, out var pluginPair) && !pluginPair.Metadata.Disabled) { // use non global plugin for query actionKeyword = possibleActionKeyword; - search = terms.Length > 1 ? rawQuery[(actionKeyword.Length + 1)..] : string.Empty; + search = terms.Length > 1 ? rawQuery[(actionKeyword.Length + 1)..].TrimStart() : string.Empty; searchTerms = terms[1..]; } else { // non action keyword actionKeyword = string.Empty; - search = rawQuery; + search = rawQuery.TrimStart(); searchTerms = terms; } diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index 4a5eb39af..f80b6c028 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading.Tasks; using System.Windows.Media; namespace Flow.Launcher.Plugin @@ -85,6 +86,14 @@ namespace Flow.Launcher.Plugin /// public Func Action { get; set; } + /// + /// Delegate. An Async action to take in the form of a function call when the result has been selected + /// + /// true to hide flowlauncher after select result + /// + /// + public Func> AsyncAction { get; set; } + /// /// Priority of the current result /// default: 0 @@ -169,5 +178,10 @@ namespace Flow.Launcher.Plugin /// Show message as ToolTip on result SubTitle hover over /// public string SubTitleToolTip { get; set; } + + public ValueTask ExecuteAsync(ActionContext context) + { + return AsyncAction?.Invoke(context) ?? ValueTask.FromResult(Action?.Invoke(context) ?? false); + } } } \ No newline at end of file diff --git a/Flow.Launcher.Test/Plugins/JsonRPCPluginTest.cs b/Flow.Launcher.Test/Plugins/JsonRPCPluginTest.cs index 7231dfbe0..fb91c6388 100644 --- a/Flow.Launcher.Test/Plugins/JsonRPCPluginTest.cs +++ b/Flow.Launcher.Test/Plugins/JsonRPCPluginTest.cs @@ -48,7 +48,7 @@ namespace Flow.Launcher.Test.Plugins foreach (var result in results) { Assert.IsNotNull(result); - Assert.IsNotNull(result.Action); + Assert.IsNotNull(result.AsyncAction); Assert.IsNotNull(result.Title); } @@ -92,7 +92,7 @@ namespace Flow.Launcher.Test.Plugins Assert.AreEqual(result1, referenceResult); Assert.IsNotNull(result1); - Assert.IsNotNull(result1.Action); + Assert.IsNotNull(result1.AsyncAction); } } diff --git a/Flow.Launcher.Test/QueryBuilderTest.cs b/Flow.Launcher.Test/QueryBuilderTest.cs index 6090ecc65..45ff8fc9e 100644 --- a/Flow.Launcher.Test/QueryBuilderTest.cs +++ b/Flow.Launcher.Test/QueryBuilderTest.cs @@ -17,7 +17,7 @@ namespace Flow.Launcher.Test Query q = QueryBuilder.Build("> file.txt file2 file3", nonGlobalPlugins); - Assert.AreEqual("file.txt file2 file3", q.Search); + Assert.AreEqual("file.txt file2 file3", q.Search); Assert.AreEqual(">", q.ActionKeyword); } @@ -31,7 +31,7 @@ namespace Flow.Launcher.Test Query q = QueryBuilder.Build("> file.txt file2 file3", nonGlobalPlugins); - Assert.AreEqual("> file.txt file2 file3", q.Search); + Assert.AreEqual("> file.txt file2 file3", q.Search); } [Test] diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index b96abca95..2a7f9c494 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -86,7 +86,7 @@ Height="32" Margin="0,0,0,0" HorizontalAlignment="Center" - Source="{Binding Image}" + Source="{Binding Image, TargetNullValue={x:Null}}" Stretch="Uniform" Visibility="{Binding ShowIcon}" /> diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 0531c925d..fbcea504e 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -194,37 +194,38 @@ namespace Flow.Launcher.ViewModel PluginManager.API.OpenUrl("https://github.com/Flow-Launcher/Flow.Launcher/wiki/Flow-Launcher/"); }); OpenSettingCommand = new RelayCommand(_ => { App.API.OpenSettingDialog(); }); - OpenResultCommand = new RelayCommand(index => + OpenResultCommand = new RelayCommand(async index => { var results = SelectedResults; if (index != null) { - results.SelectedIndex = int.Parse(index.ToString()); + results.SelectedIndex = int.Parse(index.ToString()!); } var result = results.SelectedItem?.Result; - if (result != null) // SelectedItem returns null if selection is empty. + if (result == null) { - bool hideWindow = result.Action != null && result.Action(new ActionContext - { - SpecialKeyState = GlobalHotkey.CheckModifiers() - }); + return; + } + var hideWindow = await result.ExecuteAsync(new ActionContext + { + SpecialKeyState = GlobalHotkey.CheckModifiers() + }).ConfigureAwait(false); - if (hideWindow) - { - Hide(); - } + if (hideWindow) + { + Hide(); + } - if (SelectedIsFromQueryResults()) - { - _userSelectedRecord.Add(result); - _history.Add(result.OriginQuery.RawQuery); - } - else - { - SelectedResults = Results; - } + if (SelectedIsFromQueryResults()) + { + _userSelectedRecord.Add(result); + _history.Add(result.OriginQuery.RawQuery); + } + else + { + SelectedResults = Results; } }); @@ -572,7 +573,7 @@ namespace Flow.Launcher.ViewModel if (currentCancellationToken.IsCancellationRequested) return; - var query = QueryBuilder.Build(QueryText.Trim(), PluginManager.NonGlobalPlugins); + var query = QueryBuilder.Build(QueryText, PluginManager.NonGlobalPlugins); // handle the exclusiveness of plugin using action keyword RemoveOldQueryResults(query); @@ -664,7 +665,7 @@ namespace Flow.Launcher.ViewModel private void RemoveOldQueryResults(Query query) { - if (_lastQuery.ActionKeyword != query.ActionKeyword) + if (_lastQuery?.ActionKeyword != query?.ActionKeyword) { Results.Clear(); } diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.resx b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.resx index e18d76242..3775e7f5d 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.resx +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.resx @@ -1,4 +1,4 @@ - +