diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs
index 455ee096d..89286dfb0 100644
--- a/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs
+++ b/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs
@@ -11,6 +11,8 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
{
internal class PythonEnvironment : AbstractPluginEnvironment
{
+ private static readonly string ClassName = nameof(PythonEnvironment);
+
internal override string Language => AllowedLanguage.Python;
internal override string EnvName => DataLocation.PythonEnvironmentName;
@@ -39,9 +41,20 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
// Python 3.11.4 is no longer Windows 7 compatible. If user is on Win 7 and
// uses Python plugin they need to custom install and use v3.8.9
- JTF.Run(() => DroplexPackage.Drop(App.python_3_11_4_embeddable, InstallPath));
+ JTF.Run(async () =>
+ {
+ try
+ {
+ await DroplexPackage.Drop(App.python_3_11_4_embeddable, InstallPath);
- PluginsSettingsFilePath = ExecutablePath;
+ PluginsSettingsFilePath = ExecutablePath;
+ }
+ catch (System.Exception e)
+ {
+ API.ShowMsgError(API.GetTranslation("failToInstallPythonEnv"));
+ API.LogException(ClassName, "Failed to install Python environment", e);
+ }
+ });
}
internal override PluginPair CreatePluginPair(string filePath, PluginMetadata metadata)
diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs
index 12965286f..724ae20f4 100644
--- a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs
+++ b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs
@@ -11,6 +11,8 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
{
internal class TypeScriptEnvironment : AbstractPluginEnvironment
{
+ private static readonly string ClassName = nameof(TypeScriptEnvironment);
+
internal override string Language => AllowedLanguage.TypeScript;
internal override string EnvName => DataLocation.NodeEnvironmentName;
@@ -34,9 +36,20 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
{
FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s));
- JTF.Run(() => DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath));
+ JTF.Run(async () =>
+ {
+ try
+ {
+ await DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath);
- PluginsSettingsFilePath = ExecutablePath;
+ PluginsSettingsFilePath = ExecutablePath;
+ }
+ catch (System.Exception e)
+ {
+ API.ShowMsgError(API.GetTranslation("failToInstallTypeScriptEnv"));
+ API.LogException(ClassName, "Failed to install TypeScript environment", e);
+ }
+ });
}
internal override PluginPair CreatePluginPair(string filePath, PluginMetadata metadata)
diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs
index 6960b79c9..6a32664a1 100644
--- a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs
+++ b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs
@@ -11,6 +11,8 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
{
internal class TypeScriptV2Environment : AbstractPluginEnvironment
{
+ private static readonly string ClassName = nameof(TypeScriptV2Environment);
+
internal override string Language => AllowedLanguage.TypeScriptV2;
internal override string EnvName => DataLocation.NodeEnvironmentName;
@@ -34,9 +36,20 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
{
FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s));
- JTF.Run(() => DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath));
+ JTF.Run(async () =>
+ {
+ try
+ {
+ await DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath);
- PluginsSettingsFilePath = ExecutablePath;
+ PluginsSettingsFilePath = ExecutablePath;
+ }
+ catch (System.Exception e)
+ {
+ API.ShowMsgError(API.GetTranslation("failToInstallTypeScriptEnv"));
+ API.LogException(ClassName, "Failed to install TypeScript environment", e);
+ }
+ });
}
internal override PluginPair CreatePluginPair(string filePath, PluginMetadata metadata)
diff --git a/Flow.Launcher.Core/Plugin/PluginsLoader.cs b/Flow.Launcher.Core/Plugin/PluginsLoader.cs
index 9d511297e..e9e5ee367 100644
--- a/Flow.Launcher.Core/Plugin/PluginsLoader.cs
+++ b/Flow.Launcher.Core/Plugin/PluginsLoader.cs
@@ -124,13 +124,9 @@ namespace Flow.Launcher.Core.Plugin
API.GetTranslation("pluginsHaveErrored") :
API.GetTranslation("pluginHasErrored");
- _ = Task.Run(() =>
- {
- API.ShowMsgBox($"{errorMessage}{Environment.NewLine}{Environment.NewLine}" +
- $"{errorPluginString}{Environment.NewLine}{Environment.NewLine}" +
- API.GetTranslation("referToLogs"), string.Empty,
- MessageBoxButton.OK, MessageBoxImage.Warning);
- });
+ API.ShowMsgError($"{errorMessage}{Environment.NewLine}{Environment.NewLine}" +
+ $"{errorPluginString}{Environment.NewLine}{Environment.NewLine}" +
+ API.GetTranslation("referToLogs"));
}
return plugins;
diff --git a/Flow.Launcher.Core/Resource/AvailableLanguages.cs b/Flow.Launcher.Core/Resource/AvailableLanguages.cs
index ecaecf646..5534ea172 100644
--- a/Flow.Launcher.Core/Resource/AvailableLanguages.cs
+++ b/Flow.Launcher.Core/Resource/AvailableLanguages.cs
@@ -17,6 +17,7 @@ namespace Flow.Launcher.Core.Resource
public static Language German = new Language("de", "Deutsch");
public static Language Korean = new Language("ko", "한국어");
public static Language Serbian = new Language("sr", "Srpski");
+ public static Language Serbian_Cyrillic = new Language("sr-Cyrl-RS", "Српски");
public static Language Portuguese_Portugal = new Language("pt-pt", "Português");
public static Language Portuguese_Brazil = new Language("pt-br", "Português (Brasil)");
public static Language Spanish = new Language("es", "Spanish");
@@ -47,6 +48,7 @@ namespace Flow.Launcher.Core.Resource
German,
Korean,
Serbian,
+ Serbian_Cyrillic,
Portuguese_Portugal,
Portuguese_Brazil,
Spanish,
@@ -79,7 +81,8 @@ namespace Flow.Launcher.Core.Resource
"da" => "System",
"de" => "System",
"ko" => "시스템",
- "sr" => "Систем",
+ "sr" => "Sistem",
+ "sr-Cyrl-RS" => "Систем",
"pt-pt" => "Sistema",
"pt-br" => "Sistema",
"es" => "Sistema",
diff --git a/Flow.Launcher.Core/packages.lock.json b/Flow.Launcher.Core/packages.lock.json
index 598662936..f5f81e874 100644
--- a/Flow.Launcher.Core/packages.lock.json
+++ b/Flow.Launcher.Core/packages.lock.json
@@ -161,8 +161,8 @@
},
"Microsoft.Win32.SystemEvents": {
"type": "Transitive",
- "resolved": "9.0.8",
- "contentHash": "64oQBN8I8EOcyHGNt6+rlcqm4tlcKfqOpswtBCJZnpzBQ15L6IFKqjnbjbOWBpG9wKq9A/aC2LFSmSqplbwTYA=="
+ "resolved": "7.0.0",
+ "contentHash": "2nXPrhdAyAzir0gLl8Yy8S5Mnm/uBSQQA7jEsILOS1MTyS7DbmV1NgViMtvV1sfCD1ebITpNwb1NIinKeJgUVQ=="
},
"Mono.Cecil": {
"type": "Transitive",
@@ -222,10 +222,10 @@
},
"System.Drawing.Common": {
"type": "Transitive",
- "resolved": "9.0.8",
- "contentHash": "ineIJmF+yuBEHGft9R153J9kmBFaeEfFL5Put5nzENneRcGGPUb3MvM8zrZ5pERQ0jPPSE3Wqw/clXvOq2F/Kw==",
+ "resolved": "7.0.0",
+ "contentHash": "KIX+oBU38pxkKPxvLcLfIkOV5Ien8ReN78wro7OF5/erwcmortzeFx+iBswlh2Vz6gVne0khocQudGwaO1Ey6A==",
"dependencies": {
- "Microsoft.Win32.SystemEvents": "9.0.8"
+ "Microsoft.Win32.SystemEvents": "7.0.0"
}
},
"System.IO.Pipelines": {
diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
index 9f01d5d0f..9aa8f9577 100644
--- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
+++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
@@ -74,7 +74,9 @@
all
-
+
+
+
diff --git a/Flow.Launcher.Infrastructure/packages.lock.json b/Flow.Launcher.Infrastructure/packages.lock.json
index 6786b0f49..ac00d0202 100644
--- a/Flow.Launcher.Infrastructure/packages.lock.json
+++ b/Flow.Launcher.Infrastructure/packages.lock.json
@@ -108,11 +108,11 @@
},
"System.Drawing.Common": {
"type": "Direct",
- "requested": "[9.0.8, )",
- "resolved": "9.0.8",
- "contentHash": "ineIJmF+yuBEHGft9R153J9kmBFaeEfFL5Put5nzENneRcGGPUb3MvM8zrZ5pERQ0jPPSE3Wqw/clXvOq2F/Kw==",
+ "requested": "[7.0.0, )",
+ "resolved": "7.0.0",
+ "contentHash": "KIX+oBU38pxkKPxvLcLfIkOV5Ien8ReN78wro7OF5/erwcmortzeFx+iBswlh2Vz6gVne0khocQudGwaO1Ey6A==",
"dependencies": {
- "Microsoft.Win32.SystemEvents": "9.0.8"
+ "Microsoft.Win32.SystemEvents": "7.0.0"
}
},
"ToolGood.Words.Pinyin": {
@@ -156,8 +156,8 @@
},
"Microsoft.Win32.SystemEvents": {
"type": "Transitive",
- "resolved": "9.0.8",
- "contentHash": "64oQBN8I8EOcyHGNt6+rlcqm4tlcKfqOpswtBCJZnpzBQ15L6IFKqjnbjbOWBpG9wKq9A/aC2LFSmSqplbwTYA=="
+ "resolved": "7.0.0",
+ "contentHash": "2nXPrhdAyAzir0gLl8Yy8S5Mnm/uBSQQA7jEsILOS1MTyS7DbmV1NgViMtvV1sfCD1ebITpNwb1NIinKeJgUVQ=="
},
"Microsoft.Windows.SDK.Win32Docs": {
"type": "Transitive",
diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs
index a459e9ee6..2c9b8d4fd 100644
--- a/Flow.Launcher.Plugin/Result.cs
+++ b/Flow.Launcher.Plugin/Result.cs
@@ -57,7 +57,10 @@ namespace Flow.Launcher.Plugin
/// for user on the plugin result. If autocomplete action for example is tab, pressing tab will have
/// the default constructed autocomplete text (result's Title), or the text provided here if not empty.
///
- /// When a value is not set, the will be used.
+ ///
+ /// When a value is not set, the will be used.
+ /// Please include the action keyword prefix when necessary because Flow does not prepend it automatically.
+ ///
public string AutoCompleteText { get; set; }
///
@@ -257,6 +260,17 @@ namespace Flow.Launcher.Plugin
///
public bool ShowBadge { get; set; } = false;
+ ///
+ /// This holds the text which can be shown as a query suggestion.
+ ///
+ ///
+ /// When a value is not set, the will be used.
+ /// Do not include the action keyword prefix because Flow prepends it automatically.
+ /// If the it does not start with the query text, it will not be shown as a suggestion.
+ /// So make sure to set this value to start with the query text.
+ ///
+ public string QuerySuggestionText { get; set; }
+
///
/// Run this result, asynchronously
///
@@ -307,7 +321,8 @@ namespace Flow.Launcher.Plugin
Preview = Preview,
AddSelectedCount = AddSelectedCount,
RecordKey = RecordKey,
- ShowBadge = ShowBadge
+ ShowBadge = ShowBadge,
+ QuerySuggestionText = QuerySuggestionText
};
}
diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs
index 6e053db29..0360c761e 100644
--- a/Flow.Launcher/App.xaml.cs
+++ b/Flow.Launcher/App.xaml.cs
@@ -297,6 +297,7 @@ namespace Flow.Launcher
});
}
+ [Conditional("RELEASE")]
private static void AutoPluginUpdates()
{
_ = Task.Run(async () =>
diff --git a/Flow.Launcher/Converters/QuerySuggestionBoxConverter.cs b/Flow.Launcher/Converters/QuerySuggestionBoxConverter.cs
index eb492e334..c2d7d016c 100644
--- a/Flow.Launcher/Converters/QuerySuggestionBoxConverter.cs
+++ b/Flow.Launcher/Converters/QuerySuggestionBoxConverter.cs
@@ -33,15 +33,39 @@ public class QuerySuggestionBoxConverter : IMultiValueConverter
{
var selectedResult = selectedItem.Result;
var selectedResultActionKeyword = string.IsNullOrEmpty(selectedResult.ActionKeywordAssigned) ? "" : selectedResult.ActionKeywordAssigned + " ";
- var selectedResultPossibleSuggestion = selectedResultActionKeyword + selectedResult.Title;
- if (!selectedResultPossibleSuggestion.StartsWith(queryText, StringComparison.CurrentCultureIgnoreCase))
+ string selectedResultPossibleSuggestion = null;
+
+ // Firstly check if the result has QuerySuggestionText
+ if (!string.IsNullOrEmpty(selectedResult.QuerySuggestionText))
+ {
+ selectedResultPossibleSuggestion = selectedResultActionKeyword + selectedResult.QuerySuggestionText;
+
+ // If this QuerySuggestionText does not start with the queryText, set it to null
+ if (!selectedResultPossibleSuggestion.StartsWith(queryText, StringComparison.CurrentCultureIgnoreCase))
+ {
+ selectedResultPossibleSuggestion = null;
+ }
+ }
+
+ // Then check Title as suggestion
+ if (string.IsNullOrEmpty(selectedResultPossibleSuggestion))
+ {
+ selectedResultPossibleSuggestion = selectedResultActionKeyword + selectedResult.Title;
+
+ // If this QuerySuggestionText does not start with the queryText, set it to null
+ if (!selectedResultPossibleSuggestion.StartsWith(queryText, StringComparison.CurrentCultureIgnoreCase))
+ {
+ selectedResultPossibleSuggestion = null;
+ }
+ }
+
+ if (string.IsNullOrEmpty(selectedResultPossibleSuggestion))
return string.Empty;
-
// For AutocompleteQueryCommand.
// When user typed lower case and result title is uppercase, we still want to display suggestion
- selectedItem.QuerySuggestionText = queryText + selectedResultPossibleSuggestion.Substring(queryText.Length);
+ selectedItem.QuerySuggestionText = string.Concat(queryText, selectedResultPossibleSuggestion.AsSpan(queryText.Length));
// Check if Text will be larger than our QueryTextBox
Typeface typeface = new Typeface(queryTextBox.FontFamily, queryTextBox.FontStyle, queryTextBox.FontWeight, queryTextBox.FontStretch);
diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml
index bf6cb674e..a9694eba8 100644
--- a/Flow.Launcher/Languages/en.xaml
+++ b/Flow.Launcher/Languages/en.xaml
@@ -34,6 +34,10 @@
Please try again
Unable to parse Http Proxy
+
+ Failed to install TypeScript environment. Please try again later
+ Failed to install Python environment. Please try again later.
+
Failed to register hotkey "{0}". The hotkey may be in use by another program. Change to a different hotkey, or exit another program.
Failed to unregister hotkey "{0}". Please try again or see log for details
diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs
index e0ed105cf..38ca18147 100644
--- a/Flow.Launcher/PublicAPIInstance.cs
+++ b/Flow.Launcher/PublicAPIInstance.cs
@@ -8,6 +8,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
@@ -379,24 +380,35 @@ namespace Flow.Launcher
explorer.Start();
}
}
+ catch (COMException ex) when (ex.ErrorCode == unchecked((int)0x80004004))
+ {
+ /*
+ * The COMException with HResult 0x80004004 is E_ABORT (operation aborted).
+ * Shell APIs often return this when the operation is canceled or the shell cannot complete it cleanly.
+ * It most likely comes from Win32Helper.OpenFolderAndSelectFile(targetPath).
+ * Typical triggers:
+ * The target file/folder was deleted/moved between computing targetPath and the shell call.
+ * The folder is on an offline network/removable drive.
+ * Explorer is restarting/busy and aborts the request.
+ * A selection request to a new/closing Explorer window is canceled.
+ * Because it is commonly user- or environment-driven and not actionable,
+ * we should treat it as expected noise and ignore it to avoid bothering users.
+ */
+ }
catch (Win32Exception ex) when (ex.NativeErrorCode == 2)
{
LogError(ClassName, "File Manager not found");
- ShowMsgBox(
- string.Format(GetTranslation("fileManagerNotFound"), ex.Message),
+ ShowMsgError(
GetTranslation("fileManagerNotFoundTitle"),
- MessageBoxButton.OK,
- MessageBoxImage.Error
+ string.Format(GetTranslation("fileManagerNotFound"), ex.Message)
);
}
catch (Exception ex)
{
LogException(ClassName, "Failed to open folder", ex);
- ShowMsgBox(
- string.Format(GetTranslation("folderOpenError"), ex.Message),
+ ShowMsgError(
GetTranslation("errorTitle"),
- MessageBoxButton.OK,
- MessageBoxImage.Error
+ string.Format(GetTranslation("folderOpenError"), ex.Message)
);
}
}
@@ -424,11 +436,9 @@ namespace Flow.Launcher
{
var tabOrWindow = browserInfo.OpenInTab ? "tab" : "window";
LogException(ClassName, $"Failed to open URL in browser {tabOrWindow}: {path}, {inPrivate ?? browserInfo.EnablePrivate}, {browserInfo.PrivateArg}", e);
- ShowMsgBox(
- GetTranslation("browserOpenError"),
+ ShowMsgError(
GetTranslation("errorTitle"),
- MessageBoxButton.OK,
- MessageBoxImage.Error
+ GetTranslation("browserOpenError")
);
}
}
diff --git a/Flow.Launcher/packages.lock.json b/Flow.Launcher/packages.lock.json
index 9b1bc94a7..a4a3bcd6c 100644
--- a/Flow.Launcher/packages.lock.json
+++ b/Flow.Launcher/packages.lock.json
@@ -552,8 +552,8 @@
},
"Microsoft.Win32.SystemEvents": {
"type": "Transitive",
- "resolved": "9.0.8",
- "contentHash": "64oQBN8I8EOcyHGNt6+rlcqm4tlcKfqOpswtBCJZnpzBQ15L6IFKqjnbjbOWBpG9wKq9A/aC2LFSmSqplbwTYA=="
+ "resolved": "7.0.0",
+ "contentHash": "2nXPrhdAyAzir0gLl8Yy8S5Mnm/uBSQQA7jEsILOS1MTyS7DbmV1NgViMtvV1sfCD1ebITpNwb1NIinKeJgUVQ=="
},
"Mono.Cecil": {
"type": "Transitive",
@@ -677,10 +677,10 @@
},
"System.Drawing.Common": {
"type": "Transitive",
- "resolved": "9.0.8",
- "contentHash": "ineIJmF+yuBEHGft9R153J9kmBFaeEfFL5Put5nzENneRcGGPUb3MvM8zrZ5pERQ0jPPSE3Wqw/clXvOq2F/Kw==",
+ "resolved": "7.0.0",
+ "contentHash": "KIX+oBU38pxkKPxvLcLfIkOV5Ien8ReN78wro7OF5/erwcmortzeFx+iBswlh2Vz6gVne0khocQudGwaO1Ey6A==",
"dependencies": {
- "Microsoft.Win32.SystemEvents": "9.0.8"
+ "Microsoft.Win32.SystemEvents": "7.0.0"
}
},
"System.Globalization": {