From 9b05174a97005bba1997c260c69764efc8049e8a Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 30 Dec 2022 20:56:30 +0800 Subject: [PATCH 01/11] Use localized name for shell link programs --- .../Programs/ShellLocalization.cs | 92 +++++++++++++++++++ .../Programs/Win32.cs | 20 ++-- 2 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs new file mode 100644 index 000000000..4f344d89e --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs @@ -0,0 +1,92 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + + +namespace Flow.Launcher.Plugin.Program.Programs +{ + // From PT Run + /// + /// Class to get localized name of shell items like 'My computer'. The localization is based on the 'windows display language'. + /// Reused code from https://stackoverflow.com/questions/41423491/how-to-get-localized-name-of-known-folder for the method + /// + public static class ShellLocalization + { + internal const uint DONTRESOLVEDLLREFERENCES = 0x00000001; + internal const uint LOADLIBRARYASDATAFILE = 0x00000002; + + [DllImport("shell32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)] + internal static extern int SHGetLocalizedName(string pszPath, StringBuilder pszResModule, ref int cch, out int pidsRes); + + [DllImport("user32.dll", EntryPoint = "LoadStringW", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)] + internal static extern int LoadString(IntPtr hModule, int resourceID, StringBuilder resourceValue, int len); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, EntryPoint = "LoadLibraryExW")] + internal static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags); + + [DllImport("kernel32.dll", ExactSpelling = true)] + internal static extern int FreeLibrary(IntPtr hModule); + + [DllImport("kernel32.dll", EntryPoint = "ExpandEnvironmentStringsW", CharSet = CharSet.Unicode, ExactSpelling = true)] + internal static extern uint ExpandEnvironmentStrings(string lpSrc, StringBuilder lpDst, int nSize); + + /// + /// Returns the localized name of a shell item. + /// + /// Path to the shell item (e. g. shortcut 'File Explorer.lnk'). + /// The localized name as string or . + public static string GetLocalizedName(string path) + { + StringBuilder resourcePath = new StringBuilder(1024); + StringBuilder localizedName = new StringBuilder(1024); + int len, id; + len = resourcePath.Capacity; + + // If there is no resource to localize a file name the method returns a non zero value. + if (SHGetLocalizedName(path, resourcePath, ref len, out id) == 0) + { + _ = ExpandEnvironmentStrings(resourcePath.ToString(), resourcePath, resourcePath.Capacity); + IntPtr hMod = LoadLibraryEx(resourcePath.ToString(), IntPtr.Zero, DONTRESOLVEDLLREFERENCES | LOADLIBRARYASDATAFILE); + if (hMod != IntPtr.Zero) + { + if (LoadString(hMod, id, localizedName, localizedName.Capacity) != 0) + { + string lString = localizedName.ToString(); + _ = FreeLibrary(hMod); + return lString; + } + + _ = FreeLibrary(hMod); + } + } + + return string.Empty; + } + + /// + /// This method returns the localized path to a shell item (folder or file) + /// + /// The path to localize + /// The localized path or the original path if localized version is not available + public static string GetLocalizedPath(string path) + { + path = Environment.ExpandEnvironmentVariables(path); + string ext = Path.GetExtension(path); + var pathParts = path.Split("\\"); + string[] locPath = new string[pathParts.Length]; + + for (int i = 0; i < pathParts.Length; i++) + { + int iElements = i + 1; + string lName = GetLocalizedName(string.Join("\\", pathParts[..iElements])); + locPath[i] = !string.IsNullOrEmpty(lName) ? lName : pathParts[i]; + } + + string newPath = string.Join("\\", locPath); + newPath = !newPath.EndsWith(ext, StringComparison.InvariantCultureIgnoreCase) ? newPath + ext : newPath; + + return newPath; + } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index f8c220610..3bbe55d38 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -44,6 +44,9 @@ namespace Flow.Launcher.Plugin.Program.Programs public bool Enabled { get; set; } public string Location => ParentDirectory; + // Localized name based on windows display language + public string LocalizedName { get; set; } = string.Empty; + private const string ShortcutExtension = "lnk"; private const string UrlExtension = "url"; private const string ExeExtension = "exe"; @@ -69,27 +72,30 @@ namespace Flow.Launcher.Plugin.Program.Programs string title; MatchResult matchResult; + // Name of the result + string resultName = string.IsNullOrEmpty(LocalizedName) ? Name : LocalizedName; + // We suppose Name won't be null - if (!Main._settings.EnableDescription || Description == null || Name.StartsWith(Description)) + if (!Main._settings.EnableDescription || Description == null || resultName.StartsWith(Description)) { - title = Name; + title = resultName; matchResult = StringMatcher.FuzzySearch(query, title); } - else if (Description.StartsWith(Name)) + else if (Description.StartsWith(resultName)) { title = Description; matchResult = StringMatcher.FuzzySearch(query, Description); } else { - title = $"{Name}: {Description}"; - var nameMatch = StringMatcher.FuzzySearch(query, Name); + title = $"{resultName}: {Description}"; + var nameMatch = StringMatcher.FuzzySearch(query, resultName); var desciptionMatch = StringMatcher.FuzzySearch(query, Description); if (desciptionMatch.Score > nameMatch.Score) { for (int i = 0; i < desciptionMatch.MatchData.Count; i++) { - desciptionMatch.MatchData[i] += Name.Length + 2; // 2 is ": " + desciptionMatch.MatchData[i] += resultName.Length + 2; // 2 is ": " } matchResult = desciptionMatch; } @@ -297,6 +303,8 @@ namespace Flow.Launcher.Plugin.Program.Programs } } + program.LocalizedName = ShellLocalization.GetLocalizedName(path); + return program; } catch (COMException e) From c6ff0a51131250b11743e9d9ce1d4ad53515dc76 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 31 Dec 2022 17:49:38 +0800 Subject: [PATCH 02/11] Fix .lnk description logic --- .../Flow.Launcher.Plugin.Program/Programs/Win32.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index 3bbe55d38..4d3aecf58 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -273,14 +273,13 @@ namespace Flow.Launcher.Plugin.Program.Programs ShellLinkHelper _helper = new ShellLinkHelper(); string target = _helper.retrieveTargetPath(path); - if (!string.IsNullOrEmpty(target)) + if (!string.IsNullOrEmpty(target) && File.Exists(target)) { - var extension = Extension(target); - if (extension == ExeExtension && File.Exists(target)) - { - program.LnkResolvedPath = Path.GetFullPath(target); - program.ExecutableName = Path.GetFileName(target); + program.LnkResolvedPath = Path.GetFullPath(target); + program.ExecutableName = Path.GetFileName(target); + if (Extension(target) == ExeExtension) + { var args = _helper.arguments; if(!string.IsNullOrEmpty(args)) { From 207b29f816385408e3a4e72427d59db7a30eb0cb Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 31 Dec 2022 17:42:42 +0800 Subject: [PATCH 03/11] Update comments --- Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index 4d3aecf58..6b245d2c4 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -30,14 +30,17 @@ namespace Flow.Launcher.Plugin.Program.Programs /// public string FullPath { get; set; } /// - /// Path of the excutable for .lnk, or the URL for .url. Arguments are included if any. + /// Path of the executable for .lnk, or the URL for .url. Arguments are included if any. /// public string LnkResolvedPath { get; set; } /// - /// Path of the actual executable file. + /// Path of the actual executable file. Args are included. /// public string ExecutablePath => LnkResolvedPath ?? FullPath; public string ParentDirectory { get; set; } + /// + /// Name of the executable for .lnk files + /// public string ExecutableName { get; set; } public string Description { get; set; } public bool Valid { get; set; } @@ -584,7 +587,6 @@ namespace Flow.Launcher.Plugin.Program.Programs private static IEnumerable ProgramsHasher(IEnumerable programs) { - // TODO: Unable to distinguish multiple lnks to the same excutable but with different params return programs.GroupBy(p => p.ExecutablePath.ToLowerInvariant()) .AsParallel() .SelectMany(g => From e6b8a0dde2b477e53585a66cbf6469e269408217 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 31 Dec 2022 21:02:27 +0800 Subject: [PATCH 04/11] Catch exception in ShellLinkHelper --- .../Programs/ShellLinkHelper.cs | 17 ++++++++++++++--- .../Programs/Win32.cs | 9 --------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs index b93fb23c9..78c66d604 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs @@ -3,6 +3,7 @@ using System.Text; using System.Runtime.InteropServices; using Accessibility; using System.Runtime.InteropServices.ComTypes; +using Flow.Launcher.Plugin.Program.Logger; namespace Flow.Launcher.Plugin.Program.Programs { @@ -119,9 +120,19 @@ namespace Flow.Launcher.Plugin.Program.Programs // To set the app description if (!String.IsNullOrEmpty(target)) { - buffer = new StringBuilder(MAX_PATH); - ((IShellLinkW)link).GetDescription(buffer, MAX_PATH); - description = buffer.ToString(); + try + { + buffer = new StringBuilder(MAX_PATH); + ((IShellLinkW)link).GetDescription(buffer, MAX_PATH); + description = buffer.ToString(); + } + catch (COMException e) + { + // C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\MiracastView.lnk always cause exception + ProgramLogger.LogException($"|IShellLinkW|retrieveTargetPath|{path}" + + "|Error caused likely due to trying to get the description of the program", + e); + } buffer.Clear(); ((IShellLinkW)link).GetArguments(buffer, MAX_PATH); diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index 6b245d2c4..019048295 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -309,15 +309,6 @@ namespace Flow.Launcher.Plugin.Program.Programs return program; } - catch (COMException e) - { - // C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\MiracastView.lnk always cause exception - ProgramLogger.LogException($"|Win32|LnkProgram|{path}" + - "|Error caused likely due to trying to get the description of the program", - e); - - return Default; - } catch (FileNotFoundException e) { ProgramLogger.LogException($"|Win32|LnkProgram|{path}" + From 617183b14a9c57d0966d6fbc3eda0e5b3d2d00be Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 31 Dec 2022 17:59:46 +0800 Subject: [PATCH 05/11] Refactor result matching logic --- .../Programs/Win32.cs | 100 +++++++++++++----- 1 file changed, 76 insertions(+), 24 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index 019048295..fafe7d5bf 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -69,6 +69,29 @@ namespace Flow.Launcher.Plugin.Program.Programs Enabled = false }; + private static MatchResult Match(string query, List candidates) + { + if (candidates.Count == 0) + return null; + + List matches = new List(); + foreach(var candidate in candidates) + { + var match = StringMatcher.FuzzySearch(query, candidate); + if (match.IsSearchPrecisionScoreMet()) + { + matches.Add(match); + } + } + if (matches.Count == 0) + { + return null; + } + else + { + return matches.MaxBy(match => match.Score); + } + } public Result Result(string query, IPublicAPI api) { @@ -76,44 +99,73 @@ namespace Flow.Launcher.Plugin.Program.Programs MatchResult matchResult; // Name of the result - string resultName = string.IsNullOrEmpty(LocalizedName) ? Name : LocalizedName; + // Check equality to avoid matching again in candidates + bool useLocalizedName = !string.IsNullOrEmpty(LocalizedName) && !Name.Equals(LocalizedName); + string resultName = useLocalizedName ? LocalizedName : Name; - // We suppose Name won't be null - if (!Main._settings.EnableDescription || Description == null || resultName.StartsWith(Description)) + if (!Main._settings.EnableDescription) { title = resultName; - matchResult = StringMatcher.FuzzySearch(query, title); - } - else if (Description.StartsWith(resultName)) - { - title = Description; - matchResult = StringMatcher.FuzzySearch(query, Description); + matchResult = StringMatcher.FuzzySearch(query, resultName); } else { - title = $"{resultName}: {Description}"; - var nameMatch = StringMatcher.FuzzySearch(query, resultName); - var desciptionMatch = StringMatcher.FuzzySearch(query, Description); - if (desciptionMatch.Score > nameMatch.Score) + if (string.IsNullOrEmpty(Description) || resultName.StartsWith(Description)) { - for (int i = 0; i < desciptionMatch.MatchData.Count; i++) - { - desciptionMatch.MatchData[i] += resultName.Length + 2; // 2 is ": " - } - matchResult = desciptionMatch; + // 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); + } + 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; + } } - else matchResult = nameMatch; } + List candidates = new List(); + if (!matchResult.IsSearchPrecisionScoreMet()) { if (ExecutableName != null) // only lnk program will need this one - matchResult = StringMatcher.FuzzySearch(query, ExecutableName); - - if (!matchResult.IsSearchPrecisionScoreMet()) + { + candidates.Add(ExecutableName); + } + if (useLocalizedName) + { + candidates.Add(Name); + } + matchResult = Match(query, candidates); + if (matchResult == null) + { return null; - - matchResult.MatchData = new List(); + } + else + { + // Nothing to highlight in title in this case + matchResult.MatchData.Clear(); + } } string subtitle = string.Empty; From c5c6ae7b68dd0eaef0f8959c951947b735327db0 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 31 Dec 2022 21:18:20 +0800 Subject: [PATCH 06/11] Fix exception message argument --- Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs index d0070f833..b0e34b2a5 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs @@ -277,7 +277,7 @@ namespace Flow.Launcher.Plugin.Program.Programs } catch (Exception e) { - ProgramLogger.LogException("UWP", "CurrentUserPackages", $"{id}", "An unexpected error occured and " + ProgramLogger.LogException("UWP", "CurrentUserPackages", $"{p.Id}", "An unexpected error occured and " + $"unable to verify if package is valid", e); return false; } From 186f5f826e6a04896835ecfd202dd72dbd5aea20 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 31 Dec 2022 21:24:50 +0800 Subject: [PATCH 07/11] Fix error message --- Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs index b0e34b2a5..c05e36b8c 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs @@ -277,7 +277,7 @@ namespace Flow.Launcher.Plugin.Program.Programs } catch (Exception e) { - ProgramLogger.LogException("UWP", "CurrentUserPackages", $"{p.Id}", "An unexpected error occured and " + ProgramLogger.LogException("UWP", "CurrentUserPackages", $"{p.Id.FullName}", "An unexpected error occured and " + $"unable to verify if package is valid", e); return false; } From 4dbfe2d6a0b3577d1483f51c896986b63c080bf0 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 31 Dec 2022 21:25:12 +0800 Subject: [PATCH 08/11] Rename variables for readability --- .../Programs/UWP.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs index c05e36b8c..4c4a505f1 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs @@ -249,24 +249,24 @@ namespace Flow.Launcher.Plugin.Program.Programs private static IEnumerable CurrentUserPackages() { - var u = WindowsIdentity.GetCurrent().User; + var user = WindowsIdentity.GetCurrent().User; - if (u != null) + if (user != null) { - var id = u.Value; - PackageManager m; + var userId = user.Value; + PackageManager packageManager; try { - m = new PackageManager(); + packageManager = new PackageManager(); } catch { // Bug from https://github.com/microsoft/CsWinRT, using Microsoft.Windows.SDK.NET.Ref 10.0.19041.0. // Only happens on the first time, so a try catch can fix it. - m = new PackageManager(); + packageManager = new PackageManager(); } - var ps = m.FindPackagesForUser(id); - ps = ps.Where(p => + var packages = packageManager.FindPackagesForUser(userId); + packages = packages.Where(p => { try { @@ -282,7 +282,7 @@ namespace Flow.Launcher.Plugin.Program.Programs return false; } }); - return ps; + return packages; } else { From ff4290c1925b478e135421ecf3d8e2e02e3bbb41 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 31 Dec 2022 21:34:49 +0800 Subject: [PATCH 09/11] fix typo --- Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs index 4c4a505f1..00e7927ec 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs @@ -277,7 +277,7 @@ namespace Flow.Launcher.Plugin.Program.Programs } catch (Exception e) { - ProgramLogger.LogException("UWP", "CurrentUserPackages", $"{p.Id.FullName}", "An unexpected error occured and " + ProgramLogger.LogException("UWP", "CurrentUserPackages", $"{p.Id.FullName}", "An unexpected error occurred and " + $"unable to verify if package is valid", e); return false; } From 3992990ccb3cd26c00ee29e158eb4c0ba7c06a91 Mon Sep 17 00:00:00 2001 From: Vic <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 1 Jan 2023 00:24:36 +0800 Subject: [PATCH 10/11] Remove redundant extension check --- .../Programs/Win32.cs | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index fafe7d5bf..e9aeb03a8 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -333,26 +333,23 @@ namespace Flow.Launcher.Plugin.Program.Programs program.LnkResolvedPath = Path.GetFullPath(target); program.ExecutableName = Path.GetFileName(target); - if (Extension(target) == ExeExtension) + var args = _helper.arguments; + if(!string.IsNullOrEmpty(args)) { - var args = _helper.arguments; - if(!string.IsNullOrEmpty(args)) - { - program.LnkResolvedPath += " " + args; - } + program.LnkResolvedPath += " " + args; + } - var description = _helper.description; - if (!string.IsNullOrEmpty(description)) + var description = _helper.description; + if (!string.IsNullOrEmpty(description)) + { + program.Description = description; + } + else + { + var info = FileVersionInfo.GetVersionInfo(target); + if (!string.IsNullOrEmpty(info.FileDescription)) { - program.Description = description; - } - else - { - var info = FileVersionInfo.GetVersionInfo(target); - if (!string.IsNullOrEmpty(info.FileDescription)) - { - program.Description = info.FileDescription; - } + program.Description = info.FileDescription; } } } From 804a5d54dcaa425739094d0ba5217c6a7c5f06bc Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Tue, 3 Jan 2023 13:47:25 -0500 Subject: [PATCH 11/11] simplify logic --- .../Programs/Win32.cs | 57 +++++++------------ 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index 4cbdf25f2..dec43530e 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -23,7 +23,7 @@ namespace Flow.Launcher.Plugin.Program.Programs public class Win32 : IProgram, IEquatable { public string Name { get; set; } - public string UniqueIdentifier { get => _uid; set => _uid = value == null ? string.Empty : value.ToLowerInvariant(); } // For path comparison + public string UniqueIdentifier { get => _uid; set => _uid = value == null ? string.Empty : value.ToLowerInvariant(); } // For path comparison public string IcoPath { get; set; } /// /// Path of the file. It's the path of .lnk and .url for .lnk and .url files. @@ -69,28 +69,15 @@ namespace Flow.Launcher.Plugin.Program.Programs Enabled = false }; - private static MatchResult Match(string query, List candidates) + private static MatchResult Match(string query, IReadOnlyCollection candidates) { if (candidates.Count == 0) return null; - List matches = new List(); - foreach(var candidate in candidates) - { - var match = StringMatcher.FuzzySearch(query, candidate); - if (match.IsSearchPrecisionScoreMet()) - { - matches.Add(match); - } - } - if (matches.Count == 0) - { - return null; - } - else - { - return matches.MaxBy(match => match.Score); - } + var match = candidates.Select(candidate => StringMatcher.FuzzySearch(query, candidate)) + .MaxBy(match => match.Score); + + return match?.IsSearchPrecisionScoreMet() ?? false ? match : null; } public Result Result(string query, IPublicAPI api) @@ -334,7 +321,7 @@ namespace Flow.Launcher.Plugin.Program.Programs program.ExecutableName = Path.GetFileName(target); var args = _helper.arguments; - if(!string.IsNullOrEmpty(args)) + if (!string.IsNullOrEmpty(args)) { program.LnkResolvedPath += " " + args; } @@ -361,7 +348,7 @@ namespace Flow.Launcher.Plugin.Program.Programs catch (FileNotFoundException e) { ProgramLogger.LogException($"|Win32|LnkProgram|{path}" + - "|An unexpected error occurred in the calling method LnkProgram", e); + "|An unexpected error occurred in the calling method LnkProgram", e); return Default; } @@ -428,7 +415,7 @@ namespace Flow.Launcher.Plugin.Program.Programs catch (FileNotFoundException e) { ProgramLogger.LogException($"|Win32|ExeProgram|{path}" + - $"|File not found when trying to load the program from {path}", e); + $"|File not found when trying to load the program from {path}", e); return Default; } @@ -448,8 +435,7 @@ namespace Flow.Launcher.Plugin.Program.Programs return Directory.EnumerateFiles(directory, "*", new EnumerationOptions { - IgnoreInaccessible = true, - RecurseSubdirectories = recursive + IgnoreInaccessible = true, RecurseSubdirectories = recursive }).Where(x => suffixes.Contains(Extension(x))); } @@ -458,7 +444,7 @@ namespace Flow.Launcher.Plugin.Program.Programs var extension = Path.GetExtension(path)?.ToLowerInvariant(); if (!string.IsNullOrEmpty(extension)) { - return extension.Substring(1); // remove dot + return extension.Substring(1); // remove dot } else { @@ -470,7 +456,7 @@ namespace Flow.Launcher.Plugin.Program.Programs { // Disabled custom sources are not in DisabledProgramSources var paths = directories.AsParallel() - .SelectMany(s => EnumerateProgramsInDir(s, suffixes)); + .SelectMany(s => EnumerateProgramsInDir(s, suffixes)); // Remove disabled programs in DisabledProgramSources var programs = ExceptDisabledSource(paths).Select(x => GetProgramFromPath(x, protocols)); @@ -502,8 +488,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 => !IsSubPathOf(x, parent))) - .AsParallel() - .SelectMany(p => EnumerateProgramsInDir(p, suffixes, recursive: false)); + .AsParallel() + .SelectMany(p => EnumerateProgramsInDir(p, suffixes, recursive: false)); var programs = ExceptDisabledSource(toFilter.Distinct()) .Select(x => GetProgramFromPath(x, protocols)); @@ -533,7 +519,7 @@ namespace Flow.Launcher.Plugin.Program.Programs toFilter = toFilter.Distinct().Where(p => suffixes.Contains(Extension(p))); var programs = ExceptDisabledSource(toFilter) - .Select(x => GetProgramFromPath(x, protocols)).Where(x => x.Valid).ToList(); // ToList due to disposing issue + .Select(x => GetProgramFromPath(x, protocols)).Where(x => x.Valid).ToList(); // ToList due to disposing issue return programs; } @@ -587,7 +573,8 @@ namespace Flow.Launcher.Plugin.Program.Programs ExeExtension => ExeProgram(path), UrlExtension => UrlProgram(path, protocols), _ => Win32Program(path) - }; ; + }; + ; } public static IEnumerable ExceptDisabledSource(IEnumerable paths) @@ -797,10 +784,10 @@ namespace Flow.Launcher.Plugin.Program.Programs { var rel = Path.GetRelativePath(basePath, subPath); return rel != "." - && rel != ".." - && !rel.StartsWith("../") - && !rel.StartsWith(@"..\") - && !Path.IsPathRooted(rel); + && rel != ".." + && !rel.StartsWith("../") + && !rel.StartsWith(@"..\") + && !Path.IsPathRooted(rel); } private static List GetCommonParents(IEnumerable programSources) @@ -815,7 +802,7 @@ namespace Flow.Launcher.Plugin.Program.Programs foreach (var source in group) { if (parents.Any(p => IsSubPathOf(source.Location, p.Location) && - source != p)) + source != p)) { parents.Remove(source); }