From f5d3acbe233bc9603a1b36f129148c400cf2fd3d Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Tue, 3 Jan 2023 23:23:56 -0500 Subject: [PATCH 01/71] Catch General Exception when checking update, and use PeriodicTimer to avoid error to crash the main thread --- Flow.Launcher.Core/Updater.cs | 10 +++++++--- Flow.Launcher/App.xaml.cs | 20 +++++++++----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 91de8298c..3f64b273e 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -33,7 +33,7 @@ namespace Flow.Launcher.Core public async Task UpdateAppAsync(IPublicAPI api, bool silentUpdate = true) { - await UpdateLock.WaitAsync(); + await UpdateLock.WaitAsync().ConfigureAwait(false); try { if (!silentUpdate) @@ -88,9 +88,13 @@ namespace Flow.Launcher.Core UpdateManager.RestartApp(Constant.ApplicationFileName); } } - catch (Exception e) when (e is HttpRequestException or WebException or SocketException || e.InnerException is TimeoutException) + catch (Exception e) { - Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e); + if ((e is HttpRequestException or WebException or SocketException || e.InnerException is TimeoutException)) + Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e); + else + Log.Exception($"|Updater.UpdateApp|Error Occurred", e); + if (!silentUpdate) api.ShowMsg(api.GetTranslation("update_flowlauncher_fail"), api.GetTranslation("update_flowlauncher_check_connection")); diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 43fa0eddb..9df936e76 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.Text; +using System.Threading; using System.Threading.Tasks; using System.Timers; using System.Windows; @@ -84,7 +85,7 @@ namespace Flow.Launcher Current.MainWindow = window; Current.MainWindow.Title = Constant.FlowLauncher; - + HotKeyMapper.Initialize(_mainVM); // happlebao todo temp fix for instance code logic @@ -130,20 +131,17 @@ namespace Flow.Launcher //[Conditional("RELEASE")] private void AutoUpdates() { - Task.Run(async () => + _ = Task.Run(async () => { if (_settings.AutoUpdates) { - // check udpate every 5 hours - var timer = new Timer(1000 * 60 * 60 * 5); - timer.Elapsed += async (s, e) => - { - await _updater.UpdateAppAsync(API); - }; - timer.Start(); - - // check updates on startup + // check update every 5 hours + var timer = new PeriodicTimer(TimeSpan.FromHours(5)); await _updater.UpdateAppAsync(API); + + while (await timer.WaitForNextTickAsync()) + // check updates on startup + await _updater.UpdateAppAsync(API); } }); } From c2137011e8ae13781207b67ddbdc73e8c09bebc0 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 7 Jan 2023 22:15:57 +1100 Subject: [PATCH 02/71] Update comment --- Flow.Launcher/App.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 9df936e76..4ae754fcd 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -88,7 +88,7 @@ namespace Flow.Launcher HotKeyMapper.Initialize(_mainVM); - // happlebao todo temp fix for instance code logic + // todo temp fix for instance code logic // load plugin before change language, because plugin language also needs be changed InternationalizationManager.Instance.Settings = _settings; InternationalizationManager.Instance.ChangeLanguage(_settings.Language); From dfe2c01fb5745381561724e417899c1686e53196 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Sat, 7 Jan 2023 09:14:18 -0600 Subject: [PATCH 03/71] fix spelling --- Flow.Launcher/App.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 4ae754fcd..1d398276d 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -92,7 +92,7 @@ namespace Flow.Launcher // load plugin before change language, because plugin language also needs be changed InternationalizationManager.Instance.Settings = _settings; InternationalizationManager.Instance.ChangeLanguage(_settings.Language); - // main windows needs initialized before theme change because of blur settigns + // main windows needs initialized before theme change because of blur settings ThemeManager.Instance.Settings = _settings; ThemeManager.Instance.ChangeTheme(_settings.Theme); From 8b517954ef905a87b2ea54dd743c06fabffacca9 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Sat, 7 Jan 2023 13:11:43 -0600 Subject: [PATCH 04/71] Try Atomic Save for Setting --- Flow.Launcher.Infrastructure/Helper.cs | 6 +- .../Storage/JsonStorage.cs | 89 +++++++++++-------- .../Storage/PluginJsonStorage.cs | 2 +- 3 files changed, 56 insertions(+), 41 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Helper.cs b/Flow.Launcher.Infrastructure/Helper.cs index faa4c93b5..db575de90 100644 --- a/Flow.Launcher.Infrastructure/Helper.cs +++ b/Flow.Launcher.Infrastructure/Helper.cs @@ -1,4 +1,6 @@ -using System; +#nullable enable + +using System; using System.IO; using System.Runtime.CompilerServices; using System.Text.Json; @@ -16,7 +18,7 @@ namespace Flow.Launcher.Infrastructure /// /// http://www.yinwang.org/blog-cn/2015/11/21/programming-philosophy /// - public static T NonNull(this T obj) + public static T NonNull(this T? obj) { if (obj == null) { diff --git a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs index 0083ccb87..20b2e4e21 100644 --- a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Globalization; using System.IO; using System.Text.Json; @@ -11,62 +12,73 @@ namespace Flow.Launcher.Infrastructure.Storage /// public class JsonStorage where T : new() { - protected T _data; + protected T? Data; // need a new directory name public const string DirectoryName = "Settings"; public const string FileSuffix = ".json"; - public string FilePath { get; set; } - public string DirectoryPath { get; set; } + protected string FilePath { get; init; } = null!; + private string TempFilePath => $"{FilePath}.tmp"; + private string BackupFilePath => $"{FilePath}.bak"; + protected string DirectoryPath { get; init; } = null!; public T Load() { + string? serialized = null; + if (File.Exists(FilePath)) { - var serialized = File.ReadAllText(FilePath); - if (!string.IsNullOrWhiteSpace(serialized)) + serialized = File.ReadAllText(FilePath); + } + + if (!string.IsNullOrEmpty(serialized)) + { + try { - Deserialize(serialized); + Data = JsonSerializer.Deserialize(serialized)?? TryLoadBackup() ?? LoadDefault(); } - else + catch (JsonException) { - LoadDefault(); + Data = TryLoadBackup() ?? LoadDefault(); } } else { - LoadDefault(); + Data = TryLoadBackup() ?? LoadDefault(); } - return _data.NonNull(); + return Data.NonNull(); } - private void Deserialize(string serialized) - { - try - { - _data = JsonSerializer.Deserialize(serialized); - } - catch (JsonException e) - { - LoadDefault(); - Log.Exception($"|JsonStorage.Deserialize|Deserialize error for json <{FilePath}>", e); - } - - if (_data == null) - { - LoadDefault(); - } - } - - private void LoadDefault() + private T LoadDefault() { if (File.Exists(FilePath)) { BackupOriginFile(); } - _data = new T(); - Save(); + return new T(); + } + + private T? TryLoadBackup() + { + if (!File.Exists(BackupFilePath)) + return default; + + try + { + var data = JsonSerializer.Deserialize(File.ReadAllText(BackupFilePath)); + if (data != null) + { + Log.Info($"|JsonStorage.Load|Load backup file {BackupFilePath} successfully"); + File.Replace(BackupFilePath, FilePath, null); + return data; + } + return default; + } + catch (JsonException) + { + return default; + } } private void BackupOriginFile() @@ -82,13 +94,14 @@ namespace Flow.Launcher.Infrastructure.Storage public void Save() { - string serialized = JsonSerializer.Serialize(_data, new JsonSerializerOptions() { WriteIndented = true }); + string serialized = JsonSerializer.Serialize(Data, new JsonSerializerOptions + { + WriteIndented = true + }); - File.WriteAllText(FilePath, serialized); + File.WriteAllText(TempFilePath, serialized); + File.Replace(TempFilePath, FilePath, BackupFilePath); + File.Delete(TempFilePath); } } - - [Obsolete("Deprecated as of Flow Launcher v1.8.0, on 2021.06.21. " + - "This is used only for Everything plugin v1.4.9 or below backwards compatibility")] - public class JsonStrorage : JsonStorage where T : new() { } } diff --git a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs index 923a1a6b5..abe3f55b5 100644 --- a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs @@ -18,7 +18,7 @@ namespace Flow.Launcher.Infrastructure.Storage public PluginJsonStorage(T data) : this() { - _data = data; + Data = data; } } } From 43e38f648c92cc93512cab8ade7ccd5de75dec2b Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Sat, 7 Jan 2023 13:22:17 -0600 Subject: [PATCH 05/71] update expect.txt --- .github/actions/spelling/expect.txt | 110 ++++++++++++++-------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index a91287cc0..612ee3957 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -1,64 +1,64 @@ -crowdin -DWM -workflows -wpf actionkeyword -stackoverflow -Wox -flowlauncher -Fody -stackoverflow -IContext -IShell -IPlugin -appveyor -netflix -youtube -appdata -Prioritise -Segoe -Google -Customise -UWP -uwp -Bokmal -Bokm -uninstallation -uninstalling -voidtools -fullscreen -hotkeys -totalcmd -lnk amazonaws -mscorlib -pythonw +appdata +appref +appref-ms +appveyor +baidu +bak +Bokm +Bokmal +CMD +crowdin +Customise +dlgtext dotnet -winget -jjw24 -wolframalpha -gmail +dpi duckduckgo +DWM +EWX facebook findicon -baidu -pls -websearch -qianlifeng -userdata -srchadmin -EWX -dlgtext -CMD -appref-ms -appref -TSource -runas -dpi -popup -ptr -pluginindicator -TobiasSekan +flowlauncher +Fody +fullscreen +gmail +Google +hotkeys +IContext Img img +IPlugin +IShell +jjw24 +lnk +mscorlib +netflix +pls +pluginindicator +popup +Prioritise +ptr +pythonw +qianlifeng resx +runas +Segoe +srchadmin +stackoverflow +TobiasSekan +totalcmd +TSource +uninstallation +uninstalling +userdata +UWP +uwp +voidtools +websearch +winget +wolframalpha +workflows +Wox +wpf +youtube From 1e256e441816628e6ef479ac6f7d5d79dff8f4d1 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Sat, 7 Jan 2023 13:22:58 -0600 Subject: [PATCH 06/71] Revert "update expect.txt" This reverts commit 43e38f648c92cc93512cab8ade7ccd5de75dec2b. --- .github/actions/spelling/expect.txt | 108 ++++++++++++++-------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 612ee3957..a91287cc0 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -1,64 +1,64 @@ -actionkeyword -amazonaws -appdata -appref -appref-ms -appveyor -baidu -bak -Bokm -Bokmal -CMD crowdin -Customise -dlgtext -dotnet -dpi -duckduckgo DWM -EWX -facebook -findicon +workflows +wpf +actionkeyword +stackoverflow +Wox flowlauncher Fody -fullscreen -gmail -Google -hotkeys -IContext -Img -img -IPlugin -IShell -jjw24 -lnk -mscorlib -netflix -pls -pluginindicator -popup -Prioritise -ptr -pythonw -qianlifeng -resx -runas -Segoe -srchadmin stackoverflow -TobiasSekan -totalcmd -TSource -uninstallation -uninstalling -userdata +IContext +IShell +IPlugin +appveyor +netflix +youtube +appdata +Prioritise +Segoe +Google +Customise UWP uwp +Bokmal +Bokm +uninstallation +uninstalling voidtools -websearch +fullscreen +hotkeys +totalcmd +lnk +amazonaws +mscorlib +pythonw +dotnet winget +jjw24 wolframalpha -workflows -Wox -wpf -youtube +gmail +duckduckgo +facebook +findicon +baidu +pls +websearch +qianlifeng +userdata +srchadmin +EWX +dlgtext +CMD +appref-ms +appref +TSource +runas +dpi +popup +ptr +pluginindicator +TobiasSekan +Img +img +resx From 162add930700059ed901c79b3a66b292c77de491 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Sat, 7 Jan 2023 13:24:19 -0600 Subject: [PATCH 07/71] update expect.txt --- .github/actions/spelling/expect.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index a91287cc0..ba6faec9a 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -62,3 +62,5 @@ TobiasSekan Img img resx +bak +tmp From 1defb6a4172e9fd6dd0d8b0cb6b4fc3896eaa312 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Mon, 9 Jan 2023 18:02:50 +0800 Subject: [PATCH 08/71] Refactor HotkeyModel --- .../Hotkey/HotkeyModel.cs | 66 ++++++++++++++----- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs index 5bd97714c..e4a020cb7 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs @@ -11,10 +11,21 @@ namespace Flow.Launcher.Infrastructure.Hotkey public bool Shift { get; set; } public bool Win { get; set; } public bool Ctrl { get; set; } - public Key CharKey { get; set; } + private Key charKey = Key.None; + public Key CharKey + { + get => charKey; + set + { + if (ValidateHotkey(value)) + { + charKey = value; + } + } + } - Dictionary specialSymbolDictionary = new Dictionary + private static readonly Dictionary specialSymbolDictionary = new Dictionary { {Key.Space, "Space"}, {Key.Oem3, "~"} @@ -86,7 +97,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey Ctrl = true; keys.Remove("Ctrl"); } - if (keys.Count > 0) + if (keys.Count == 1) { string charKey = keys[0]; KeyValuePair? specialSymbolPair = specialSymbolDictionary.FirstOrDefault(pair => pair.Value == charKey); @@ -110,36 +121,61 @@ namespace Flow.Launcher.Infrastructure.Hotkey public override string ToString() { - string text = string.Empty; + List keys = new List(); if (Ctrl) { - text += "Ctrl + "; + keys.Add("Ctrl"); } if (Alt) { - text += "Alt + "; + keys.Add("Alt"); } if (Shift) { - text += "Shift + "; + keys.Add("Shift"); } if (Win) { - text += "Win + "; + keys.Add("Win"); } if (CharKey != Key.None) { - text += specialSymbolDictionary.ContainsKey(CharKey) + keys.Add(specialSymbolDictionary.ContainsKey(CharKey) ? specialSymbolDictionary[CharKey] - : CharKey.ToString(); - } - else if (!string.IsNullOrEmpty(text)) - { - text = text.Remove(text.Length - 3); + : CharKey.ToString()); } + return string.Join(" + ", keys); + } - return text; + private static bool ValidateHotkey(Key key) + { + HashSet invalidKeys = new() + { + Key.LeftAlt, Key.RightAlt, + Key.LeftCtrl, Key.RightCtrl, + Key.LeftShift, Key.RightShift, + Key.LWin, Key.RWin, + }; + + return !invalidKeys.Contains(key); + } + + public override bool Equals(object obj) + { + if (obj is HotkeyModel other) + { + return ModifierKeys == other.ModifierKeys && CharKey == other.charKey; + } + else + { + return false; + } + } + + public override int GetHashCode() + { + return this.ToString().GetHashCode(); } } } From 10fa2f7beb8d01a35990ba6c156db2c263e11acd Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Mon, 9 Jan 2023 21:50:29 +0800 Subject: [PATCH 09/71] Validate hotkey --- Flow.Launcher/HotkeyControl.xaml.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index d746c8fd2..ffa73da15 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -9,7 +9,6 @@ using Flow.Launcher.Helper; using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Plugin; using System.Threading; -using System.Windows.Interop; namespace Flow.Launcher { @@ -79,7 +78,7 @@ namespace Flow.Launcher if (triggerValidate) { - CurrentHotkeyAvailable = CheckHotkeyAvailability(); + CurrentHotkeyAvailable = CurrentHotkey.CharKey != Key.None && CheckHotkeyAvailability(); if (!CurrentHotkeyAvailable) { tbMsg.Foreground = new SolidColorBrush(Colors.Red); From ff79651fb2bd1b7ddde8345d05da92938434e9aa Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Mon, 9 Jan 2023 22:08:27 +0800 Subject: [PATCH 10/71] Use Equals() for comparison --- Flow.Launcher/HotkeyControl.xaml.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index ffa73da15..7d2da76da 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -54,9 +54,7 @@ namespace Flow.Launcher specialKeyState.CtrlPressed, key); - var hotkeyString = hotkeyModel.ToString(); - - if (hotkeyString == tbHotkey.Text) + if (hotkeyModel.Equals(CurrentHotkey)) { return; } From cd056f6355d945dd367807f594c7e59b1041a14d Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Mon, 9 Jan 2023 22:09:39 +0800 Subject: [PATCH 11/71] Use overloaded version --- Flow.Launcher/Resources/Pages/WelcomePage2.xaml.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/Resources/Pages/WelcomePage2.xaml.cs b/Flow.Launcher/Resources/Pages/WelcomePage2.xaml.cs index 4f8d65378..e89a7dd03 100644 --- a/Flow.Launcher/Resources/Pages/WelcomePage2.xaml.cs +++ b/Flow.Launcher/Resources/Pages/WelcomePage2.xaml.cs @@ -27,7 +27,7 @@ namespace Flow.Launcher.Resources.Pages tbMsgTextOriginal = HotkeyControl.tbMsg.Text; tbMsgForegroundColorOriginal = HotkeyControl.tbMsg.Foreground; - HotkeyControl.SetHotkeyAsync(new Infrastructure.Hotkey.HotkeyModel(Settings.Hotkey), false); + HotkeyControl.SetHotkeyAsync(Settings.Hotkey, false); } private void HotkeyControl_OnGotFocus(object sender, RoutedEventArgs args) { @@ -49,4 +49,4 @@ namespace Flow.Launcher.Resources.Pages HotkeyControl.tbMsg.Foreground = tbMsgForegroundColorOriginal; } } -} \ No newline at end of file +} From 8208af4d1a843451bca97653feb35fdaffe12d81 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Tue, 10 Jan 2023 14:18:12 +0800 Subject: [PATCH 12/71] Always show/search desc in result if enabled --- .../Programs/UWP.cs | 16 ++++---- .../Programs/Win32.cs | 40 ++++++------------- 2 files changed, 19 insertions(+), 37 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs index 2f84fdbf5..023eea042 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs @@ -378,15 +378,10 @@ namespace Flow.Launcher.Plugin.Program.Programs MatchResult matchResult; // We suppose Name won't be null - if (!Main._settings.EnableDescription || Description == null || Name.StartsWith(Description)) + if (!Main._settings.EnableDescription || string.IsNullOrWhiteSpace(Description) || Name.Equals(Description)) { title = Name; - matchResult = StringMatcher.FuzzySearch(query, title); - } - else if (Description.StartsWith(Name)) - { - title = Description; - matchResult = StringMatcher.FuzzySearch(query, Description); + matchResult = StringMatcher.FuzzySearch(query, Name); } else { @@ -401,10 +396,13 @@ namespace Flow.Launcher.Plugin.Program.Programs } matchResult = descriptionMatch; } - else matchResult = nameMatch; + else + { + matchResult = nameMatch; + } } - if (!matchResult.Success) + if (!matchResult.IsSearchPrecisionScoreMet()) return null; var result = new Result diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index dec43530e..f678b6bc8 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -90,44 +90,28 @@ namespace Flow.Launcher.Plugin.Program.Programs bool useLocalizedName = !string.IsNullOrEmpty(LocalizedName) && !Name.Equals(LocalizedName); string resultName = useLocalizedName ? LocalizedName : Name; - if (!Main._settings.EnableDescription) + if (!Main._settings.EnableDescription || string.IsNullOrWhiteSpace(Description) || resultName.Equals(Description)) { title = resultName; matchResult = StringMatcher.FuzzySearch(query, resultName); } else { - if (string.IsNullOrEmpty(Description) || resultName.StartsWith(Description)) + // Search in both + title = $"{resultName}: {Description}"; + var nameMatch = StringMatcher.FuzzySearch(query, resultName); + var descriptionMatch = StringMatcher.FuzzySearch(query, Description); + if (descriptionMatch.Score > nameMatch.Score) { - // Description is invalid or included in resultName - // Description is always localized, so Name.StartsWith(Description) is generally useless - title = resultName; - matchResult = StringMatcher.FuzzySearch(query, resultName); - } - else if (Description.StartsWith(resultName)) - { - // resultName included in Description - title = Description; - matchResult = StringMatcher.FuzzySearch(query, Description); + for (int i = 0; i < descriptionMatch.MatchData.Count; i++) + { + descriptionMatch.MatchData[i] += resultName.Length + 2; // 2 is ": " + } + matchResult = descriptionMatch; } else { - // Search in both - title = $"{resultName}: {Description}"; - var nameMatch = StringMatcher.FuzzySearch(query, resultName); - var descriptionMatch = StringMatcher.FuzzySearch(query, Description); - if (descriptionMatch.Score > nameMatch.Score) - { - for (int i = 0; i < descriptionMatch.MatchData.Count; i++) - { - descriptionMatch.MatchData[i] += resultName.Length + 2; // 2 is ": " - } - matchResult = descriptionMatch; - } - else - { - matchResult = nameMatch; - } + matchResult = nameMatch; } } From 0c58c2b4f93569a56bd5a6cfa493af749958a3dd Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Tue, 10 Jan 2023 15:01:30 +0800 Subject: [PATCH 13/71] Ban single character key --- Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs index e4a020cb7..54115f129 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Windows.Input; +using System.Windows.Navigation; namespace Flow.Launcher.Infrastructure.Hotkey { @@ -148,7 +149,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey return string.Join(" + ", keys); } - private static bool ValidateHotkey(Key key) + private bool ValidateHotkey(Key key) { HashSet invalidKeys = new() { @@ -158,7 +159,15 @@ namespace Flow.Launcher.Infrastructure.Hotkey Key.LWin, Key.RWin, }; - return !invalidKeys.Contains(key); + if (invalidKeys.Contains(key)) + { + return false; + } + if (ModifierKeys == ModifierKeys.None) + { + return key >= Key.F1 && key <= Key.F24; + } + return true; } public override bool Equals(object obj) From f6e2fe3525a28a38119cc7369c80b6a23b01eba1 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 11 Jan 2023 12:14:18 +0800 Subject: [PATCH 14/71] Reset message when got focus --- Flow.Launcher/HotkeyControl.xaml | 1 + Flow.Launcher/HotkeyControl.xaml.cs | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher/HotkeyControl.xaml b/Flow.Launcher/HotkeyControl.xaml index 5a593d20a..acf4a21ec 100644 --- a/Flow.Launcher/HotkeyControl.xaml +++ b/Flow.Launcher/HotkeyControl.xaml @@ -48,6 +48,7 @@ Margin="0,0,18,0" VerticalContentAlignment="Center" input:InputMethod.IsInputMethodEnabled="False" + GotFocus="tbHotkey_GotFocus" LostFocus="tbHotkey_LostFocus" PreviewKeyDown="TbHotkey_OnPreviewKeyDown" TabIndex="100" /> diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index 7d2da76da..b1340cddc 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -14,10 +14,6 @@ namespace Flow.Launcher { public partial class HotkeyControl : UserControl { - private Brush tbMsgForegroundColorOriginal; - - private string tbMsgTextOriginal; - public HotkeyModel CurrentHotkey { get; private set; } public bool CurrentHotkeyAvailable { get; private set; } @@ -28,8 +24,6 @@ namespace Flow.Launcher public HotkeyControl() { InitializeComponent(); - tbMsgTextOriginal = tbMsg.Text; - tbMsgForegroundColorOriginal = tbMsg.Foreground; } private CancellationTokenSource hotkeyUpdateSource; @@ -110,7 +104,17 @@ namespace Flow.Launcher private void tbHotkey_LostFocus(object sender, RoutedEventArgs e) { - tbMsg.Text = tbMsgTextOriginal; + + } + + private void tbHotkey_GotFocus(object sender, RoutedEventArgs e) + { + ResetMessage(); + } + + private void ResetMessage() + { + tbMsg.Text = InternationalizationManager.Instance.GetTranslation("flowlauncherPressHotkey"); tbMsg.SetResourceReference(TextBox.ForegroundProperty, "Color05B"); } } From a399d24c1e06c67703c57932c2a37b76c24bebaf Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 11 Jan 2023 14:03:44 +0800 Subject: [PATCH 15/71] Extract set message logic --- Flow.Launcher/HotkeyControl.xaml.cs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index b1340cddc..7fac47e4d 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -70,18 +70,8 @@ namespace Flow.Launcher if (triggerValidate) { - CurrentHotkeyAvailable = CurrentHotkey.CharKey != Key.None && CheckHotkeyAvailability(); - if (!CurrentHotkeyAvailable) - { - tbMsg.Foreground = new SolidColorBrush(Colors.Red); - tbMsg.Text = InternationalizationManager.Instance.GetTranslation("hotkeyUnavailable"); - } - else - { - tbMsg.Foreground = new SolidColorBrush(Colors.Green); - tbMsg.Text = InternationalizationManager.Instance.GetTranslation("success"); - } - tbMsg.Visibility = Visibility.Visible; + bool hotkeyAvailable = keyModel.CharKey != Key.None && CheckHotkeyAvailability(keyModel); + SetMessage(hotkeyAvailable); OnHotkeyChanged(); var token = hotkeyUpdateSource.Token; @@ -117,5 +107,20 @@ namespace Flow.Launcher tbMsg.Text = InternationalizationManager.Instance.GetTranslation("flowlauncherPressHotkey"); tbMsg.SetResourceReference(TextBox.ForegroundProperty, "Color05B"); } + + private void SetMessage(bool hotkeyAvailable) + { + if (!hotkeyAvailable) + { + tbMsg.Foreground = new SolidColorBrush(Colors.Red); + tbMsg.Text = InternationalizationManager.Instance.GetTranslation("hotkeyUnavailable"); + } + else + { + tbMsg.Foreground = new SolidColorBrush(Colors.Green); + tbMsg.Text = InternationalizationManager.Instance.GetTranslation("success"); + } + tbMsg.Visibility = Visibility.Visible; + } } } From 72f8b9e052ddf14d615fd1287e0d0c2685fadc5e Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 11 Jan 2023 16:11:34 +0800 Subject: [PATCH 16/71] Refactor HotkeyModel validation logic --- .../Hotkey/HotkeyModel.cs | 51 ++++++++----------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs index 54115f129..0908a404b 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs @@ -13,18 +13,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey public bool Win { get; set; } public bool Ctrl { get; set; } - private Key charKey = Key.None; - public Key CharKey - { - get => charKey; - set - { - if (ValidateHotkey(value)) - { - charKey = value; - } - } - } + public Key CharKey { get; set; } = Key.None; private static readonly Dictionary specialSymbolDictionary = new Dictionary { @@ -149,32 +138,36 @@ namespace Flow.Launcher.Infrastructure.Hotkey return string.Join(" + ", keys); } - private bool ValidateHotkey(Key key) + public bool Validate() { - HashSet invalidKeys = new() + switch (CharKey) { - Key.LeftAlt, Key.RightAlt, - Key.LeftCtrl, Key.RightCtrl, - Key.LeftShift, Key.RightShift, - Key.LWin, Key.RWin, - }; - - if (invalidKeys.Contains(key)) - { - return false; + case Key.LeftAlt: + case Key.RightAlt: + case Key.LeftCtrl: + case Key.RightCtrl: + case Key.LeftShift: + case Key.RightShift: + case Key.LWin: + case Key.RWin: + return false; + default: + if (ModifierKeys == ModifierKeys.None) + { + return CharKey >= Key.F1 && CharKey <= Key.F24; + } + else + { + return CharKey != Key.None; + } } - if (ModifierKeys == ModifierKeys.None) - { - return key >= Key.F1 && key <= Key.F24; - } - return true; } public override bool Equals(object obj) { if (obj is HotkeyModel other) { - return ModifierKeys == other.ModifierKeys && CharKey == other.charKey; + return ModifierKeys == other.ModifierKeys && CharKey == other.CharKey; } else { From c03a0b031eb8a1105f6329e3a38eb375eff84fdb Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 11 Jan 2023 16:13:39 +0800 Subject: [PATCH 17/71] Validate hotkey before setting --- Flow.Launcher/HotkeyControl.xaml.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index 7fac47e4d..e6d482900 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -70,7 +70,7 @@ namespace Flow.Launcher if (triggerValidate) { - bool hotkeyAvailable = keyModel.CharKey != Key.None && CheckHotkeyAvailability(keyModel); + bool hotkeyAvailable = CheckHotkeyAvailability(keyModel); SetMessage(hotkeyAvailable); OnHotkeyChanged(); @@ -88,7 +88,7 @@ namespace Flow.Launcher return SetHotkeyAsync(new HotkeyModel(keyStr), triggerValidate); } - private bool CheckHotkeyAvailability() => HotKeyMapper.CheckAvailability(CurrentHotkey); + private static bool CheckHotkeyAvailability(HotkeyModel hotkey) => hotkey.Validate() && HotKeyMapper.CheckAvailability(hotkey); public new bool IsFocused => tbHotkey.IsFocused; From 3f6ab55ae7904daabceee383bc0e1fbf065c2f32 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 11 Jan 2023 16:14:50 +0800 Subject: [PATCH 18/71] Use properties for hashcode --- Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs index 0908a404b..e1d29fb81 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs @@ -177,7 +177,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey public override int GetHashCode() { - return this.ToString().GetHashCode(); + return HashCode.Combine(ModifierKeys, CharKey); } } } From 28c5031bfb63967fe8697e3b6afe06241b12f981 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 11 Jan 2023 16:22:19 +0800 Subject: [PATCH 19/71] Maintain focus when hotkey invalid --- Flow.Launcher/HotkeyControl.xaml.cs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index e6d482900..804d1d4cb 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -63,14 +63,13 @@ namespace Flow.Launcher public async Task SetHotkeyAsync(HotkeyModel keyModel, bool triggerValidate = true) { - CurrentHotkey = keyModel; - - tbHotkey.Text = CurrentHotkey.ToString(); + tbHotkey.Text = keyModel.ToString(); tbHotkey.Select(tbHotkey.Text.Length, 0); if (triggerValidate) { bool hotkeyAvailable = CheckHotkeyAvailability(keyModel); + CurrentHotkeyAvailable = hotkeyAvailable; SetMessage(hotkeyAvailable); OnHotkeyChanged(); @@ -78,8 +77,18 @@ namespace Flow.Launcher await Task.Delay(500, token); if (token.IsCancellationRequested) return; - FocusManager.SetFocusedElement(FocusManager.GetFocusScope(this), null); - Keyboard.ClearFocus(); + + if (CurrentHotkeyAvailable) + { + CurrentHotkey = keyModel; + // To trigger LostFocus + FocusManager.SetFocusedElement(FocusManager.GetFocusScope(this), null); + Keyboard.ClearFocus(); + } + } + else + { + CurrentHotkey = keyModel; } } @@ -94,7 +103,7 @@ namespace Flow.Launcher private void tbHotkey_LostFocus(object sender, RoutedEventArgs e) { - + } private void tbHotkey_GotFocus(object sender, RoutedEventArgs e) From 835370af34f6687fe1b1ace505ca9a97c7dd2a15 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 11 Jan 2023 19:28:42 +0800 Subject: [PATCH 20/71] Set text to current hotkey when lost focus --- Flow.Launcher/HotkeyControl.xaml.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index 804d1d4cb..15feae6cc 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -103,7 +103,8 @@ namespace Flow.Launcher private void tbHotkey_LostFocus(object sender, RoutedEventArgs e) { - + tbHotkey.Text = CurrentHotkey.ToString(); + tbHotkey.Select(tbHotkey.Text.Length, 0); } private void tbHotkey_GotFocus(object sender, RoutedEventArgs e) From 203705bda1fc31ebdd30858274d8ae188e0f496c Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 11 Jan 2023 20:08:13 +0800 Subject: [PATCH 21/71] Use compound assignment --- Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs index e1d29fb81..61415dcb6 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs @@ -28,19 +28,19 @@ namespace Flow.Launcher.Infrastructure.Hotkey ModifierKeys modifierKeys = ModifierKeys.None; if (Alt) { - modifierKeys = ModifierKeys.Alt; + modifierKeys |= ModifierKeys.Alt; } if (Shift) { - modifierKeys = modifierKeys | ModifierKeys.Shift; + modifierKeys |= ModifierKeys.Shift; } if (Win) { - modifierKeys = modifierKeys | ModifierKeys.Windows; + modifierKeys |= ModifierKeys.Windows; } if (Ctrl) { - modifierKeys = modifierKeys | ModifierKeys.Control; + modifierKeys |= ModifierKeys.Control; } return modifierKeys; } From 3a8162be49db1af2c2043d9f76582f10aa19766d Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 12 Jan 2023 00:27:19 +0800 Subject: [PATCH 22/71] Ban alphanumeric keys --- Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs index 61415dcb6..b92bc0207 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs @@ -154,7 +154,9 @@ namespace Flow.Launcher.Infrastructure.Hotkey default: if (ModifierKeys == ModifierKeys.None) { - return CharKey >= Key.F1 && CharKey <= Key.F24; + return !((CharKey >= Key.A && CharKey <= Key.Z) || + (CharKey >= Key.D0 && CharKey <= Key.D9) || + (CharKey >= Key.NumPad0 && CharKey <= Key.NumPad9)); } else { From 072113a127979f9403ae4938eb15dd11a8aa7228 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 12 Jan 2023 17:06:23 +0800 Subject: [PATCH 23/71] Expand builtin shortcuts when needed --- Flow.Launcher/ViewModel/MainViewModel.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 71b0d0237..705f6aad0 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -841,15 +841,20 @@ namespace Flow.Launcher.ViewModel queryBuilder.Replace('@' + shortcut.Key, shortcut.Expand()); } + string customExpanded = queryBuilder.ToString(); + Application.Current.Dispatcher.Invoke(() => { foreach (var shortcut in builtInShortcuts) { try { - var expansion = shortcut.Expand(); - queryBuilder.Replace(shortcut.Key, expansion); - queryBuilderTmp.Replace(shortcut.Key, expansion); + if (customExpanded.Contains(shortcut.Key)) + { + var expansion = shortcut.Expand(); + queryBuilder.Replace(shortcut.Key, expansion); + queryBuilderTmp.Replace(shortcut.Key, expansion); + } } catch (Exception e) { From f07cff7742030c7ec05e8eb9083dff3b2fbaaa37 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Thu, 12 Jan 2023 15:29:58 -0600 Subject: [PATCH 24/71] fix explorer setting UseLocationAsWorkingDir --- .../Search/ResultManager.cs | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs index 2676b27b2..38d909e6c 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs @@ -27,8 +27,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search var usePathSearchActionKeyword = Settings.PathSearchKeywordEnabled && !Settings.SearchActionKeywordEnabled; - var pathSearchActionKeyword = Settings.PathSearchActionKeyword == Query.GlobalPluginWildcardSign - ? string.Empty + var pathSearchActionKeyword = Settings.PathSearchActionKeyword == Query.GlobalPluginWildcardSign + ? string.Empty : $"{Settings.PathSearchActionKeyword} "; var searchActionKeyword = Settings.SearchActionKeyword == Query.GlobalPluginWildcardSign @@ -36,7 +36,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search : $"{Settings.SearchActionKeyword} "; var keyword = usePathSearchActionKeyword ? pathSearchActionKeyword : searchActionKeyword; - + var formatted_path = path; if (type == ResultType.Folder) @@ -49,8 +49,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search public static string GetAutoCompleteText(string title, Query query, string path, ResultType resultType) { return !Settings.PathSearchKeywordEnabled && !Settings.SearchActionKeywordEnabled - ? $"{query.ActionKeyword} {title}" // Only Quick Access action keyword is used in this scenario - : GetPathWithActionKeyword(path, resultType, query.ActionKeyword); + ? $"{query.ActionKeyword} {title}" // Only Quick Access action keyword is used in this scenario + : GetPathWithActionKeyword(path, resultType, query.ActionKeyword); } public static Result CreateResult(Query query, SearchResult result) @@ -215,9 +215,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal static Result CreateFileResult(string filePath, Query query, int score = 0, bool windowsIndexed = false) { - Result.PreviewInfo preview = IsMedia(Path.GetExtension(filePath)) ? new Result.PreviewInfo { - IsMedia = true, - PreviewImagePath = filePath, + Result.PreviewInfo preview = IsMedia(Path.GetExtension(filePath)) ? new Result.PreviewInfo + { + IsMedia = true, PreviewImagePath = filePath, } : Result.PreviewInfo.Default; var title = Path.GetFileName(filePath); @@ -246,6 +246,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search { FileName = filePath, UseShellExecute = true, + WorkingDirectory = Settings.UseLocationAsWorkingDir ? Path.GetDirectoryName(filePath) : string.Empty, Verb = "runas", }); } @@ -286,8 +287,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search public static bool IsMedia(string extension) { if (string.IsNullOrEmpty(extension)) - { - return false; + { + return false; } else { @@ -295,7 +296,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search } } - public static readonly string[] MediaExtensions = { ".jpg", ".png", ".avi", ".mkv", ".bmp", ".gif", ".wmv", ".mp3", ".flac", ".mp4" }; + public static readonly string[] MediaExtensions = + { + ".jpg", ".png", ".avi", ".mkv", ".bmp", ".gif", ".wmv", ".mp3", ".flac", ".mp4" + }; } public enum ResultType From a7afa171e0ae6e90945430b4e51f283b7648e13a Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Thu, 12 Jan 2023 15:52:43 -0600 Subject: [PATCH 25/71] catch exception when killing unused jsonrpc process --- Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs | 183 +++++++++++---------- 1 file changed, 95 insertions(+), 88 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs b/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs index 28d57501b..f3b2eed87 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs @@ -259,9 +259,16 @@ namespace Flow.Launcher.Core.Plugin await using var registeredEvent = token.Register(() => { - if (!process.HasExited) - process.Kill(); - sourceBuffer.Dispose(); + try + { + if (!process.HasExited) + process.Kill(); + sourceBuffer.Dispose(); + } + catch (Exception e) + { + Log.Exception("|JsonRPCPlugin.ExecuteAsync|Exception when kill process", e); + } }); try @@ -288,7 +295,7 @@ namespace Flow.Launcher.Core.Plugin } sourceBuffer.Seek(0, SeekOrigin.Begin); - + return sourceBuffer; } @@ -376,7 +383,8 @@ namespace Flow.Launcher.Core.Plugin sep.SetResourceReference(Separator.BackgroundProperty, "Color03B"); /* for theme change */ var panel = new StackPanel { - Orientation = Orientation.Vertical, VerticalAlignment = VerticalAlignment.Center, + Orientation = Orientation.Vertical, + VerticalAlignment = VerticalAlignment.Center, Margin = settingLabelPanelMargin }; RowDefinition gridRow = new RowDefinition(); @@ -390,8 +398,10 @@ namespace Flow.Launcher.Core.Plugin }; var desc = new TextBlock() { - Text = attribute.Description, FontSize = 12, - VerticalAlignment = VerticalAlignment.Center,Margin = settingDescMargin, + Text = attribute.Description, + FontSize = 12, + VerticalAlignment = VerticalAlignment.Center, + Margin = settingDescMargin, TextWrapping = TextWrapping.WrapWithOverflow }; desc.SetResourceReference(TextBlock.ForegroundProperty, "Color04B"); @@ -405,7 +415,7 @@ namespace Flow.Launcher.Core.Plugin panel.Children.Add(name); panel.Children.Add(desc); } - + Grid.SetColumn(panel, 0); Grid.SetRow(panel, rowCount); @@ -420,20 +430,20 @@ namespace Flow.Launcher.Core.Plugin { Text = attribute.Description.Replace("\\r\\n", "\r\n"), Margin = settingTextBlockMargin, - Padding = new Thickness(0,0,0,0), + Padding = new Thickness(0, 0, 0, 0), HorizontalAlignment = System.Windows.HorizontalAlignment.Left, TextAlignment = TextAlignment.Left, TextWrapping = TextWrapping.Wrap }; - Grid.SetColumn(contentControl, 0); - Grid.SetColumnSpan(contentControl, 2); - Grid.SetRow(contentControl, rowCount); - if (rowCount != 0) - mainPanel.Children.Add(sep); - Grid.SetRow(sep, rowCount); - Grid.SetColumn(sep, 0); - Grid.SetColumnSpan(sep, 2); - break; + Grid.SetColumn(contentControl, 0); + Grid.SetColumnSpan(contentControl, 2); + Grid.SetRow(contentControl, rowCount); + if (rowCount != 0) + mainPanel.Children.Add(sep); + Grid.SetRow(sep, rowCount); + Grid.SetColumn(sep, 0); + Grid.SetColumnSpan(sep, 2); + break; } case "input": { @@ -449,50 +459,49 @@ namespace Flow.Launcher.Core.Plugin Settings[attribute.Name] = textBox.Text; }; contentControl = textBox; - Grid.SetColumn(contentControl, 1); - Grid.SetRow(contentControl, rowCount); - if (rowCount != 0) - mainPanel.Children.Add(sep); - Grid.SetRow(sep, rowCount); - Grid.SetColumn(sep, 0); - Grid.SetColumnSpan(sep, 2); - break; + Grid.SetColumn(contentControl, 1); + Grid.SetRow(contentControl, rowCount); + if (rowCount != 0) + mainPanel.Children.Add(sep); + Grid.SetRow(sep, rowCount); + Grid.SetColumn(sep, 0); + Grid.SetColumnSpan(sep, 2); + break; } case "inputWithFileBtn": + { + var textBox = new TextBox() { - var textBox = new TextBox() - { - Margin = new Thickness(10, 0, 0, 0), - Text = Settings[attribute.Name] as string ?? string.Empty, - HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch, - ToolTip = attribute.Description - }; - textBox.TextChanged += (_, _) => - { - Settings[attribute.Name] = textBox.Text; - }; - var Btn = new System.Windows.Controls.Button() - { - Margin = new Thickness(10,0,0,0), - Content = "Browse" - }; - var dockPanel = new DockPanel() - { - Margin = settingControlMargin - }; - DockPanel.SetDock(Btn, Dock.Right); - dockPanel.Children.Add(Btn); - dockPanel.Children.Add(textBox); - contentControl = dockPanel; - Grid.SetColumn(contentControl, 1); - Grid.SetRow(contentControl, rowCount); - if (rowCount != 0) - mainPanel.Children.Add(sep); - Grid.SetRow(sep, rowCount); - Grid.SetColumn(sep, 0); - Grid.SetColumnSpan(sep, 2); - break; - } + Margin = new Thickness(10, 0, 0, 0), + Text = Settings[attribute.Name] as string ?? string.Empty, + HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch, + ToolTip = attribute.Description + }; + textBox.TextChanged += (_, _) => + { + Settings[attribute.Name] = textBox.Text; + }; + var Btn = new System.Windows.Controls.Button() + { + Margin = new Thickness(10, 0, 0, 0), Content = "Browse" + }; + var dockPanel = new DockPanel() + { + Margin = settingControlMargin + }; + DockPanel.SetDock(Btn, Dock.Right); + dockPanel.Children.Add(Btn); + dockPanel.Children.Add(textBox); + contentControl = dockPanel; + Grid.SetColumn(contentControl, 1); + Grid.SetRow(contentControl, rowCount); + if (rowCount != 0) + mainPanel.Children.Add(sep); + Grid.SetRow(sep, rowCount); + Grid.SetColumn(sep, 0); + Grid.SetColumnSpan(sep, 2); + break; + } case "textarea": { var textBox = new TextBox() @@ -511,14 +520,14 @@ namespace Flow.Launcher.Core.Plugin Settings[attribute.Name] = ((TextBox)sender).Text; }; contentControl = textBox; - Grid.SetColumn(contentControl, 1); - Grid.SetRow(contentControl, rowCount); - if (rowCount != 0) - mainPanel.Children.Add(sep); - Grid.SetRow(sep, rowCount); - Grid.SetColumn(sep, 0); - Grid.SetColumnSpan(sep, 2); - break; + Grid.SetColumn(contentControl, 1); + Grid.SetRow(contentControl, rowCount); + if (rowCount != 0) + mainPanel.Children.Add(sep); + Grid.SetRow(sep, rowCount); + Grid.SetColumn(sep, 0); + Grid.SetColumnSpan(sep, 2); + break; } case "passwordBox": { @@ -535,14 +544,14 @@ namespace Flow.Launcher.Core.Plugin Settings[attribute.Name] = ((PasswordBox)sender).Password; }; contentControl = passwordBox; - Grid.SetColumn(contentControl, 1); - Grid.SetRow(contentControl, rowCount); - if (rowCount != 0) - mainPanel.Children.Add(sep); - Grid.SetRow(sep, rowCount); - Grid.SetColumn(sep, 0); - Grid.SetColumnSpan(sep, 2); - break; + Grid.SetColumn(contentControl, 1); + Grid.SetRow(contentControl, rowCount); + if (rowCount != 0) + mainPanel.Children.Add(sep); + Grid.SetRow(sep, rowCount); + Grid.SetColumn(sep, 0); + Grid.SetColumnSpan(sep, 2); + break; } case "dropdown": { @@ -559,14 +568,14 @@ namespace Flow.Launcher.Core.Plugin Settings[attribute.Name] = (string)((System.Windows.Controls.ComboBox)sender).SelectedItem; }; contentControl = comboBox; - Grid.SetColumn(contentControl, 1); - Grid.SetRow(contentControl, rowCount); - if (rowCount != 0) - mainPanel.Children.Add(sep); - Grid.SetRow(sep, rowCount); - Grid.SetColumn(sep, 0); - Grid.SetColumnSpan(sep, 2); - break; + Grid.SetColumn(contentControl, 1); + Grid.SetRow(contentControl, rowCount); + if (rowCount != 0) + mainPanel.Children.Add(sep); + Grid.SetRow(sep, rowCount); + Grid.SetColumn(sep, 0); + Grid.SetColumnSpan(sep, 2); + break; } case "checkbox": var checkBox = new CheckBox @@ -592,13 +601,11 @@ namespace Flow.Launcher.Core.Plugin case "hyperlink": var hyperlink = new Hyperlink { - ToolTip = attribute.Description, - NavigateUri = attribute.url + ToolTip = attribute.Description, NavigateUri = attribute.url }; var linkbtn = new System.Windows.Controls.Button { - HorizontalAlignment = System.Windows.HorizontalAlignment.Right, - Margin = settingControlMargin + HorizontalAlignment = System.Windows.HorizontalAlignment.Right, Margin = settingControlMargin }; linkbtn.Content = attribute.urlLabel; @@ -619,7 +626,7 @@ namespace Flow.Launcher.Core.Plugin mainPanel.Children.Add(panel); mainPanel.Children.Add(contentControl); rowCount++; - + } return settingWindow; } From ce8c3f92881ff93fadae0b827813f6c83cdadcbd Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 13 Jan 2023 15:12:45 +0800 Subject: [PATCH 26/71] Fix typo --- Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs | 2 +- .../Search/DirectoryInfo/DirectoryInfoSearch.cs | 6 +++--- .../Search/QuickAccessLinks/AccessLink.cs | 2 +- .../Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs index 2918cb61f..2174aeee6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs @@ -32,7 +32,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal const string DefaultContentSearchActionKeyword = "doc:"; - internal const char DirectorySeperator = '\\'; + internal const char DirectorySeparator = '\\'; internal const string WindowsIndexingOptions = "srchadmin.dll"; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs index df27c3dfa..9fd495f49 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs @@ -15,7 +15,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo var criteria = ConstructSearchCriteria(search); if (search.LastIndexOf(Constants.AllFilesFolderSearchWildcard) > - search.LastIndexOf(Constants.DirectorySeperator)) + search.LastIndexOf(Constants.DirectorySeparator)) return DirectorySearch(new EnumerationOptions { RecurseSubdirectories = true @@ -29,9 +29,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo { string incompleteName = ""; - if (!search.EndsWith(Constants.DirectorySeperator)) + if (!search.EndsWith(Constants.DirectorySeparator)) { - var indexOfSeparator = search.LastIndexOf(Constants.DirectorySeperator); + var indexOfSeparator = search.LastIndexOf(Constants.DirectorySeparator); incompleteName = search[(indexOfSeparator + 1)..].ToLower(); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/QuickAccessLinks/AccessLink.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/QuickAccessLinks/AccessLink.cs index 0e4465b45..1975211f9 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/QuickAccessLinks/AccessLink.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/QuickAccessLinks/AccessLink.cs @@ -15,7 +15,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks { get { - var path = Path.EndsWith(Constants.DirectorySeperator) ? Path[0..^1] : Path; + var path = Path.EndsWith(Constants.DirectorySeparator) ? Path[0..^1] : Path; if (path.EndsWith(':')) return path[0..^1] + " Drive"; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs index 38d909e6c..62ad71608 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs @@ -40,8 +40,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search var formatted_path = path; if (type == ResultType.Folder) - // the seperator is needed so when navigating the folder structure contents of the folder are listed - formatted_path = path.EndsWith(Constants.DirectorySeperator) ? path : path + Constants.DirectorySeperator; + // the separator is needed so when navigating the folder structure contents of the folder are listed + formatted_path = path.EndsWith(Constants.DirectorySeparator) ? path : path + Constants.DirectorySeparator; return $"{keyword}{formatted_path}"; } @@ -187,9 +187,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal static Result CreateOpenCurrentFolderResult(string path, string actionKeyword, bool windowsIndexed = false) { - // Path passed from PathSearchAsync ends with Constants.DirectorySeperator ('\'), need to remove the seperator + // Path passed from PathSearchAsync ends with Constants.DirectorySeparator ('\'), need to remove the separator // so it's consistent with folder results returned by index search which does not end with one - var folderPath = path.TrimEnd(Constants.DirectorySeperator); + var folderPath = path.TrimEnd(Constants.DirectorySeparator); return new Result { From 457e4138b4924b322249f9e21b3242908fbefbb9 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 13 Jan 2023 15:15:03 +0800 Subject: [PATCH 27/71] Update expected words --- .github/actions/spelling/expect.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 04042a3a9..2e331fea7 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -83,4 +83,6 @@ btn otf searchplugin Noresult -wpftk \ No newline at end of file +wpftk +mkv +flac \ No newline at end of file From bd1ef4ec919e5f01c6cbbd9d641b61ac7afca461 Mon Sep 17 00:00:00 2001 From: DB p Date: Fri, 13 Jan 2023 18:53:44 +0900 Subject: [PATCH 28/71] Add wrong key for wrong themes. --- Flow.Launcher/Themes/Base.xaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Flow.Launcher/Themes/Base.xaml b/Flow.Launcher/Themes/Base.xaml index 84b979194..2ba3a5929 100644 --- a/Flow.Launcher/Themes/Base.xaml +++ b/Flow.Launcher/Themes/Base.xaml @@ -396,6 +396,12 @@ + + + F1 M12000,12000z M0,0z M10354,10962C10326,10951 10279,10927 10249,10907 10216,10886 9476,10153 8370,9046 7366,8042 6541,7220 6536,7220 6532,7220 6498,7242 6461,7268 6213,7447 5883,7619 5592,7721 5194,7860 4802,7919 4360,7906 3612,7886 2953,7647 2340,7174 2131,7013 1832,6699 1664,6465 1394,6088 1188,5618 1097,5170 1044,4909 1030,4764 1030,4470 1030,4130 1056,3914 1135,3609 1263,3110 1511,2633 1850,2235 1936,2134 2162,1911 2260,1829 2781,1395 3422,1120 4090,1045 4271,1025 4667,1025 4848,1045 5505,1120 6100,1368 6630,1789 6774,1903 7081,2215 7186,2355 7362,2588 7467,2759 7579,2990 7802,3455 7911,3937 7911,4460 7911,4854 7861,5165 7737,5542 7684,5702 7675,5724 7602,5885 7517,6071 7390,6292 7270,6460 7242,6499 7220,6533 7220,6538 7220,6542 8046,7371 9055,8380 10441,9766 10898,10229 10924,10274 10945,10308 10966,10364 10976,10408 10990,10472 10991,10493 10980,10554 10952,10717 10840,10865 10690,10937 10621,10971 10607,10974 10510,10977 10425,10980 10395,10977 10354,10962z M4685,7050C5214,7001 5694,6809 6100,6484 6209,6396 6396,6209 6484,6100 7151,5267 7246,4110 6721,3190 6369,2571 5798,2137 5100,1956 4706,1855 4222,1855 3830,1957 3448,2056 3140,2210 2838,2453 2337,2855 2010,3427 1908,4080 1877,4274 1877,4656 1908,4850 1948,5105 2028,5370 2133,5590 2459,6272 3077,6782 3810,6973 3967,7014 4085,7034 4290,7053 4371,7061 4583,7059 4685,7050z From 218eb2b332709aada4fafefdbb55985bee6c42f3 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 16 Jan 2023 21:33:29 +1100 Subject: [PATCH 29/71] Add sponsor to readme add sponsor --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index cccbe401b..ef78e3cd0 100644 --- a/README.md +++ b/README.md @@ -330,6 +330,8 @@ And you can download       +       +

### Mentions From 2e4127c63b0de314f155c19e154a30c6c1294cba Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 00:37:05 +0800 Subject: [PATCH 30/71] Catch specifc exception --- .../Search/SearchManager.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 93a81f947..b3c118fca 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -105,14 +105,16 @@ namespace Flow.Launcher.Plugin.Explorer.Search await foreach (var search in searchResults.WithCancellation(token).ConfigureAwait(false)) results.Add(ResultManager.CreateResult(query, search)); } + catch (OperationCanceledException) + { + return results.ToList(); + } + catch (EngineNotAvailableException) + { + throw; + } catch (Exception e) { - if (e is OperationCanceledException) - return results.ToList(); - - if (e is EngineNotAvailableException) - throw; - throw new SearchException(engineName, e.Message, e); } From 6efa9d1731fee3de894566eb558c0f92111cdaeb Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 00:40:54 +0800 Subject: [PATCH 31/71] Only expand environment var when path starts with % --- Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index b3c118fca..45ba690d3 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -175,7 +175,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search return EnvironmentVariables.GetEnvironmentStringPathSuggestions(querySearch, query, Context); // Query is a location path with a full environment variable, eg. %appdata%\somefolder\ - var isEnvironmentVariablePath = querySearch[1..].Contains("%\\"); + var isEnvironmentVariablePath = querySearch[0] == '%' && querySearch[1..].Contains("%\\"); var locationPath = querySearch; From 983f0aafc4267fa64b9469d72710532aa9b027fd Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 00:49:24 +0800 Subject: [PATCH 32/71] Use a static dictionary for environment vars --- .../Search/EnvironmentVariables.cs | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs index 595ac3610..fae5f59cd 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.IO; @@ -8,12 +8,25 @@ namespace Flow.Launcher.Plugin.Explorer.Search { public static class EnvironmentVariables { + private static Dictionary _envStringPaths = null; + private static Dictionary EnvStringPaths + { + get + { + if (_envStringPaths == null) + { + _envStringPaths = LoadEnvironmentStringPaths(); + } + return _envStringPaths; + } + } + internal static bool IsEnvironmentVariableSearch(string search) { return search.StartsWith("%") && search != "%%" - && !search.Contains("\\") && - LoadEnvironmentStringPaths().Count > 0; + && !search.Contains("\\") + && EnvStringPaths.Count > 0; } internal static Dictionary LoadEnvironmentStringPaths() @@ -44,15 +57,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal static string TranslateEnvironmentVariablePath(string environmentVariablePath) { - var envStringPaths = LoadEnvironmentStringPaths(); var splitSearch = environmentVariablePath.Substring(1).Split("%"); var exactEnvStringPath = splitSearch[0]; // if there are more than 2 % characters in the query, don't bother - if (splitSearch.Length == 2 && envStringPaths.ContainsKey(exactEnvStringPath)) + if (splitSearch.Length == 2 && EnvStringPaths.ContainsKey(exactEnvStringPath)) { var queryPartToReplace = $"%{exactEnvStringPath}%"; - var expandedPath = envStringPaths[exactEnvStringPath]; + var expandedPath = EnvStringPaths[exactEnvStringPath]; // replace the %envstring% part of the query with its expanded equivalent return environmentVariablePath.Replace(queryPartToReplace, expandedPath); } @@ -64,7 +76,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search { var results = new List(); - var environmentVariables = LoadEnvironmentStringPaths(); var search = querySearch; if (querySearch.EndsWith("%") && search.Length > 1) @@ -72,9 +83,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search // query starts and ends with a %, find an exact match from env-string paths search = querySearch.Substring(1, search.Length - 2); - if (environmentVariables.ContainsKey(search)) + if (EnvStringPaths.ContainsKey(search)) { - var expandedPath = environmentVariables[search]; + var expandedPath = EnvStringPaths[search]; results.Add(ResultManager.CreateFolderResult($"%{search}%", expandedPath, expandedPath, query)); @@ -91,7 +102,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search search = search.Substring(1); } - foreach (var p in environmentVariables) + foreach (var p in EnvStringPaths) { if (p.Key.StartsWith(search, StringComparison.InvariantCultureIgnoreCase)) { From 009ee3dc5c7a35daa36872f77a2f999cb8001815 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 12:34:36 +0800 Subject: [PATCH 33/71] Simplify environment variable detection --- .../Search/EnvironmentVariables.cs | 29 +++++++------------ .../Search/SearchManager.cs | 2 +- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs index fae5f59cd..3d6a1ad8a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs @@ -23,12 +23,17 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal static bool IsEnvironmentVariableSearch(string search) { - return search.StartsWith("%") + return search.StartsWith("%") && search != "%%" - && !search.Contains("\\") + && !search.Contains('\\') && EnvStringPaths.Count > 0; } + internal static bool BeginsWithEnvironmentVar(string search) + { + return search[0] == '%' && search[1..].Contains("%\\"); + } + internal static Dictionary LoadEnvironmentStringPaths() { var envStringPaths = new Dictionary(StringComparer.InvariantCultureIgnoreCase); @@ -57,19 +62,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal static string TranslateEnvironmentVariablePath(string environmentVariablePath) { - var splitSearch = environmentVariablePath.Substring(1).Split("%"); - var exactEnvStringPath = splitSearch[0]; - - // if there are more than 2 % characters in the query, don't bother - if (splitSearch.Length == 2 && EnvStringPaths.ContainsKey(exactEnvStringPath)) - { - var queryPartToReplace = $"%{exactEnvStringPath}%"; - var expandedPath = EnvStringPaths[exactEnvStringPath]; - // replace the %envstring% part of the query with its expanded equivalent - return environmentVariablePath.Replace(queryPartToReplace, expandedPath); - } - - return environmentVariablePath; + return Environment.ExpandEnvironmentVariables(environmentVariablePath); } internal static List GetEnvironmentStringPathSuggestions(string querySearch, Query query, PluginInitContext context) @@ -86,9 +79,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search if (EnvStringPaths.ContainsKey(search)) { var expandedPath = EnvStringPaths[search]; - + results.Add(ResultManager.CreateFolderResult($"%{search}%", expandedPath, expandedPath, query)); - + return results; } } @@ -101,7 +94,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search { search = search.Substring(1); } - + foreach (var p in EnvStringPaths) { if (p.Key.StartsWith(search, StringComparison.InvariantCultureIgnoreCase)) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 45ba690d3..677b7f038 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -175,7 +175,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search return EnvironmentVariables.GetEnvironmentStringPathSuggestions(querySearch, query, Context); // Query is a location path with a full environment variable, eg. %appdata%\somefolder\ - var isEnvironmentVariablePath = querySearch[0] == '%' && querySearch[1..].Contains("%\\"); + var isEnvironmentVariablePath = EnvironmentVariables.BeginsWithEnvironmentVar(querySearch); var locationPath = querySearch; From 52e72992c2d417e2fd5b3e149a568aa0fef6aabe Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 14:47:42 +0800 Subject: [PATCH 34/71] Change context and settings to non static --- Flow.Launcher.Test/Plugins/ExplorerTest.cs | 3 ++- .../Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs | 8 ++++---- .../Search/WindowsIndex/WindowsIndexSearchManager.cs | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs index 36f0294a9..4075947ff 100644 --- a/Flow.Launcher.Test/Plugins/ExplorerTest.cs +++ b/Flow.Launcher.Test/Plugins/ExplorerTest.cs @@ -176,7 +176,7 @@ namespace Flow.Launcher.Test.Plugins var searchManager = new SearchManager(new Settings(), new PluginInitContext()); // When - var result = SearchManager.IsFileContentSearch(query.ActionKeyword); + var result = searchManager.IsFileContentSearch(query.ActionKeyword); // Then Assert.IsTrue(result, @@ -193,6 +193,7 @@ namespace Flow.Launcher.Test.Plugins [TestCase(@"c:\>*", true)] [TestCase(@"c:\>", true)] [TestCase(@"c:\SomeLocation\SomeOtherLocation\>", true)] + [TestCase(@"c:\SomeLocation\SomeOtherLocation", true)] public void WhenGivenQuerySearchString_ThenShouldIndicateIfIsLocationPathString(string querySearchString, bool expectedResult) { // When, Given diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 677b7f038..ce1283e06 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -13,9 +13,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search { public class SearchManager { - internal static PluginInitContext Context; + internal PluginInitContext Context; - internal static Settings Settings; + internal Settings Settings; public SearchManager(Settings settings, PluginInitContext context) { @@ -144,7 +144,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search }; } - private static List EverythingContentSearchResult(Query query) + private List EverythingContentSearchResult(Query query) { return new List() { @@ -236,7 +236,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search return results.ToList(); } - public static bool IsFileContentSearch(string actionKeyword) => actionKeyword == Settings.FileContentSearchActionKeyword; + public bool IsFileContentSearch(string actionKeyword) => actionKeyword == Settings.FileContentSearchActionKeyword; private bool UseWindowsIndexForDirectorySearch(string locationPath) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs index abb50849d..f1060a4ac 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs @@ -97,10 +97,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex private IAsyncEnumerable HandledEngineNotAvailableExceptionAsync() { - if (!SearchManager.Settings.WarnWindowsSearchServiceOff) + if (!Settings.WarnWindowsSearchServiceOff) return AsyncEnumerable.Empty(); - var api = SearchManager.Context.API; + var api = Main.Context.API; throw new EngineNotAvailableException( "Windows Index", @@ -108,7 +108,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex api.GetTranslation("plugin_explorer_windowsSearchServiceNotRunning"), c => { - SearchManager.Settings.WarnWindowsSearchServiceOff = false; + Settings.WarnWindowsSearchServiceOff = false; // Clears the warning message so user is not mistaken that it has not worked api.ChangeQuery(string.Empty); From 51f5d8a410e1708280e1c7e48c23951b4c8db37d Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 14:48:35 +0800 Subject: [PATCH 35/71] Add new constructor for EngineNotAvailableException --- .../Exceptions/EngineNotAvailableException.cs | 21 +++++++++++++++--- .../Everything/EverythingSearchManager.cs | 22 +++++++------------ .../WindowsIndex/WindowsIndexSearchManager.cs | 6 ++--- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/EngineNotAvailableException.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/EngineNotAvailableException.cs index 1a48892f5..a6315fb4b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/EngineNotAvailableException.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/EngineNotAvailableException.cs @@ -3,8 +3,6 @@ using System; using System.Threading.Tasks; using System.Windows; -using Flow.Launcher.Plugin.Explorer.Search.IProvider; -using JetBrains.Annotations; namespace Flow.Launcher.Plugin.Explorer.Exceptions; @@ -20,7 +18,7 @@ public class EngineNotAvailableException : Exception string engineName, string resolution, string message, - Func> action = null) : base(message) + Func>? action = null) : base(message) { EngineName = engineName; Resolution = resolution; @@ -40,6 +38,23 @@ public class EngineNotAvailableException : Exception EngineName = engineName; Resolution = resolution; } + + public EngineNotAvailableException( + string engineName, + string resolution, + string message, + string errorIconPath, + Func>? action = null) : base(message) + { + EngineName = engineName; + Resolution = resolution; + ErrorIcon = errorIconPath; + Action = action ?? (_ => + { + Clipboard.SetDataObject(this.ToString()); + return ValueTask.FromResult(true); + }); + } public override string ToString() { diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs index ffd22d9f5..4bb8a0cdd 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs @@ -27,20 +27,16 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything Enum.GetName(Settings.IndexSearchEngineOption.Everything)!, Main.Context.API.GetTranslation("flowlauncher_plugin_everything_click_to_launch_or_install"), Main.Context.API.GetTranslation("flowlauncher_plugin_everything_is_not_running"), - ClickToInstallEverythingAsync) - { - ErrorIcon = Constants.EverythingErrorImagePath - }; + Constants.EverythingErrorImagePath, + ClickToInstallEverythingAsync); } catch (DllNotFoundException) { throw new EngineNotAvailableException( Enum.GetName(Settings.IndexSearchEngineOption.Everything)!, "Please check whether your system is x86 or x64", - Main.Context.API.GetTranslation("flowlauncher_plugin_everything_sdk_issue")) - { - ErrorIcon = Constants.GeneralSearchErrorImagePath - }; + Constants.GeneralSearchErrorImagePath, + Main.Context.API.GetTranslation("flowlauncher_plugin_everything_sdk_issue")); } } private async ValueTask ClickToInstallEverythingAsync(ActionContext _) @@ -72,16 +68,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything if (!Settings.EnableEverythingContentSearch) { throw new EngineNotAvailableException(Enum.GetName(Settings.IndexSearchEngineOption.Everything)!, - "Click to Enable Everything Content Search (only applicable to Everything 1.5+ with indexed content)", - "Everything Content Search is not enabled.", + Main.Context.API.GetTranslation("flowlauncher_plugin_everything_enable_content_search"), + Main.Context.API.GetTranslation("flowlauncher_plugin_everything_enable_content_search_tips"), + Constants.EverythingErrorImagePath, _ => { Settings.EnableEverythingContentSearch = true; return ValueTask.FromResult(true); - }) - { - ErrorIcon = Constants.EverythingErrorImagePath - }; + }); } if (token.IsCancellationRequested) yield break; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs index f1060a4ac..c3a7d9e91 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs @@ -106,6 +106,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex "Windows Index", api.GetTranslation("plugin_explorer_windowsSearchServiceFix"), api.GetTranslation("plugin_explorer_windowsSearchServiceNotRunning"), + Constants.WindowsIndexErrorImagePath, c => { Settings.WarnWindowsSearchServiceOff = false; @@ -114,10 +115,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex api.ChangeQuery(string.Empty); return ValueTask.FromResult(false); - }) - { - ErrorIcon = Constants.WindowsIndexErrorImagePath - }; + }); } } } From 383298a46bca314c26f1f6c1738c1935c35dcf19 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 16:04:41 +0800 Subject: [PATCH 36/71] Fix null subtitle when creating disk result --- Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs index 62ad71608..ed4f39735 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs @@ -71,7 +71,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search { Title = title, IcoPath = path, - SubTitle = Path.GetDirectoryName(path), + SubTitle = subtitle, AutoCompleteText = GetAutoCompleteText(title, query, path, ResultType.Folder), TitleHighlightData = StringMatcher.FuzzySearch(query.Search, title).MatchData, CopyText = path, From a6b7c5898b1a472b3d377f40e2b089b8d5c472b1 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 16:05:39 +0800 Subject: [PATCH 37/71] Fix subpath check --- .../Search/SearchManager.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index ce1283e06..4a25fe0ad 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Flow.Launcher.Plugin.Explorer.Exceptions; +using System.IO; namespace Flow.Launcher.Plugin.Explorer.Search { @@ -119,7 +120,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search } results.RemoveWhere(r => Settings.IndexSearchExcludedSubdirectoryPaths.Any( - excludedPath => r.SubTitle.StartsWith(excludedPath.Path, StringComparison.OrdinalIgnoreCase))); + excludedPath => IsSubPathOf(r.SubTitle, excludedPath.Path))); return results.ToList(); } @@ -254,5 +255,16 @@ namespace Flow.Launcher.Plugin.Explorer.Search && search != "%%" && !search.Contains('\\'); } + + // https://stackoverflow.com/a/66877016 + internal static bool IsSubPathOf(string subPath, string basePath) + { + var rel = Path.GetRelativePath(basePath, subPath); + return rel != "." + && rel != ".." + && !rel.StartsWith("../") + && !rel.StartsWith(@"..\") + && !Path.IsPathRooted(rel); + } } } From 2c36692052f1f43782ee6f7f3fdf8416b7f7f6c7 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 16:06:01 +0800 Subject: [PATCH 38/71] Use case-insensitve comparator for path --- .../Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 4a25fe0ad..da6509124 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -31,12 +31,13 @@ namespace Flow.Launcher.Plugin.Explorer.Search public bool Equals(Result x, Result y) { - return x.Title == y.Title && x.SubTitle == y.SubTitle; + return x.Title.Equals(y.Title, StringComparison.OrdinalIgnoreCase) + && string.Equals(x.SubTitle, y.SubTitle, StringComparison.OrdinalIgnoreCase); } public int GetHashCode(Result obj) { - return HashCode.Combine(obj.Title.GetHashCode(), obj.SubTitle?.GetHashCode() ?? 0); + return HashCode.Combine(obj.Title.ToLowerInvariant(), obj.SubTitle?.ToLowerInvariant() ?? ""); } } @@ -118,7 +119,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search { throw new SearchException(engineName, e.Message, e); } - + results.RemoveWhere(r => Settings.IndexSearchExcludedSubdirectoryPaths.Any( excludedPath => IsSubPathOf(r.SubTitle, excludedPath.Path))); From 32268890b964e4e125ba81973541aa9588f05335 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 20:23:33 +0800 Subject: [PATCH 39/71] Remove TranslateEnvironmentVariablePath --- .../Search/EnvironmentVariables.cs | 5 ----- .../Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs index 3d6a1ad8a..c17277112 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs @@ -60,11 +60,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search return envStringPaths; } - internal static string TranslateEnvironmentVariablePath(string environmentVariablePath) - { - return Environment.ExpandEnvironmentVariables(environmentVariablePath); - } - internal static List GetEnvironmentStringPathSuggestions(string querySearch, Query query, PluginInitContext context) { var results = new List(); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index da6509124..25604cf2f 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -178,11 +178,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search // Query is a location path with a full environment variable, eg. %appdata%\somefolder\ var isEnvironmentVariablePath = EnvironmentVariables.BeginsWithEnvironmentVar(querySearch); - + var locationPath = querySearch; if (isEnvironmentVariablePath) - locationPath = EnvironmentVariables.TranslateEnvironmentVariablePath(locationPath); + locationPath = Environment.ExpandEnvironmentVariables(locationPath); // Check that actual location exists, otherwise directory search will throw directory not found exception if (!FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath).LocationExists()) From ac92b93f669feb512a0ef0cb2ec1364f9b2b3377 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 20:29:25 +0800 Subject: [PATCH 40/71] Move IsSubPathOf to SharedCommands --- .../SharedCommands/FilesFolders.cs | 17 +++++++++++++++++ .../Search/SearchManager.cs | 13 +------------ .../Programs/Win32.cs | 15 ++------------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs index 5cb3a171a..97d8c25d3 100644 --- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs +++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs @@ -241,5 +241,22 @@ namespace Flow.Launcher.Plugin.SharedCommands return path; } + + /// + /// Returns if is a sub path of . + /// From https://stackoverflow.com/a/66877016 + /// + /// + /// + /// + public static bool IsSubPathOf(string subPath, string basePath) + { + var rel = Path.GetRelativePath(basePath, subPath); + return rel != "." + && rel != ".." + && !rel.StartsWith("../") + && !rel.StartsWith(@"..\") + && !Path.IsPathRooted(rel); + } } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 25604cf2f..324832990 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -121,7 +121,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search } results.RemoveWhere(r => Settings.IndexSearchExcludedSubdirectoryPaths.Any( - excludedPath => IsSubPathOf(r.SubTitle, excludedPath.Path))); + excludedPath => FilesFolders.IsSubPathOf(r.SubTitle, excludedPath.Path))); return results.ToList(); } @@ -256,16 +256,5 @@ namespace Flow.Launcher.Plugin.Explorer.Search && search != "%%" && !search.Contains('\\'); } - - // https://stackoverflow.com/a/66877016 - internal static bool IsSubPathOf(string subPath, string basePath) - { - var rel = Path.GetRelativePath(basePath, subPath); - return rel != "." - && rel != ".." - && !rel.StartsWith("../") - && !rel.StartsWith(@"..\") - && !Path.IsPathRooted(rel); - } } } diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index f678b6bc8..28eb9832f 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -471,7 +471,7 @@ namespace Flow.Launcher.Plugin.Program.Programs var paths = pathEnv.Split(";", StringSplitOptions.RemoveEmptyEntries).DistinctBy(p => p.ToLowerInvariant()); - var toFilter = paths.Where(x => commonParents.All(parent => !IsSubPathOf(x, parent))) + var toFilter = paths.Where(x => commonParents.All(parent => !FilesFolders.IsSubPathOf(x, parent))) .AsParallel() .SelectMany(p => EnumerateProgramsInDir(p, suffixes, recursive: false)); @@ -763,17 +763,6 @@ namespace Flow.Launcher.Plugin.Program.Programs } } - // https://stackoverflow.com/a/66877016 - private static bool IsSubPathOf(string subPath, string basePath) - { - var rel = Path.GetRelativePath(basePath, subPath); - return rel != "." - && rel != ".." - && !rel.StartsWith("../") - && !rel.StartsWith(@"..\") - && !Path.IsPathRooted(rel); - } - private static List GetCommonParents(IEnumerable programSources) { // To avoid unnecessary io @@ -785,7 +774,7 @@ namespace Flow.Launcher.Plugin.Program.Programs HashSet parents = group.ToHashSet(); foreach (var source in group) { - if (parents.Any(p => IsSubPathOf(source.Location, p.Location) && + if (parents.Any(p => FilesFolders.IsSubPathOf(source.Location, p.Location) && source != p)) { parents.Remove(source); From beb144956c2d1c6163a5dd7f96486f5edd80c2a5 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 21:33:09 +0800 Subject: [PATCH 41/71] Rename method and add option to allow equality --- .../SharedCommands/FilesFolders.cs | 14 +++++++------- .../Search/SearchManager.cs | 2 +- .../Flow.Launcher.Plugin.Program/Programs/Win32.cs | 7 +++---- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs index 97d8c25d3..c59f05598 100644 --- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs +++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics; using System.IO; -using System.Windows; namespace Flow.Launcher.Plugin.SharedCommands { @@ -243,16 +242,17 @@ namespace Flow.Launcher.Plugin.SharedCommands } /// - /// Returns if is a sub path of . + /// Returns if contains . /// From https://stackoverflow.com/a/66877016 /// - /// - /// + /// Parent path + /// Sub path + /// If , when and are equal, returns /// - public static bool IsSubPathOf(string subPath, string basePath) + public static bool PathContains(string parentPath, string subPath, bool allowEqual = false) { - var rel = Path.GetRelativePath(basePath, subPath); - return rel != "." + var rel = Path.GetRelativePath(parentPath, subPath); + return (rel != "." || allowEqual) && rel != ".." && !rel.StartsWith("../") && !rel.StartsWith(@"..\") diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 324832990..3a1dc3726 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -121,7 +121,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search } results.RemoveWhere(r => Settings.IndexSearchExcludedSubdirectoryPaths.Any( - excludedPath => FilesFolders.IsSubPathOf(r.SubTitle, excludedPath.Path))); + excludedPath => FilesFolders.PathContains(excludedPath.Path, r.SubTitle))); return results.ToList(); } diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index 28eb9832f..e0079967b 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -470,8 +470,8 @@ namespace Flow.Launcher.Plugin.Program.Programs } var paths = pathEnv.Split(";", StringSplitOptions.RemoveEmptyEntries).DistinctBy(p => p.ToLowerInvariant()); - - var toFilter = paths.Where(x => commonParents.All(parent => !FilesFolders.IsSubPathOf(x, parent))) + + var toFilter = paths.Where(x => commonParents.All(parent => !FilesFolders.PathContains(parent, x))) .AsParallel() .SelectMany(p => EnumerateProgramsInDir(p, suffixes, recursive: false)); @@ -774,8 +774,7 @@ namespace Flow.Launcher.Plugin.Program.Programs HashSet parents = group.ToHashSet(); foreach (var source in group) { - if (parents.Any(p => FilesFolders.IsSubPathOf(source.Location, p.Location) && - source != p)) + if (parents.Any(p => FilesFolders.PathContains(p.Location, source.Location))) { parents.Remove(source); } From b42fc54b806285067dd2c22cf600fd22c174c3b7 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 21:33:21 +0800 Subject: [PATCH 42/71] Add test for PathContains() --- Flow.Launcher.Test/FilesFoldersTest.cs | 53 ++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 Flow.Launcher.Test/FilesFoldersTest.cs diff --git a/Flow.Launcher.Test/FilesFoldersTest.cs b/Flow.Launcher.Test/FilesFoldersTest.cs new file mode 100644 index 000000000..656395591 --- /dev/null +++ b/Flow.Launcher.Test/FilesFoldersTest.cs @@ -0,0 +1,53 @@ +using Flow.Launcher.Plugin.SharedCommands; +using NUnit.Framework; + +namespace Flow.Launcher.Test +{ + [TestFixture] + + public class FilesFoldersTest + { + // Testcases from https://stackoverflow.com/a/31941905/20703207 + // Disk + [TestCase(@"c:", @"c:\foo", true)] + [TestCase(@"c:\", @"c:\foo", true)] + // Slash + [TestCase(@"c:\foo\bar\", @"c:\foo\", false)] + [TestCase(@"c:\foo\bar", @"c:\foo\", false)] + [TestCase(@"c:\foo", @"c:\foo\bar", true)] + [TestCase(@"c:\foo\", @"c:\foo\bar", true)] + // File + [TestCase(@"c:\foo", @"c:\foo\a.txt", true)] + [TestCase(@"c:\foo", @"c:/foo/a.txt", true)] + [TestCase(@"c:\FOO\a.txt", @"c:\foo", false)] + [TestCase(@"c:\foo\a.txt", @"c:\foo\", false)] + [TestCase(@"c:\foobar\a.txt", @"c:\foo", false)] + [TestCase(@"c:\foobar\a.txt", @"c:\foo\", false)] + [TestCase(@"c:\foo\", @"c:\foo.txt", false)] + // Prefix + [TestCase(@"c:\foo", @"c:\foobar", false)] + [TestCase(@"C:\Program", @"C:\Program Files\", false)] + [TestCase(@"c:\foobar", @"c:\foo\a.txt", false)] + [TestCase(@"c:\foobar\", @"c:\foo\a.txt", false)] + // Edge case + [TestCase(@"c:\foo", @"c:\foo\..\bar\baz", false)] + [TestCase(@"c:\bar", @"c:\foo\..\bar\baz", true)] + [TestCase(@"c:\barr", @"c:\foo\..\bar\baz", false)] + // Equality + [TestCase(@"c:\foo", @"c:\foo", false)] + [TestCase(@"c:\foo\", @"c:\foo", false)] + [TestCase(@"c:\foo", @"c:\foo\", false)] + public void TestPathContains(string parentPath, string path, bool expectedResult) + { + Assert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path)); + } + + [TestCase(@"c:\foo", @"c:\foo", true)] + [TestCase(@"c:\foo\", @"c:\foo", true)] + [TestCase(@"c:\foo\", @"c:\foo", true)] + public void TestPathContainsWhenEqual(string parentPath, string path, bool expectedResult) + { + Assert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path, true)); + } + } +} From 4bea50d4cf9c738f03440e03d21f9801227b51ec Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 23:16:12 +0800 Subject: [PATCH 43/71] Add unit test for PathEqualityComparator --- Flow.Launcher.Test/FilesFoldersTest.cs | 2 +- Flow.Launcher.Test/Plugins/ExplorerTest.cs | 41 +++++++++++++++++++ .../Search/SearchManager.cs | 14 ++++--- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher.Test/FilesFoldersTest.cs b/Flow.Launcher.Test/FilesFoldersTest.cs index 656395591..a65cc600d 100644 --- a/Flow.Launcher.Test/FilesFoldersTest.cs +++ b/Flow.Launcher.Test/FilesFoldersTest.cs @@ -44,7 +44,7 @@ namespace Flow.Launcher.Test [TestCase(@"c:\foo", @"c:\foo", true)] [TestCase(@"c:\foo\", @"c:\foo", true)] - [TestCase(@"c:\foo\", @"c:\foo", true)] + [TestCase(@"c:\foo", @"c:\foo\", true)] public void TestPathContainsWhenEqual(string parentPath, string path, bool expectedResult) { Assert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path, true)); diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs index 4075947ff..322441247 100644 --- a/Flow.Launcher.Test/Plugins/ExplorerTest.cs +++ b/Flow.Launcher.Test/Plugins/ExplorerTest.cs @@ -7,9 +7,11 @@ using Flow.Launcher.Plugin.SharedCommands; using NUnit.Framework; using System; using System.Collections.Generic; +using System.IO; using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; +using static Flow.Launcher.Plugin.Explorer.Search.SearchManager; namespace Flow.Launcher.Test.Plugins { @@ -394,5 +396,44 @@ namespace Flow.Launcher.Test.Plugins // Then Assert.AreEqual(result, expectedResult); } + + [TestCase(@"c:\foo", @"c:\foo", true)] + [TestCase(@"C:\Foo\", @"c:\foo\", true)] + [TestCase(@"c:\foo", @"c:\foo\", false)] + public void PathEqualityComparatorEquality(string path1, string path2, bool expectedResult) + { + var comparator = PathEqualityComparator.Instance; + var result1 = new Result + { + Title = Path.GetFileName(path1), + SubTitle = path1 + }; + var result2 = new Result + { + Title = Path.GetFileName(path2), + SubTitle = path2 + }; + Assert.AreEqual(expectedResult, comparator.Equals(result1, result2)); + } + + [TestCase(@"c:\foo\", @"c:\foo\")] + [TestCase(@"C:\Foo\", @"c:\foo\")] + public void PathEqualityComparatorHashCode(string path1, string path2) + { + var comparator = PathEqualityComparator.Instance; + var result1 = new Result + { + Title = Path.GetFileName(path1), + SubTitle = path1 + }; + var result2 = new Result + { + Title = Path.GetFileName(path2), + SubTitle = path2 + }; + var hash1 = comparator.GetHashCode(result1); + var hash2 = comparator.GetHashCode(result2); + Assert.IsTrue(hash1 == hash2); + } } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 3a1dc3726..0a40590ba 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Flow.Launcher.Plugin.Explorer.Exceptions; -using System.IO; namespace Flow.Launcher.Plugin.Explorer.Search { @@ -24,14 +23,17 @@ namespace Flow.Launcher.Plugin.Explorer.Search Settings = settings; } - private class PathEqualityComparator : IEqualityComparer + /// + /// Note: Assuming all diretories end with "\". + /// + public class PathEqualityComparator : IEqualityComparer { private static PathEqualityComparator instance; public static PathEqualityComparator Instance => instance ??= new PathEqualityComparator(); public bool Equals(Result x, Result y) { - return x.Title.Equals(y.Title, StringComparison.OrdinalIgnoreCase) + return x.Title.Equals(y.Title, StringComparison.OrdinalIgnoreCase) && string.Equals(x.SubTitle, y.SubTitle, StringComparison.OrdinalIgnoreCase); } @@ -178,7 +180,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search // Query is a location path with a full environment variable, eg. %appdata%\somefolder\ var isEnvironmentVariablePath = EnvironmentVariables.BeginsWithEnvironmentVar(querySearch); - + var locationPath = querySearch; if (isEnvironmentVariablePath) @@ -249,10 +251,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(pathToDirectory).StartsWith(x.Path, StringComparison.OrdinalIgnoreCase)) && WindowsIndex.WindowsIndex.PathIsIndexed(pathToDirectory); } - + internal static bool IsEnvironmentVariableSearch(string search) { - return search.StartsWith("%") + return search.StartsWith("%") && search != "%%" && !search.Contains('\\'); } From 03f062ca34c49e6cb6223f867718436116969ddd Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jan 2023 23:26:10 +0800 Subject: [PATCH 44/71] Fix build error --- Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs index c59f05598..2ccc35884 100644 --- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs +++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs @@ -1,6 +1,9 @@ using System; using System.Diagnostics; using System.IO; +#if !DEBUG +using System.Windows; +#endif namespace Flow.Launcher.Plugin.SharedCommands { From fefb1378704291ae6e70ee8691640718333ac2f0 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 20 Jan 2023 07:45:39 +1100 Subject: [PATCH 45/71] fix test format --- Flow.Launcher.Test/Plugins/ExplorerTest.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs index 322441247..70c13f296 100644 --- a/Flow.Launcher.Test/Plugins/ExplorerTest.cs +++ b/Flow.Launcher.Test/Plugins/ExplorerTest.cs @@ -400,8 +400,9 @@ namespace Flow.Launcher.Test.Plugins [TestCase(@"c:\foo", @"c:\foo", true)] [TestCase(@"C:\Foo\", @"c:\foo\", true)] [TestCase(@"c:\foo", @"c:\foo\", false)] - public void PathEqualityComparatorEquality(string path1, string path2, bool expectedResult) + public void GivenTwoPaths_WhenCompared_ThenShouldBeExpectedSameOrDifferent(string path1, string path2, bool expectedResult) { + // Given var comparator = PathEqualityComparator.Instance; var result1 = new Result { @@ -413,13 +414,16 @@ namespace Flow.Launcher.Test.Plugins Title = Path.GetFileName(path2), SubTitle = path2 }; + + // When, Then Assert.AreEqual(expectedResult, comparator.Equals(result1, result2)); } [TestCase(@"c:\foo\", @"c:\foo\")] [TestCase(@"C:\Foo\", @"c:\foo\")] - public void PathEqualityComparatorHashCode(string path1, string path2) + public void GivenTwoPaths_WhenComparedHasCode_ThenShouldBeSame(string path1, string path2) { + // Given var comparator = PathEqualityComparator.Instance; var result1 = new Result { @@ -431,8 +435,11 @@ namespace Flow.Launcher.Test.Plugins Title = Path.GetFileName(path2), SubTitle = path2 }; + var hash1 = comparator.GetHashCode(result1); var hash2 = comparator.GetHashCode(result2); + + // When, Then Assert.IsTrue(hash1 == hash2); } } From b77bfea8875be532cafacfcefce6a14c34023ea6 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 20 Jan 2023 07:55:16 +1100 Subject: [PATCH 46/71] update test name --- Flow.Launcher.Test/FilesFoldersTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Test/FilesFoldersTest.cs b/Flow.Launcher.Test/FilesFoldersTest.cs index a65cc600d..d16826053 100644 --- a/Flow.Launcher.Test/FilesFoldersTest.cs +++ b/Flow.Launcher.Test/FilesFoldersTest.cs @@ -1,4 +1,4 @@ -using Flow.Launcher.Plugin.SharedCommands; +using Flow.Launcher.Plugin.SharedCommands; using NUnit.Framework; namespace Flow.Launcher.Test @@ -37,7 +37,7 @@ namespace Flow.Launcher.Test [TestCase(@"c:\foo", @"c:\foo", false)] [TestCase(@"c:\foo\", @"c:\foo", false)] [TestCase(@"c:\foo", @"c:\foo\", false)] - public void TestPathContains(string parentPath, string path, bool expectedResult) + public void GivenTwoPaths_WhenCheckPathContains_ThenShouldBeExpectedResult(string parentPath, string path, bool expectedResult) { Assert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path)); } @@ -45,7 +45,7 @@ namespace Flow.Launcher.Test [TestCase(@"c:\foo", @"c:\foo", true)] [TestCase(@"c:\foo\", @"c:\foo", true)] [TestCase(@"c:\foo", @"c:\foo\", true)] - public void TestPathContainsWhenEqual(string parentPath, string path, bool expectedResult) + public void GivenTwoPathsAreTheSame_WhenCheckPathContains_ThenShouldBeTrue(string parentPath, string path, bool expectedResult) { Assert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path, true)); } From 768ed4f80a2b7f83530ff7698cdc0fb30a87fe59 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 20 Jan 2023 12:13:02 +0800 Subject: [PATCH 47/71] Update wording Co-authored-by: Jeremy Wu --- Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 0a40590ba..916399e5c 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -24,7 +24,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search } /// - /// Note: Assuming all diretories end with "\". + /// Note: A path that ends with "\" and one that doesn't will not be regarded as equal. /// public class PathEqualityComparator : IEqualityComparer { From 504fb4ae0588735635955ac5a580e01baafc6175 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 20 Jan 2023 14:02:04 +0800 Subject: [PATCH 48/71] Display environment vars in upper case --- .../Search/EnvironmentVariables.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs index c17277112..130de2ab1 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs @@ -52,8 +52,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search path = Path.IsPathFullyQualified(path) ? path : Path.GetFullPath(path); // Variables are returned with a mixture of all upper/lower case. - // Call ToLower() to make the results look consistent - envStringPaths.Add(special.Key.ToString().ToLower(), path); + // Call ToUpper() to make the results look consistent + envStringPaths.Add(special.Key.ToString().ToUpper(), path); } } From 4d267fe71ee0f3aeb88f8781cb9aa4f5739cb49d Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 20 Jan 2023 14:27:12 +0800 Subject: [PATCH 49/71] Fix incorrect %homepath% parsing Parse environment variables before checking path existence --- .../SharedCommands/FilesFolders.cs | 10 ++++++++++ .../Search/EnvironmentVariables.cs | 20 ++++++++++--------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs index 2ccc35884..42a0e0c73 100644 --- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs +++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs @@ -261,5 +261,15 @@ namespace Flow.Launcher.Plugin.SharedCommands && !rel.StartsWith(@"..\") && !Path.IsPathRooted(rel); } + + /// + /// Returns path ended with "\" + /// + /// + /// + public static string EnsureTrailingSlash(this string path) + { + return path.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar; + } } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs index 130de2ab1..a649de58e 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs @@ -2,7 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; -using System.Text; +using Flow.Launcher.Plugin.SharedCommands; namespace Flow.Launcher.Plugin.Explorer.Search { @@ -37,20 +37,22 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal static Dictionary LoadEnvironmentStringPaths() { var envStringPaths = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + var homedrive = Environment.GetEnvironmentVariable("HOMEDRIVE")?.EnsureTrailingSlash() ?? "C:\\"; foreach (DictionaryEntry special in Environment.GetEnvironmentVariables()) { var path = special.Value.ToString(); + // we add a trailing slash to the path to make sure drive paths become valid absolute paths. + // for example, if %systemdrive% is C: we turn it to C:\ + path = path.EnsureTrailingSlash(); + + // if we don't have an absolute path, we use Path.GetFullPath to get one. + // for example, if %homepath% is \Users\John we turn it to C:\Users\John + // Add basepath for GetFullPath() to parse %HOMEPATH% correctly + path = Path.IsPathFullyQualified(path) ? path : Path.GetFullPath(path, homedrive); + if (Directory.Exists(path)) { - // we add a trailing slash to the path to make sure drive paths become valid absolute paths. - // for example, if %systemdrive% is C: we turn it to C:\ - path = path.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar; - - // if we don't have an absolute path, we use Path.GetFullPath to get one. - // for example, if %homepath% is \Users\John we turn it to C:\Users\John - path = Path.IsPathFullyQualified(path) ? path : Path.GetFullPath(path); - // Variables are returned with a mixture of all upper/lower case. // Call ToUpper() to make the results look consistent envStringPaths.Add(special.Key.ToString().ToUpper(), path); From 966d3e752efc3f7e52a83bfb3d8e46b62478c6fc Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 20 Jan 2023 15:03:40 +0800 Subject: [PATCH 50/71] Fix environment variable expansion logic --- Flow.Launcher.Test/Plugins/ExplorerTest.cs | 17 +++++++++++++++++ .../Search/EnvironmentVariables.cs | 10 ++++++++-- .../Search/SearchManager.cs | 14 ++++---------- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs index 70c13f296..e9d37433f 100644 --- a/Flow.Launcher.Test/Plugins/ExplorerTest.cs +++ b/Flow.Launcher.Test/Plugins/ExplorerTest.cs @@ -442,5 +442,22 @@ namespace Flow.Launcher.Test.Plugins // When, Then Assert.IsTrue(hash1 == hash2); } + + [TestCase(@"%appdata%", true)] + [TestCase(@"%appdata%\123", true)] + [TestCase(@"c:\foo %appdata%\", false)] + [TestCase(@"c:\users\%USERNAME%\downloads", true)] + [TestCase(@"c:\downloads", false)] + [TestCase(@"%", false)] + [TestCase(@"%%", false)] + [TestCase(@"%bla%blabla%", false)] + public void GivenPath_WhenHavingEnvironmentVariableOrNot_ThenShouldBeExpected(string path, bool expectedResult) + { + // When + var result = EnvironmentVariables.HasEnvironmentVar(path); + + // Then + Assert.AreEqual(result, expectedResult); + } } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs index a649de58e..5b0a5a8bd 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; +using System.Linq; using Flow.Launcher.Plugin.SharedCommands; namespace Flow.Launcher.Plugin.Explorer.Search @@ -29,9 +30,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search && EnvStringPaths.Count > 0; } - internal static bool BeginsWithEnvironmentVar(string search) + public static bool HasEnvironmentVar(string search) { - return search[0] == '%' && search[1..].Contains("%\\"); + // "c:\foo %appdata%\" returns false + var splited = search.Split(Path.DirectorySeparatorChar); + return splited.Any(dir => dir.StartsWith('%') && + dir.EndsWith('%') && + dir.Length > 2 && + dir.Split('%').Length == 3); } internal static Dictionary LoadEnvironmentStringPaths() diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 916399e5c..83057ff04 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -173,18 +173,12 @@ namespace Flow.Launcher.Plugin.Explorer.Search var results = new HashSet(PathEqualityComparator.Instance); - var isEnvironmentVariable = EnvironmentVariables.IsEnvironmentVariableSearch(querySearch); - - if (isEnvironmentVariable) + if (EnvironmentVariables.IsEnvironmentVariableSearch(querySearch)) return EnvironmentVariables.GetEnvironmentStringPathSuggestions(querySearch, query, Context); - // Query is a location path with a full environment variable, eg. %appdata%\somefolder\ - var isEnvironmentVariablePath = EnvironmentVariables.BeginsWithEnvironmentVar(querySearch); - - var locationPath = querySearch; - - if (isEnvironmentVariablePath) - locationPath = Environment.ExpandEnvironmentVariables(locationPath); + // Query is a location path with a full environment variable, eg. %appdata%\somefolder\, c:\users\%USERNAME%\downloads + var needToExpand = EnvironmentVariables.HasEnvironmentVar(querySearch); + var locationPath = needToExpand ? Environment.ExpandEnvironmentVariables(querySearch) : querySearch; // Check that actual location exists, otherwise directory search will throw directory not found exception if (!FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath).LocationExists()) From 71a2f996dbff2c92b219aa5641af01ef50870622 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 20 Jan 2023 15:27:19 +0800 Subject: [PATCH 51/71] Set environment var dict in LoadEnvironmentStringPaths() --- .../Search/EnvironmentVariables.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs index 5b0a5a8bd..e526fb85a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs @@ -16,7 +16,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search { if (_envStringPaths == null) { - _envStringPaths = LoadEnvironmentStringPaths(); + LoadEnvironmentStringPaths(); } return _envStringPaths; } @@ -40,9 +40,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search dir.Split('%').Length == 3); } - internal static Dictionary LoadEnvironmentStringPaths() + private static void LoadEnvironmentStringPaths() { - var envStringPaths = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + _envStringPaths = new Dictionary(StringComparer.InvariantCultureIgnoreCase); var homedrive = Environment.GetEnvironmentVariable("HOMEDRIVE")?.EnsureTrailingSlash() ?? "C:\\"; foreach (DictionaryEntry special in Environment.GetEnvironmentVariables()) @@ -61,11 +61,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search { // Variables are returned with a mixture of all upper/lower case. // Call ToUpper() to make the results look consistent - envStringPaths.Add(special.Key.ToString().ToUpper(), path); + _envStringPaths.Add(special.Key.ToString().ToUpper(), path); } } - - return envStringPaths; } internal static List GetEnvironmentStringPathSuggestions(string querySearch, Query query, PluginInitContext context) From b739bb49d307e3d1d058bd3504e43139e260bbf3 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 20 Jan 2023 15:36:14 +0800 Subject: [PATCH 52/71] Fix CI test failure --- Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs index 42a0e0c73..a6cf0755c 100644 --- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs +++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs @@ -254,7 +254,7 @@ namespace Flow.Launcher.Plugin.SharedCommands /// public static bool PathContains(string parentPath, string subPath, bool allowEqual = false) { - var rel = Path.GetRelativePath(parentPath, subPath); + var rel = Path.GetRelativePath(parentPath.EnsureTrailingSlash(), subPath); return (rel != "." || allowEqual) && rel != ".." && !rel.StartsWith("../") From f31d21a7a42624412620d662efedf2cfeef5c837 Mon Sep 17 00:00:00 2001 From: DB p Date: Sat, 21 Jan 2023 15:05:12 +0900 Subject: [PATCH 53/71] Add Maximum/Minimum Value with numberbox --- Flow.Launcher/PriorityChangeWindow.xaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Flow.Launcher/PriorityChangeWindow.xaml b/Flow.Launcher/PriorityChangeWindow.xaml index d6aadead9..c917eeffc 100644 --- a/Flow.Launcher/PriorityChangeWindow.xaml +++ b/Flow.Launcher/PriorityChangeWindow.xaml @@ -85,6 +85,8 @@ Date: Sat, 21 Jan 2023 16:57:41 +0800 Subject: [PATCH 54/71] Return empty when operation canceled --- Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 83057ff04..51c4c3d9d 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -111,7 +111,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search } catch (OperationCanceledException) { - return results.ToList(); + return new List(); } catch (EngineNotAvailableException) { From babffe907f2a320b6e05bfe798c32d07d96c71d2 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 22 Jan 2023 12:59:32 +0800 Subject: [PATCH 55/71] Disable unused import warning --- Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs index a6cf0755c..cfcaaa44d 100644 --- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs +++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs @@ -1,9 +1,9 @@ using System; using System.Diagnostics; using System.IO; -#if !DEBUG +#pragma warning disable IDE0005 using System.Windows; -#endif +#pragma warning restore IDE0005 namespace Flow.Launcher.Plugin.SharedCommands { From dd02ad37bc2a620b3493614b649cbd386e7a3276 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 22 Jan 2023 13:21:53 +0800 Subject: [PATCH 56/71] Refactor --- Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs index cfcaaa44d..bd8d32ff5 100644 --- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs +++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs @@ -208,22 +208,16 @@ namespace Flow.Launcher.Plugin.SharedCommands /// public static string GetPreviousExistingDirectory(Func locationExists, string path) { - var previousDirectoryPath = ""; var index = path.LastIndexOf('\\'); if (index > 0 && index < (path.Length - 1)) { - previousDirectoryPath = path.Substring(0, index + 1); - if (!locationExists(previousDirectoryPath)) - { - return ""; - } + string previousDirectoryPath = path.Substring(0, index + 1); + return locationExists(previousDirectoryPath) ? previousDirectoryPath : ""; } else { return ""; } - - return previousDirectoryPath; } /// From d16a249e3616e6017d4df276f932eb0c7bfabd22 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 23 Jan 2023 08:51:36 +1100 Subject: [PATCH 57/71] version bump plugins --- Plugins/Flow.Launcher.Plugin.Explorer/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Program/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Shell/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Sys/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Url/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json index df2e556e1..0d94d60d9 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json @@ -10,7 +10,7 @@ "Name": "Explorer", "Description": "Find and manage files and folders via Windows Search or Everything", "Author": "Jeremy Wu", - "Version": "2.1.0", + "Version": "2.2.0", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll", diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json index 694cb5f8d..0d1ee5b16 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json @@ -6,7 +6,7 @@ "Name": "Plugins Manager", "Description": "Management of installing, uninstalling or updating Flow Launcher plugins", "Author": "Jeremy Wu", - "Version": "2.0.0", + "Version": "2.0.1", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", diff --git a/Plugins/Flow.Launcher.Plugin.Program/plugin.json b/Plugins/Flow.Launcher.Plugin.Program/plugin.json index cd9119431..3d20c0a48 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Program/plugin.json @@ -4,7 +4,7 @@ "Name": "Program", "Description": "Search programs in Flow.Launcher", "Author": "qianlifeng", - "Version": "2.1.0", + "Version": "2.2.0", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Program.dll", diff --git a/Plugins/Flow.Launcher.Plugin.Shell/plugin.json b/Plugins/Flow.Launcher.Plugin.Shell/plugin.json index 5885b10d7..2b80e5138 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Shell/plugin.json @@ -4,7 +4,7 @@ "Name": "Shell", "Description": "Provide executing commands from Flow Launcher", "Author": "qianlifeng", - "Version": "2.0.0", + "Version": "2.0.1", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Shell.dll", diff --git a/Plugins/Flow.Launcher.Plugin.Sys/plugin.json b/Plugins/Flow.Launcher.Plugin.Sys/plugin.json index 0ce62c28c..74c9d9030 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Sys/plugin.json @@ -4,7 +4,7 @@ "Name": "System Commands", "Description": "Provide System related commands. e.g. shutdown,lock, setting etc.", "Author": "qianlifeng", - "Version": "2.0.0", + "Version": "2.0.1", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Sys.dll", diff --git a/Plugins/Flow.Launcher.Plugin.Url/plugin.json b/Plugins/Flow.Launcher.Plugin.Url/plugin.json index aadaf5d70..48c184ec2 100644 --- a/Plugins/Flow.Launcher.Plugin.Url/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Url/plugin.json @@ -4,7 +4,7 @@ "Name": "URL", "Description": "Open the typed URL from Flow Launcher", "Author": "qianlifeng", - "Version": "2.0.0", + "Version": "2.0.1", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Url.dll", diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json index ccd06b345..fb1e31c12 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json @@ -26,7 +26,7 @@ "Name": "Web Searches", "Description": "Provide the web search ability", "Author": "qianlifeng", - "Version": "2.0.1", + "Version": "2.0.2", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.WebSearch.dll", diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json b/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json index 0d8c7e19c..428a96923 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json @@ -4,7 +4,7 @@ "Description": "Search settings inside Control Panel and Settings App", "Name": "Windows Settings", "Author": "TobiasSekan", - "Version": "3.0.1", + "Version": "3.0.2", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.WindowsSettings.dll", From 3db80b17e417625784353a595d4c7ebff47f379a Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 23 Jan 2023 08:53:18 +1100 Subject: [PATCH 58/71] version bump Flow --- Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj | 8 ++++---- appveyor.yml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj index 22c47ae34..fb07f8255 100644 --- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj +++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj @@ -14,10 +14,10 @@ - 3.0.1 - 3.0.1 - 3.0.1 - 3.0.1 + 3.1.0 + 3.1.0 + 3.1.0 + 3.1.0 Flow.Launcher.Plugin Flow-Launcher MIT diff --git a/appveyor.yml b/appveyor.yml index ad8ac42b4..a327fa3a9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '1.11.0.{build}' +version: '1.12.0.{build}' init: - ps: | From f517343c11d6a5ae0d7b1ec9d6da5172873569e9 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 23 Jan 2023 09:17:09 +1100 Subject: [PATCH 59/71] update error message --- Flow.Launcher.Infrastructure/Storage/JsonStorage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs index 20b2e4e21..500b0829e 100644 --- a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs @@ -69,7 +69,7 @@ namespace Flow.Launcher.Infrastructure.Storage var data = JsonSerializer.Deserialize(File.ReadAllText(BackupFilePath)); if (data != null) { - Log.Info($"|JsonStorage.Load|Load backup file {BackupFilePath} successfully"); + Log.Info($"|JsonStorage.Load|Failed to load settings.json, {BackupFilePath} restored successfully"); File.Replace(BackupFilePath, FilePath, null); return data; } From 51fac770978e1f963b08684f98d9c7dd1e8c841e Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Tue, 24 Jan 2023 20:42:53 -0600 Subject: [PATCH 60/71] Use File.Move when the setting file does not exists --- .../Storage/JsonStorage.cs | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs index 500b0829e..43e7ddab7 100644 --- a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs @@ -13,12 +13,17 @@ namespace Flow.Launcher.Infrastructure.Storage public class JsonStorage where T : new() { protected T? Data; + // need a new directory name public const string DirectoryName = "Settings"; public const string FileSuffix = ".json"; + protected string FilePath { get; init; } = null!; + private string TempFilePath => $"{FilePath}.tmp"; + private string BackupFilePath => $"{FilePath}.bak"; + protected string DirectoryPath { get; init; } = null!; @@ -35,7 +40,7 @@ namespace Flow.Launcher.Infrastructure.Storage { try { - Data = JsonSerializer.Deserialize(serialized)?? TryLoadBackup() ?? LoadDefault(); + Data = JsonSerializer.Deserialize(serialized) ?? TryLoadBackup() ?? LoadDefault(); } catch (JsonException) { @@ -46,6 +51,7 @@ namespace Flow.Launcher.Infrastructure.Storage { Data = TryLoadBackup() ?? LoadDefault(); } + return Data.NonNull(); } @@ -67,12 +73,15 @@ namespace Flow.Launcher.Infrastructure.Storage try { var data = JsonSerializer.Deserialize(File.ReadAllText(BackupFilePath)); + if (data != null) { Log.Info($"|JsonStorage.Load|Failed to load settings.json, {BackupFilePath} restored successfully"); File.Replace(BackupFilePath, FilePath, null); + return data; } + return default; } catch (JsonException) @@ -94,14 +103,22 @@ namespace Flow.Launcher.Infrastructure.Storage public void Save() { - string serialized = JsonSerializer.Serialize(Data, new JsonSerializerOptions - { - WriteIndented = true - }); + string serialized = JsonSerializer.Serialize(Data, + new JsonSerializerOptions + { + WriteIndented = true + }); File.WriteAllText(TempFilePath, serialized); - File.Replace(TempFilePath, FilePath, BackupFilePath); - File.Delete(TempFilePath); + + if (!File.Exists(FilePath)) + { + File.Move(TempFilePath, FilePath); + } + else + { + File.Replace(TempFilePath, FilePath, BackupFilePath); + } } } } From abc13a4de54c3b6579a3ad0da004330695dca928 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Wed, 25 Jan 2023 20:47:11 +1100 Subject: [PATCH 61/71] version bump --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index a327fa3a9..29fc4cf4b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '1.12.0.{build}' +version: '1.12.1.{build}' init: - ps: | From 89fb78f3cdc4b364622e705fbac97a127ed09b6b Mon Sep 17 00:00:00 2001 From: TheBestPessimist Date: Wed, 25 Jan 2023 13:20:30 +0200 Subject: [PATCH 62/71] Change the default shortcut for Plugin Indicator to `?` #1825 --- Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json index 084779ef9..64f5fce7a 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json @@ -1,10 +1,10 @@ { "ID": "6A122269676E40EB86EB543B945932B9", - "ActionKeyword": "*", + "ActionKeyword": "?", "Name": "Plugin Indicator", "Description": "Provides plugin action keyword suggestions", "Author": "qianlifeng", - "Version": "2.0.1", + "Version": "2.0.2", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginIndicator.dll", From 7fc704558d32dd78ad375e36764d8b53bfd82ff3 Mon Sep 17 00:00:00 2001 From: Lasith Manujitha <64279853+z1nc0r3@users.noreply.github.com> Date: Thu, 26 Jan 2023 10:01:40 +0530 Subject: [PATCH 63/71] Fix autocomplete on Program plugin (#1850) * Fix autocomplete on Program plugin * Code refactor --- Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs | 1 + Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs index 023eea042..8ba3ba800 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs @@ -408,6 +408,7 @@ namespace Flow.Launcher.Plugin.Program.Programs var result = new Result { Title = title, + AutoCompleteText = Name, SubTitle = Main._settings.HideAppsPath ? string.Empty : Location, IcoPath = LogoPath, Preview = new Result.PreviewInfo diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index e0079967b..0798857ed 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -155,6 +155,7 @@ namespace Flow.Launcher.Plugin.Program.Programs var result = new Result { Title = title, + AutoCompleteText = resultName, SubTitle = subtitle, IcoPath = IcoPath, Score = matchResult.Score, From 1482637cf192cf1dea9a251347747b8f3785ab9e Mon Sep 17 00:00:00 2001 From: TheBestPessimist Date: Wed, 25 Jan 2023 15:30:44 +0200 Subject: [PATCH 64/71] Everything.MatchPath = true --- .../Search/Everything/EverythingAPI.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 5381d729d..fcb59d293 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -152,6 +152,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything EverythingApiDllImport.Everything_SetMax(option.MaxCount); EverythingApiDllImport.Everything_SetSort(option.SortOption); + EverythingApiDllImport.Everything_SetMatchPath(true); if (token.IsCancellationRequested) yield break; From 2b6c92c48cc296b36cdb44c6db568e3a03ba989e Mon Sep 17 00:00:00 2001 From: TheBestPessimist Date: Wed, 25 Jan 2023 15:32:53 +0200 Subject: [PATCH 65/71] question to the FL developers --- .../Search/Everything/EverythingAPI.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index fcb59d293..63724ad98 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -39,7 +39,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything /// Gets or sets a value indicating whether [match path]. /// /// true if [match path]; otherwise, false. - public static bool MatchPath + public static bool MatchPath // TODO these seem to be unused, and they're related exactly to the feature i want: make everything search through the whole path. How should these be used? Should they be removed instead? IMHO, it seems better to use full path search by default, so i'd remove this completely { get => EverythingApiDllImport.Everything_GetMatchPath(); set => EverythingApiDllImport.Everything_SetMatchPath(value); From 1b9a879d48cd9e0acf57e9a7b0826fe122676bd7 Mon Sep 17 00:00:00 2001 From: TheBestPessimist Date: Thu, 26 Jan 2023 08:55:25 +0200 Subject: [PATCH 66/71] Use `EverythingSearchOption` flag to set up `FullPathSearch` instead of hardcoding it --- .../Search/Everything/EverythingAPI.cs | 2 +- .../Search/Everything/EverythingSearchOption.cs | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 63724ad98..2013ebe4b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -152,7 +152,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything EverythingApiDllImport.Everything_SetMax(option.MaxCount); EverythingApiDllImport.Everything_SetSort(option.SortOption); - EverythingApiDllImport.Everything_SetMatchPath(true); + EverythingApiDllImport.Everything_SetMatchPath(option.IsFullPathSearch); if (token.IsCancellationRequested) yield break; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs index 6839822a4..0b1bbd0ec 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs @@ -3,12 +3,15 @@ using Flow.Launcher.Plugin.Everything.Everything; namespace Flow.Launcher.Plugin.Explorer.Search.Everything { - public record struct EverythingSearchOption(string Keyword, + public record struct EverythingSearchOption( + string Keyword, SortOption SortOption, - bool IsContentSearch = false, + bool IsContentSearch = false, string ContentSearchKeyword = default, string ParentPath = default, bool IsRecursive = true, - int Offset = 0, - int MaxCount = 100); + int Offset = 0, + int MaxCount = 100, + bool IsFullPathSearch = true + ); } From 18d1bb566898980436b2cc55d6fb71e4541ed04c Mon Sep 17 00:00:00 2001 From: TheBestPessimist Date: Thu, 26 Jan 2023 09:19:42 +0200 Subject: [PATCH 67/71] Cleanup unused properties --- .../Search/Everything/EverythingAPI.cs | 47 ++----------------- 1 file changed, 3 insertions(+), 44 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 2013ebe4b..3efd09c4d 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -13,13 +13,12 @@ using Flow.Launcher.Plugin.Explorer.Exceptions; namespace Flow.Launcher.Plugin.Explorer.Search.Everything { - public static class EverythingApi { - private const int BufferSize = 4096; private static SemaphoreSlim _semaphore = new(1, 1); + // cached buffer to remove redundant allocations. private static readonly StringBuilder buffer = new(BufferSize); @@ -35,46 +34,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything InvalidCallError } - /// - /// Gets or sets a value indicating whether [match path]. - /// - /// true if [match path]; otherwise, false. - public static bool MatchPath // TODO these seem to be unused, and they're related exactly to the feature i want: make everything search through the whole path. How should these be used? Should they be removed instead? IMHO, it seems better to use full path search by default, so i'd remove this completely - { - get => EverythingApiDllImport.Everything_GetMatchPath(); - set => EverythingApiDllImport.Everything_SetMatchPath(value); - } - - /// - /// Gets or sets a value indicating whether [match case]. - /// - /// true if [match case]; otherwise, false. - public static bool MatchCase - { - get => EverythingApiDllImport.Everything_GetMatchCase(); - set => EverythingApiDllImport.Everything_SetMatchCase(value); - } - - /// - /// Gets or sets a value indicating whether [match whole word]. - /// - /// true if [match whole word]; otherwise, false. - public static bool MatchWholeWord - { - get => EverythingApiDllImport.Everything_GetMatchWholeWord(); - set => EverythingApiDllImport.Everything_SetMatchWholeWord(value); - } - - /// - /// Gets or sets a value indicating whether [enable regex]. - /// - /// true if [enable regex]; otherwise, false. - public static bool EnableRegex - { - get => EverythingApiDllImport.Everything_GetRegex(); - set => EverythingApiDllImport.Everything_SetRegex(value); - } - /// /// Checks whether the sort option is Fast Sort. /// @@ -95,7 +54,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything try { - EverythingApiDllImport.Everything_GetMajorVersion(); + EverythingApiDllImport.Everything_GetMajorVersion(); var result = EverythingApiDllImport.Everything_GetLastError() != StateCode.IPCError; return result; } @@ -122,7 +81,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything await _semaphore.WaitAsync(token); - + try { if (token.IsCancellationRequested) From 892f1b8ed2256f6888daecdfd93c3af6e61b6947 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Jan 2023 16:08:35 +0000 Subject: [PATCH 68/71] Bump System.Data.OleDb from 5.0.0 to 7.0.0 (#1808) --- .../Flow.Launcher.Plugin.Explorer.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj index 62cb599a1..29acf0eb7 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -45,7 +45,7 @@ - + From 51c909800f3698f370d1acb539aaaad543421f68 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Jan 2023 16:08:55 +0000 Subject: [PATCH 69/71] Bump SharpZipLib from 1.3.3 to 1.4.1 (#1833) --- .../Flow.Launcher.Plugin.PluginsManager.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj index 2b773bee4..317ba4e89 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj @@ -38,6 +38,6 @@ - + \ No newline at end of file From fbd12eb96b1f37140dbde8e7608b7e38d712e384 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 Feb 2023 12:21:25 +0800 Subject: [PATCH 70/71] Add missing translation --- Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index 2ed421ca9..15456079a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -9,6 +9,7 @@ Are you sure you want to delete {0}? Are you sure you want to permanently delete this folder? Are you sure you want to permanently delete this file? + Are you sure you want to permanently delete this file/folder? Deletion successful Successfully deleted {0} Assigning the global action keyword could bring up too many results during search. Please choose a specific action keyword From f941655d6434a882ddbb9301553500e0f239aec8 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 3 Feb 2023 12:34:42 +0800 Subject: [PATCH 71/71] Fix null reference when hotkey is invalid --- Flow.Launcher/HotkeyControl.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index 15feae6cc..b71df9758 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -103,7 +103,7 @@ namespace Flow.Launcher private void tbHotkey_LostFocus(object sender, RoutedEventArgs e) { - tbHotkey.Text = CurrentHotkey.ToString(); + tbHotkey.Text = CurrentHotkey?.ToString() ?? ""; tbHotkey.Select(tbHotkey.Text.Length, 0); }