From c63c98645cde289842ecabbc39b92ae2ddb3b277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 18 Oct 2020 21:17:29 +0800 Subject: [PATCH 01/54] Add Acronym Support for Fuzzy Search --- Flow.Launcher.Infrastructure/StringMatcher.cs | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 2a4270fb4b2..f15e22494eb 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -54,9 +54,55 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption stringToCompare = _alphabet.Translate(stringToCompare); } + // This also can be done by spliting the query + + //(var spaceSplit, var upperSplit) = stringToCompare switch + //{ + // string s when s.Contains(' ') => (s.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(w => w.First()), + // default(IEnumerable)), + // string s when s.Any(c => char.IsUpper(c)) && s.Any(c => char.IsLower(c)) => + // (null, Regex.Split(s, @"(? w.First())), + // _ => ((IEnumerable)null, (IEnumerable)null) + //}; + + var currentQueryIndex = 0; + var acronymMatchData = new List(); + var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; + + int acronymScore = 100; + + for (int compareIndex = 0; compareIndex < stringToCompare.Length; compareIndex++) + { + if (currentQueryIndex >= queryWithoutCase.Length) + break; + + if (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) + { + acronymMatchData.Add(compareIndex); + currentQueryIndex++; + continue; + } + + switch (stringToCompare[compareIndex]) + { + case char c when (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) + || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]): + acronymMatchData.Add(compareIndex); + currentQueryIndex++; + continue; + + case char c when char.IsWhiteSpace(c): + compareIndex++; + acronymScore -= 10; + break; + case char c when char.IsUpper(c): + acronymScore -= 10; + break; + } + } + var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; - var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; var querySubstrings = queryWithoutCase.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); int currentQuerySubstringIndex = 0; From e264af500fa129e74e6f22c6a2a283bf7d11560c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 18 Oct 2020 21:24:59 +0800 Subject: [PATCH 02/54] merge one extra condition to the switch case --- Flow.Launcher.Infrastructure/StringMatcher.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index f15e22494eb..cca6388f90a 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -76,16 +76,11 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption if (currentQueryIndex >= queryWithoutCase.Length) break; - if (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) - { - acronymMatchData.Add(compareIndex); - currentQueryIndex++; - continue; - } switch (stringToCompare[compareIndex]) { - case char c when (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) + case char c when compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex]) + || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]): acronymMatchData.Add(compareIndex); currentQueryIndex++; From 9ad78387293b2b3574487d32edabadd50cce055a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 18 Oct 2020 21:24:59 +0800 Subject: [PATCH 03/54] merge one extra condition to the switch case --- Flow.Launcher.Infrastructure/StringMatcher.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index f15e22494eb..6d70fff30e2 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -76,16 +76,11 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption if (currentQueryIndex >= queryWithoutCase.Length) break; - if (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) - { - acronymMatchData.Add(compareIndex); - currentQueryIndex++; - continue; - } switch (stringToCompare[compareIndex]) { - case char c when (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) + case char c when (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) + || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]): acronymMatchData.Add(compareIndex); currentQueryIndex++; From 468f8899b95d40764a941afd0eecff251ee5dc2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 18 Oct 2020 21:31:08 +0800 Subject: [PATCH 04/54] Add return statement.... --- Flow.Launcher.Infrastructure/StringMatcher.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 6d70fff30e2..d09bcaf26fd 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -96,6 +96,9 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption } } + if (acronymMatchData.Count == query.Length && acronymScore >= 60) + return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); + var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; From 4d06187fa561bad1e126d513bce15b67d1d3d114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 20 Oct 2020 08:28:05 +0800 Subject: [PATCH 05/54] use ?. and ?? instead of if == null --- Flow.Launcher.Infrastructure/StringMatcher.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index d09bcaf26fd..7b44b09c95d 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -48,11 +48,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption query = query.Trim(); - if (_alphabet != null) - { - query = _alphabet.Translate(query); - stringToCompare = _alphabet.Translate(stringToCompare); - } + stringToCompare = _alphabet?.Translate(stringToCompare) ?? stringToCompare; // This also can be done by spliting the query From 706f30a3a2c3b0aa74b67c30c0c42a41fe1fcd5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 24 Oct 2020 17:45:31 +0800 Subject: [PATCH 06/54] Add number support (treat number as part of acronuym) --- Flow.Launcher.Infrastructure/StringMatcher.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 7b44b09c95d..96391f1d6e6 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -44,8 +44,8 @@ public MatchResult FuzzyMatch(string query, string stringToCompare) /// public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption opt) { - if (string.IsNullOrEmpty(stringToCompare) || string.IsNullOrEmpty(query)) return new MatchResult (false, UserSettingSearchPrecision); - + if (string.IsNullOrEmpty(stringToCompare) || string.IsNullOrEmpty(query)) return new MatchResult(false, UserSettingSearchPrecision); + query = query.Trim(); stringToCompare = _alphabet?.Translate(stringToCompare) ?? stringToCompare; @@ -77,7 +77,8 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption { case char c when (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) - || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]): + || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]) + || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): acronymMatchData.Add(compareIndex); currentQueryIndex++; continue; @@ -86,7 +87,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption compareIndex++; acronymScore -= 10; break; - case char c when char.IsUpper(c): + case char c when char.IsUpper(c) || char.IsNumber(c): acronymScore -= 10; break; } @@ -97,7 +98,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; - + var querySubstrings = queryWithoutCase.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); int currentQuerySubstringIndex = 0; var currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; @@ -180,7 +181,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption currentQuerySubstringCharacterIndex = 0; } } - + // proceed to calculate score if every char or substring without whitespaces matched if (allQuerySubstringsMatched) { @@ -223,7 +224,7 @@ private static bool AllPreviousCharsMatched(int startIndexToVerify, int currentQ return allMatch; } - + private static List GetUpdatedIndexList(int startIndexToVerify, int currentQuerySubstringCharacterIndex, int firstMatchIndexInWord, List indexList) { var updatedList = new List(); From 1ddf83fc86d4b9a54ed93fdc8f5a359f8fb0e0b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 30 Nov 2020 11:33:31 +0800 Subject: [PATCH 07/54] Update to DotNet5 --- Flow.Launcher.Core/Flow.Launcher.Core.csproj | 4 ++-- .../Flow.Launcher.Infrastructure.csproj | 5 ++--- Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj | 6 +++--- Flow.Launcher.Test/Flow.Launcher.Test.csproj | 3 +-- Flow.Launcher/Flow.Launcher.csproj | 4 ++-- .../NetCore3.1-SelfContained.pubxml | 2 +- .../Flow.Launcher.Plugin.BrowserBookmark.csproj | 14 ++++---------- .../Flow.Launcher.Plugin.Calculator.csproj | 4 ++-- .../Flow.Launcher.Plugin.Color.csproj | 4 ++-- .../Flow.Launcher.Plugin.ControlPanel.csproj | 4 ++-- .../Flow.Launcher.Plugin.Explorer.csproj | 4 ++-- .../Flow.Launcher.Plugin.PluginIndicator.csproj | 4 ++-- .../Flow.Launcher.Plugin.PluginManagement.csproj | 4 ++-- .../Flow.Launcher.Plugin.ProcessKiller.csproj | 2 +- .../Flow.Launcher.Plugin.Program.csproj | 5 ++--- .../Flow.Launcher.Plugin.Shell.csproj | 5 ++--- .../Flow.Launcher.Plugin.Sys.csproj | 4 ++-- .../Flow.Launcher.Plugin.Url.csproj | 4 ++-- .../Flow.Launcher.Plugin.WebSearch.csproj | 14 +++----------- Scripts/flowlauncher.nuspec | 2 +- global.json | 2 +- 21 files changed, 41 insertions(+), 59 deletions(-) diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj index 9f146a457fb..370f2015bd3 100644 --- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj +++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj @@ -1,7 +1,7 @@ - + - netcoreapp3.1 + net5.0-windows true true Library diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index 28d4c0e1f6a..48d9486cf32 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -1,7 +1,6 @@ - - + - netcoreapp3.1 + net5.0-windows {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3} Library true diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj index 0f6450d1899..38ae6898fa4 100644 --- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj +++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj @@ -1,7 +1,7 @@ - - + + - netcoreapp3.1 + net5.0-windows {8451ECDD-2EA4-4966-BB0A-7BBC40138E80} true Library diff --git a/Flow.Launcher.Test/Flow.Launcher.Test.csproj b/Flow.Launcher.Test/Flow.Launcher.Test.csproj index e970c47b958..fb972d7d410 100644 --- a/Flow.Launcher.Test/Flow.Launcher.Test.csproj +++ b/Flow.Launcher.Test/Flow.Launcher.Test.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net5.0-windows10.0.19041.0 {FF742965-9A80-41A5-B042-D6C7D3A21708} Library Properties @@ -54,7 +54,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - \ No newline at end of file diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 8548ba39e5f..f959f3aa13c 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -1,8 +1,8 @@ - + WinExe - netcoreapp3.1 + net5.0-windows10.0.19041.0 true true Flow.Launcher.App diff --git a/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml index 2794a0cea1c..cad0fd46216 100644 --- a/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml +++ b/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml @@ -7,7 +7,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. FileSystem Release Any CPU - netcoreapp3.1 + net5.0-windows ..\Output\Release\ win-x64 true diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj index 85b745a6b83..ee78f78c4d2 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj @@ -1,8 +1,9 @@ - + Library - netcoreapp3.1 + net5.0-windows + true {9B130CC5-14FB-41FF-B310-0A95B6894C37} Properties Flow.Launcher.Plugin.BrowserBookmark @@ -68,14 +69,7 @@ PreserveNewest - - - - MSBuild:Compile - Designer - - - + diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj index 9e1fefdb30d..bc637be5468 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {59BD9891-3837-438A-958D-ADC7F91F6F7E} Properties Flow.Launcher.Plugin.Caculator diff --git a/Plugins/Flow.Launcher.Plugin.Color/Flow.Launcher.Plugin.Color.csproj b/Plugins/Flow.Launcher.Plugin.Color/Flow.Launcher.Plugin.Color.csproj index c7fe8271a6c..18f81e3ff4e 100644 --- a/Plugins/Flow.Launcher.Plugin.Color/Flow.Launcher.Plugin.Color.csproj +++ b/Plugins/Flow.Launcher.Plugin.Color/Flow.Launcher.Plugin.Color.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {F35190AA-4758-4D9E-A193-E3BDF6AD3567} Properties Flow.Launcher.Plugin.Color diff --git a/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj b/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj index 69973763435..be62c31cda8 100644 --- a/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj +++ b/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {1EE20B48-82FB-48A2-8086-675D6DDAB4F0} Properties Flow.Launcher.Plugin.ControlPanel 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 a1a08843a50..99e9c784b9a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows true true true diff --git a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj index e6bfa7aa396..a904a92729d 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {FDED22C8-B637-42E8-824A-63B5B6E05A3A} Properties Flow.Launcher.Plugin.PluginIndicator diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.Plugin.PluginManagement.csproj b/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.Plugin.PluginManagement.csproj index 08e89d86125..4a5df0b3a0d 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.Plugin.PluginManagement.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.Plugin.PluginManagement.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {049490F0-ECD2-4148-9B39-2135EC346EBE} Properties Flow.Launcher.Plugin.PluginManagement diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj index cf9c9629402..1aef8f58efc 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj @@ -2,7 +2,7 @@ Library - netcoreapp3.1 + net5.0-windows Flow.Launcher.Plugin.ProcessKiller Flow.Launcher.Plugin.ProcessKiller Flow-Launcher diff --git a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj index 3802297c70a..61d8b7b6cf4 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj +++ b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows10.0.19041.0 {FDB3555B-58EF-4AE6-B5F1-904719637AB4} Properties Flow.Launcher.Plugin.Program @@ -109,7 +109,6 @@ - diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj index 178d95010f7..12ee6833e53 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj +++ b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj @@ -1,8 +1,7 @@ - - + Library - netcoreapp3.1 + net5.0-windows {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} Properties Flow.Launcher.Plugin.Shell diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj index bdab40457de..6618ca77583 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj +++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {0B9DE348-9361-4940-ADB6-F5953BFFCCEC} Properties Flow.Launcher.Plugin.Sys diff --git a/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj b/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj index 7d802d81555..d5a05682570 100644 --- a/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj +++ b/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {A3DCCBCA-ACC1-421D-B16E-210896234C26} true Properties diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj index 431ca9ce802..ed2c5107c82 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj @@ -1,8 +1,8 @@ - - + Library - netcoreapp3.1 + net5.0-windows + true {403B57F2-1856-4FC7-8A24-36AB346B763E} Properties Flow.Launcher.Plugin.WebSearch @@ -119,14 +119,6 @@ Designer PreserveNewest - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - diff --git a/Scripts/flowlauncher.nuspec b/Scripts/flowlauncher.nuspec index 6c5deb86bf8..f1f58f2d18f 100644 --- a/Scripts/flowlauncher.nuspec +++ b/Scripts/flowlauncher.nuspec @@ -11,6 +11,6 @@ Flow Launcher - a launcher for windows - + diff --git a/global.json b/global.json index c3efffd4015..2ad4d91009e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "3.1.201", + "version": "5.0.100", "rollForward": "latestFeature" } } \ No newline at end of file From 3607bfde078af0f08dc4666fa1adede255e26f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 1 Dec 2020 10:37:05 +0800 Subject: [PATCH 08/54] Change name for publish file --- .../NetCore3.1-SelfContained.pubxml | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml diff --git a/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml deleted file mode 100644 index cad0fd46216..00000000000 --- a/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - FileSystem - Release - Any CPU - net5.0-windows - ..\Output\Release\ - win-x64 - true - False - False - False - - \ No newline at end of file From e973e1d0bb6b97c4e86fcac380b536bfc9464fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 2 Dec 2020 13:26:05 +0800 Subject: [PATCH 09/54] Update ModernWPF so that the app can run --- Flow.Launcher/Flow.Launcher.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index f959f3aa13c..2f58abab0d4 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -72,7 +72,7 @@ - + all From 4ea40ab9aa7907b6648315cf42e4813b96df491d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 4 Dec 2020 22:46:23 +0800 Subject: [PATCH 10/54] Add the new publish profile file --- .../PublishProfiles/Net5-SelfContained.pubxml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml diff --git a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml new file mode 100644 index 00000000000..124792e3e56 --- /dev/null +++ b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml @@ -0,0 +1,18 @@ + + + + + FileSystem + Release + Any CPU + net5.0-windows10.0.19041.0 + ..\Output\Release\ + win-x64 + true + False + False + False + + \ No newline at end of file From b7a0ada60b72b2d5c619e455d1b615ff713776d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Tue, 22 Dec 2020 21:53:59 +0800 Subject: [PATCH 11/54] Add Mapping to original string after translation. Not sure about the performance, but seems satisfying. It requires at most n times loop (n: number of translated charater) mapping once. --- .../PinyinAlphabet.cs | 81 +++++++++++++++---- Flow.Launcher.Infrastructure/StringMatcher.cs | 78 +++++++++--------- 2 files changed, 108 insertions(+), 51 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 80fd1282035..4f1aedd4ab3 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -1,21 +1,77 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using System.Text; using JetBrains.Annotations; using Flow.Launcher.Infrastructure.UserSettings; +using Microsoft.AspNetCore.Localization; using ToolGood.Words.Pinyin; namespace Flow.Launcher.Infrastructure { + public class TranslationMapping + { + private bool constructed; + + private List originalIndexs = new List(); + private List translatedIndexs = new List(); + private int translaedLength = 0; + + public void AddNewIndex(int originalIndex, int translatedIndex, int length) + { + if (constructed) + throw new InvalidOperationException("Mapping shouldn't be changed after constructed"); + + originalIndexs.Add(originalIndex); + translatedIndexs.Add(translatedIndex); + translatedIndexs.Add(translatedIndex + length); + translaedLength += length - 1; + } + + public int? MapToOriginalIndex(int translatedIndex) + { + if (translatedIndex > translatedIndexs.Last()) + return translatedIndex - translaedLength - 1; + + for (var i = 0; i < originalIndexs.Count; i++) + { + if (translatedIndex >= translatedIndexs[i * 2] && translatedIndex < translatedIndexs[i * 2 + 1]) + return originalIndexs[i]; + if (translatedIndex < translatedIndexs[i * 2]) + { + int indexDiff = 0; + for (int j = 0; j < i; j++) + { + indexDiff += translatedIndexs[i * 2 + 1] - translatedIndexs[i * 2] - 1; + } + + return translatedIndex - indexDiff; + } + } + + return translatedIndex; + } + + public void endConstruct() + { + if (constructed) + throw new InvalidOperationException("Mapping has already been constructed"); + constructed = true; + } + } + public interface IAlphabet { - string Translate(string stringToTranslate); + public (string translation, TranslationMapping map) Translate(string stringToTranslate); } public class PinyinAlphabet : IAlphabet { - private ConcurrentDictionary _pinyinCache = new ConcurrentDictionary(); + private ConcurrentDictionary _pinyinCache = + new ConcurrentDictionary(); + + private Settings _settings; public void Initialize([NotNull] Settings settings) @@ -23,7 +79,7 @@ public void Initialize([NotNull] Settings settings) _settings = settings ?? throw new ArgumentNullException(nameof(settings)); } - public string Translate(string content) + public (string translation, TranslationMapping map) Translate(string content) { if (_settings.ShouldUsePinyin) { @@ -34,14 +90,7 @@ public string Translate(string content) var resultList = WordsHelper.GetPinyinList(content); StringBuilder resultBuilder = new StringBuilder(); - - for (int i = 0; i < resultList.Length; i++) - { - if (content[i] >= 0x3400 && content[i] <= 0x9FD5) - resultBuilder.Append(resultList[i].First()); - } - - resultBuilder.Append(' '); + TranslationMapping map = new TranslationMapping(); bool pre = false; @@ -49,6 +98,7 @@ public string Translate(string content) { if (content[i] >= 0x3400 && content[i] <= 0x9FD5) { + map.AddNewIndex(i, resultBuilder.Length, resultList[i].Length + 1); resultBuilder.Append(' '); resultBuilder.Append(resultList[i]); pre = true; @@ -60,15 +110,18 @@ public string Translate(string content) pre = false; resultBuilder.Append(' '); } + resultBuilder.Append(resultList[i]); } } - return _pinyinCache[content] = resultBuilder.ToString(); + map.endConstruct(); + + return _pinyinCache[content] = (resultBuilder.ToString(), map); } else { - return content; + return (content, null); } } else @@ -78,7 +131,7 @@ public string Translate(string content) } else { - return content; + return (content, null); } } } diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 96391f1d6e6..e885798b789 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -44,22 +44,12 @@ public MatchResult FuzzyMatch(string query, string stringToCompare) /// public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption opt) { - if (string.IsNullOrEmpty(stringToCompare) || string.IsNullOrEmpty(query)) return new MatchResult(false, UserSettingSearchPrecision); + if (string.IsNullOrEmpty(stringToCompare) || string.IsNullOrEmpty(query)) + return new MatchResult(false, UserSettingSearchPrecision); query = query.Trim(); - - stringToCompare = _alphabet?.Translate(stringToCompare) ?? stringToCompare; - - // This also can be done by spliting the query - - //(var spaceSplit, var upperSplit) = stringToCompare switch - //{ - // string s when s.Contains(' ') => (s.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(w => w.First()), - // default(IEnumerable)), - // string s when s.Any(c => char.IsUpper(c)) && s.Any(c => char.IsLower(c)) => - // (null, Regex.Split(s, @"(? w.First())), - // _ => ((IEnumerable)null, (IEnumerable)null) - //}; + TranslationMapping map; + (stringToCompare, map) = _alphabet?.Translate(stringToCompare) ?? (stringToCompare, null); var currentQueryIndex = 0; var acronymMatchData = new List(); @@ -75,19 +65,21 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption switch (stringToCompare[compareIndex]) { - case char c when (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) - || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) - || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]) - || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): - acronymMatchData.Add(compareIndex); + case var c when (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == + char.ToLower(stringToCompare[compareIndex])) + || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) + || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == + queryWithoutCase[currentQueryIndex]) + || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): + acronymMatchData.Add(map?.MapToOriginalIndex(compareIndex) ?? compareIndex); currentQueryIndex++; continue; - case char c when char.IsWhiteSpace(c): + case var c when char.IsWhiteSpace(c): compareIndex++; acronymScore -= 10; break; - case char c when char.IsUpper(c) || char.IsNumber(c): + case var c when char.IsUpper(c) || char.IsNumber(c): acronymScore -= 10; break; } @@ -99,7 +91,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; - var querySubstrings = queryWithoutCase.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + var querySubstrings = queryWithoutCase.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); int currentQuerySubstringIndex = 0; var currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; var currentQuerySubstringCharacterIndex = 0; @@ -114,9 +106,10 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var indexList = new List(); List spaceIndices = new List(); - for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++) + for (var compareStringIndex = 0; + compareStringIndex < fullStringToCompareWithoutCase.Length; + compareStringIndex++) { - // To maintain a list of indices which correspond to spaces in the string to compare // To populate the list only for the first query substring if (fullStringToCompareWithoutCase[compareStringIndex].Equals(' ') && currentQuerySubstringIndex == 0) @@ -124,7 +117,8 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption spaceIndices.Add(compareStringIndex); } - if (fullStringToCompareWithoutCase[compareStringIndex] != currentQuerySubstring[currentQuerySubstringCharacterIndex]) + if (fullStringToCompareWithoutCase[compareStringIndex] != + currentQuerySubstring[currentQuerySubstringCharacterIndex]) { matchFoundInPreviousLoop = false; continue; @@ -148,14 +142,16 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption // in order to do so we need to verify all previous chars are part of the pattern var startIndexToVerify = compareStringIndex - currentQuerySubstringCharacterIndex; - if (AllPreviousCharsMatched(startIndexToVerify, currentQuerySubstringCharacterIndex, fullStringToCompareWithoutCase, currentQuerySubstring)) + if (AllPreviousCharsMatched(startIndexToVerify, currentQuerySubstringCharacterIndex, + fullStringToCompareWithoutCase, currentQuerySubstring)) { matchFoundInPreviousLoop = true; // if it's the beginning character of the first query substring that is matched then we need to update start index firstMatchIndex = currentQuerySubstringIndex == 0 ? startIndexToVerify : firstMatchIndex; - indexList = GetUpdatedIndexList(startIndexToVerify, currentQuerySubstringCharacterIndex, firstMatchIndexInWord, indexList); + indexList = GetUpdatedIndexList(startIndexToVerify, currentQuerySubstringCharacterIndex, + firstMatchIndexInWord, indexList); } } @@ -168,11 +164,13 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption if (currentQuerySubstringCharacterIndex == currentQuerySubstring.Length) { // if any of the substrings was not matched then consider as all are not matched - allSubstringsContainedInCompareString = matchFoundInPreviousLoop && allSubstringsContainedInCompareString; + allSubstringsContainedInCompareString = + matchFoundInPreviousLoop && allSubstringsContainedInCompareString; currentQuerySubstringIndex++; - allQuerySubstringsMatched = AllQuerySubstringsMatched(currentQuerySubstringIndex, querySubstrings.Length); + allQuerySubstringsMatched = + AllQuerySubstringsMatched(currentQuerySubstringIndex, querySubstrings.Length); if (allQuerySubstringsMatched) break; @@ -182,13 +180,16 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption } } + // proceed to calculate score if every char or substring without whitespaces matched if (allQuerySubstringsMatched) { var nearestSpaceIndex = CalculateClosestSpaceIndex(spaceIndices, firstMatchIndex); - var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString); + var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, + lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString); - return new MatchResult(true, UserSettingSearchPrecision, indexList, score); + var resultList = indexList.Distinct().Select(x => map?.MapToOriginalIndex(x) ?? x).ToList(); + return new MatchResult(true, UserSettingSearchPrecision, resultList, score); } return new MatchResult(false, UserSettingSearchPrecision); @@ -203,14 +204,15 @@ private int CalculateClosestSpaceIndex(List spaceIndices, int firstMatchInd } else { - int? ind = spaceIndices.OrderBy(item => (firstMatchIndex - item)).Where(item => firstMatchIndex > item).FirstOrDefault(); + int? ind = spaceIndices.OrderBy(item => (firstMatchIndex - item)) + .FirstOrDefault(item => firstMatchIndex > item); int closestSpaceIndex = ind ?? -1; return closestSpaceIndex; } } private static bool AllPreviousCharsMatched(int startIndexToVerify, int currentQuerySubstringCharacterIndex, - string fullStringToCompareWithoutCase, string currentQuerySubstring) + string fullStringToCompareWithoutCase, string currentQuerySubstring) { var allMatch = true; for (int indexToCheck = 0; indexToCheck < currentQuerySubstringCharacterIndex; indexToCheck++) @@ -225,7 +227,8 @@ private static bool AllPreviousCharsMatched(int startIndexToVerify, int currentQ return allMatch; } - private static List GetUpdatedIndexList(int startIndexToVerify, int currentQuerySubstringCharacterIndex, int firstMatchIndexInWord, List indexList) + private static List GetUpdatedIndexList(int startIndexToVerify, int currentQuerySubstringCharacterIndex, + int firstMatchIndexInWord, List indexList) { var updatedList = new List(); @@ -246,7 +249,8 @@ private static bool AllQuerySubstringsMatched(int currentQuerySubstringIndex, in return currentQuerySubstringIndex >= querySubstringsLength; } - private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, bool allSubstringsContainedInCompareString) + private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, + bool allSubstringsContainedInCompareString) { // A match found near the beginning of a string is scored more than a match found near the end // A match is scored more if the characters in the patterns are closer to each other, @@ -341,7 +345,7 @@ public bool IsSearchPrecisionScoreMet() private bool IsSearchPrecisionScoreMet(int rawScore) { - return rawScore >= (int)SearchPrecision; + return rawScore >= (int) SearchPrecision; } private int ScoreAfterSearchPrecisionFilter(int rawScore) @@ -354,4 +358,4 @@ public class MatchOption { public bool IgnoreCase { get; set; } = true; } -} +} \ No newline at end of file From 2c9f4149b7cbd0d86fd46e07f2fa2509917e67f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Tue, 22 Dec 2020 22:58:27 +0800 Subject: [PATCH 12/54] optimize use --- Flow.Launcher.Infrastructure/StringMatcher.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index e885798b789..22334c4bdfc 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -71,7 +71,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]) || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): - acronymMatchData.Add(map?.MapToOriginalIndex(compareIndex) ?? compareIndex); + acronymMatchData.Add(compareIndex); currentQueryIndex++; continue; @@ -86,7 +86,10 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption } if (acronymMatchData.Count == query.Length && acronymScore >= 60) + { + acronymMatchData = acronymMatchData.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); + } var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; @@ -188,7 +191,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString); - var resultList = indexList.Distinct().Select(x => map?.MapToOriginalIndex(x) ?? x).ToList(); + var resultList = indexList.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); return new MatchResult(true, UserSettingSearchPrecision, resultList, score); } From 75b99415eb90f4ee7f8c5a30fedef4f785480cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 26 Dec 2020 00:29:35 +0800 Subject: [PATCH 13/54] Use Binary Search instead of Linear search to reduce time complexity. Add Key Property for debugging. --- .../PinyinAlphabet.cs | 70 +++++++++++++++---- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 4f1aedd4ab3..be3c58f6618 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -18,6 +18,13 @@ public class TranslationMapping private List translatedIndexs = new List(); private int translaedLength = 0; + public string key { get; private set; } + + public void setKey(string key) + { + this.key = key; + } + public void AddNewIndex(int originalIndex, int translatedIndex, int length) { if (constructed) @@ -29,28 +36,64 @@ public void AddNewIndex(int originalIndex, int translatedIndex, int length) translaedLength += length - 1; } - public int? MapToOriginalIndex(int translatedIndex) + public int MapToOriginalIndex(int translatedIndex) { if (translatedIndex > translatedIndexs.Last()) return translatedIndex - translaedLength - 1; - - for (var i = 0; i < originalIndexs.Count; i++) + + int lowerBound = 0; + int upperBound = originalIndexs.Count - 1; + + int count = 0; + + + // Corner case handle + if (translatedIndex < translatedIndexs[0]) + return translatedIndex; + if (translatedIndex > translatedIndexs.Last()) + { + int indexDef = 0; + for (int k = 0; k < originalIndexs.Count; k++) + { + indexDef += translatedIndexs[k * 2 + 1] - translatedIndexs[k * 2]; + } + + return translatedIndex - indexDef - 1; + } + + // Binary Search with Range + for (int i = originalIndexs.Count / 2;; count++) { - if (translatedIndex >= translatedIndexs[i * 2] && translatedIndex < translatedIndexs[i * 2 + 1]) - return originalIndexs[i]; if (translatedIndex < translatedIndexs[i * 2]) { - int indexDiff = 0; - for (int j = 0; j < i; j++) + // move to lower middle + upperBound = i; + i = (i + lowerBound) / 2; + } + else if (translatedIndex > translatedIndexs[i * 2 + 1] - 1) + { + lowerBound = i; + // move to upper middle + // due to floor of integer division, move one up on corner case + i = (i + upperBound + 1) / 2; + } + else + return originalIndexs[i]; + + if (upperBound - lowerBound <= 1 && + translatedIndex > translatedIndexs[lowerBound * 2 + 1] && + translatedIndex < translatedIndexs[upperBound * 2]) + { + int indexDef = 0; + + for (int j = 0; j < upperBound; j++) { - indexDiff += translatedIndexs[i * 2 + 1] - translatedIndexs[i * 2] - 1; + indexDef += translatedIndexs[j * 2 + 1] - translatedIndexs[j * 2]; } - return translatedIndex - indexDiff; + return translatedIndex - indexDef - 1; } } - - return translatedIndex; } public void endConstruct() @@ -117,7 +160,10 @@ public void Initialize([NotNull] Settings settings) map.endConstruct(); - return _pinyinCache[content] = (resultBuilder.ToString(), map); + var key = resultBuilder.ToString(); + map.setKey(key); + + return _pinyinCache[content] = (key, map); } else { From 7ceb08071c6086f39911f1ff2c920e160267d41e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sun, 27 Dec 2020 20:16:20 +0800 Subject: [PATCH 14/54] Use inner loop to evaluate acronym match (Big Change) Don't end loop before acronym match end since if acronym match exist, we will use that one. --- Flow.Launcher.Infrastructure/StringMatcher.cs | 99 ++++++++++++------- 1 file changed, 61 insertions(+), 38 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 22334c4bdfc..7ade76cdfe0 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -51,46 +51,13 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption TranslationMapping map; (stringToCompare, map) = _alphabet?.Translate(stringToCompare) ?? (stringToCompare, null); - var currentQueryIndex = 0; + var currentAcronymQueryIndex = 0; var acronymMatchData = new List(); var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; + // preset acronymScore int acronymScore = 100; - for (int compareIndex = 0; compareIndex < stringToCompare.Length; compareIndex++) - { - if (currentQueryIndex >= queryWithoutCase.Length) - break; - - - switch (stringToCompare[compareIndex]) - { - case var c when (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == - char.ToLower(stringToCompare[compareIndex])) - || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) - || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == - queryWithoutCase[currentQueryIndex]) - || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): - acronymMatchData.Add(compareIndex); - currentQueryIndex++; - continue; - - case var c when char.IsWhiteSpace(c): - compareIndex++; - acronymScore -= 10; - break; - case var c when char.IsUpper(c) || char.IsNumber(c): - acronymScore -= 10; - break; - } - } - - if (acronymMatchData.Count == query.Length && acronymScore >= 60) - { - acronymMatchData = acronymMatchData.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); - return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); - } - var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; @@ -109,24 +76,72 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var indexList = new List(); List spaceIndices = new List(); + bool spaceMet = false; + for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++) { + if (currentAcronymQueryIndex >= queryWithoutCase.Length + || allQuerySubstringsMatched && acronymScore < (int) UserSettingSearchPrecision) + break; + + // To maintain a list of indices which correspond to spaces in the string to compare // To populate the list only for the first query substring - if (fullStringToCompareWithoutCase[compareStringIndex].Equals(' ') && currentQuerySubstringIndex == 0) + if (fullStringToCompareWithoutCase[compareStringIndex] == ' ' && currentQuerySubstringIndex == 0) { spaceIndices.Add(compareStringIndex); } - if (fullStringToCompareWithoutCase[compareStringIndex] != + // Acronym check + if (char.IsUpper(stringToCompare[compareStringIndex]) || + char.IsNumber(stringToCompare[compareStringIndex]) || + char.IsWhiteSpace(stringToCompare[compareStringIndex]) || + spaceMet) + { + if (fullStringToCompareWithoutCase[compareStringIndex] == + queryWithoutCase[currentAcronymQueryIndex]) + { + currentAcronymQueryIndex++; + + if (!spaceMet) + { + char currentCompareChar = stringToCompare[compareStringIndex]; + spaceMet = char.IsWhiteSpace(currentCompareChar); + // if is space, no need to check whether upper or digit, though insignificant + if (!spaceMet && compareStringIndex == 0 || char.IsUpper(currentCompareChar) || + char.IsDigit(currentCompareChar)) + { + acronymMatchData.Add(compareStringIndex); + } + } + else if (!(spaceMet = char.IsWhiteSpace(stringToCompare[compareStringIndex]))) + { + acronymMatchData.Add(compareStringIndex); + } + } + else + { + spaceMet = char.IsWhiteSpace(stringToCompare[compareStringIndex]); + // Acronym Penalty + if (!spaceMet) + { + acronymScore -= 10; + } + } + } + // Acronym end + + if (allQuerySubstringsMatched || fullStringToCompareWithoutCase[compareStringIndex] != currentQuerySubstring[currentQuerySubstringCharacterIndex]) { matchFoundInPreviousLoop = false; + continue; } + if (firstMatchIndex < 0) { // first matched char will become the start of the compared string @@ -174,8 +189,9 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption allQuerySubstringsMatched = AllQuerySubstringsMatched(currentQuerySubstringIndex, querySubstrings.Length); + if (allQuerySubstringsMatched) - break; + continue; // otherwise move to the next query substring currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; @@ -183,6 +199,12 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption } } + // return acronym Match if possible + if (acronymMatchData.Count == query.Length && acronymScore >= (int) UserSettingSearchPrecision) + { + acronymMatchData = acronymMatchData.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); + return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); + } // proceed to calculate score if every char or substring without whitespaces matched if (allQuerySubstringsMatched) @@ -249,6 +271,7 @@ private static List GetUpdatedIndexList(int startIndexToVerify, int current private static bool AllQuerySubstringsMatched(int currentQuerySubstringIndex, int querySubstringsLength) { + // Acronym won't utilize the substring to match return currentQuerySubstringIndex >= querySubstringsLength; } From 494312a251b03d8870e937ab3bc03f0d0936b342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 9 Jan 2021 11:04:36 +0800 Subject: [PATCH 15/54] Merge dev --- .../Flow.Launcher.Plugin.PluginsManager.csproj | 2 +- .../Flow.Launcher.Plugin.Shell.csproj | 5 +---- .../Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj | 5 +---- 3 files changed, 3 insertions(+), 9 deletions(-) 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 2e352d83217..d6ca96b46b6 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj @@ -2,7 +2,7 @@ Library - netcoreapp3.1 + net5.0-windows true true true diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj index d19c41cb203..daae28cf657 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj +++ b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj @@ -7,6 +7,7 @@ Flow.Launcher.Plugin.Shell Flow.Launcher.Plugin.Shell true + true true false false @@ -53,10 +54,6 @@ PreserveNewest - - MSBuild:Compile - Designer - diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj index 1bc5230e763..894d50cea30 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj +++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj @@ -8,6 +8,7 @@ Flow.Launcher.Plugin.Sys Flow.Launcher.Plugin.Sys true + true true false false @@ -48,10 +49,6 @@ PreserveNewest - - MSBuild:Compile - Designer - From dd074f41cfd07138b2e14907198c0178df97ca95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 9 Jan 2021 11:30:11 +0800 Subject: [PATCH 16/54] change publish profile to Net5 one --- Scripts/post_build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1 index b08fac8f67f..58d5c6a4ecd 100644 --- a/Scripts/post_build.ps1 +++ b/Scripts/post_build.ps1 @@ -90,7 +90,7 @@ function Pack-Squirrel-Installer ($path, $version, $output) { function Publish-Self-Contained ($p) { $csproj = Join-Path "$p" "Flow.Launcher/Flow.Launcher.csproj" -Resolve - $profile = Join-Path "$p" "Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml" -Resolve + $profile = Join-Path "$p" "Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml" -Resolve # we call dotnet publish on the main project. # The other projects should have been built in Release at this point. From a626e7b6ee8133d2f06cc01ad2467d49013d0b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 9 Jan 2021 11:30:19 +0800 Subject: [PATCH 17/54] try trim --- .../Properties/PublishProfiles/Net5-SelfContained.pubxml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml index 124792e3e56..f2f969aa723 100644 --- a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml +++ b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml @@ -13,6 +13,6 @@ https://go.microsoft.com/fwlink/?LinkID=208121. true False False - False + True \ No newline at end of file From 0fc9f64e8584a44e7d88f8d6579a7759bf3f44fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 9 Jan 2021 12:05:55 +0800 Subject: [PATCH 18/54] image not found issue in build --- Flow.Launcher/Flow.Launcher.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index a269425afa4..a4d2634e0a6 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -60,7 +60,7 @@ Designer PreserveNewest - + PreserveNewest From 94a047786e3cc59506b43038abe6a1a27fd2d5f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 13 Jan 2021 07:35:48 +0800 Subject: [PATCH 19/54] fix merge issue of result update event --- Flow.Launcher/ViewModel/MainViewModel.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 68c42767263..9dea039a13f 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -122,14 +122,14 @@ private void RegisterResultsUpdatedEvent() { foreach (var pair in PluginManager.GetPluginsForInterface()) { - var plugin = (IResultUpdated) pair.Plugin; + var plugin = (IResultUpdated)pair.Plugin; plugin.ResultsUpdated += (s, e) => { - Task.Run(() => + if (e.Query.RawQuery == QueryText) // TODO: allow cancellation { PluginManager.UpdatePluginMetadata(e.Results, pair.Metadata, e.Query); - UpdateResultView(e.Results, pair.Metadata, e.Query); - }, _updateToken); + _resultsUpdateQueue.Post(new ResultsForUpdate(e.Results, pair.Metadata, e.Query, _updateToken)); + } }; } } @@ -379,7 +379,7 @@ private void QueryHistory() Title = string.Format(title, h.Query), SubTitle = string.Format(time, h.ExecutedDateTime), IcoPath = "Images\\history.png", - OriginQuery = new Query {RawQuery = h.Query}, + OriginQuery = new Query { RawQuery = h.Query }, Action = _ => { SelectedResults = Results; From a4c11df204663c33bb650e70452eff29bb18b9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 14 Jan 2021 10:24:44 +0800 Subject: [PATCH 20/54] use ready to run --- .../Properties/PublishProfiles/Net5-SelfContained.pubxml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml index f2f969aa723..3c5dcc8b23c 100644 --- a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml +++ b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml @@ -12,7 +12,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. win-x64 true False - False - True + True + False \ No newline at end of file From f14da72ce1332d1c2fabc38f9f013d12d6bf677e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 18 Oct 2020 21:17:29 +0800 Subject: [PATCH 21/54] Add Acronym Support for Fuzzy Search --- Flow.Launcher.Infrastructure/StringMatcher.cs | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 2a4270fb4b2..f15e22494eb 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -54,9 +54,55 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption stringToCompare = _alphabet.Translate(stringToCompare); } + // This also can be done by spliting the query + + //(var spaceSplit, var upperSplit) = stringToCompare switch + //{ + // string s when s.Contains(' ') => (s.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(w => w.First()), + // default(IEnumerable)), + // string s when s.Any(c => char.IsUpper(c)) && s.Any(c => char.IsLower(c)) => + // (null, Regex.Split(s, @"(? w.First())), + // _ => ((IEnumerable)null, (IEnumerable)null) + //}; + + var currentQueryIndex = 0; + var acronymMatchData = new List(); + var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; + + int acronymScore = 100; + + for (int compareIndex = 0; compareIndex < stringToCompare.Length; compareIndex++) + { + if (currentQueryIndex >= queryWithoutCase.Length) + break; + + if (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) + { + acronymMatchData.Add(compareIndex); + currentQueryIndex++; + continue; + } + + switch (stringToCompare[compareIndex]) + { + case char c when (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) + || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]): + acronymMatchData.Add(compareIndex); + currentQueryIndex++; + continue; + + case char c when char.IsWhiteSpace(c): + compareIndex++; + acronymScore -= 10; + break; + case char c when char.IsUpper(c): + acronymScore -= 10; + break; + } + } + var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; - var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; var querySubstrings = queryWithoutCase.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); int currentQuerySubstringIndex = 0; From ab9e6a814326557ab499e810a5386c737175e81d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 18 Oct 2020 21:24:59 +0800 Subject: [PATCH 22/54] merge one extra condition to the switch case --- Flow.Launcher.Infrastructure/StringMatcher.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index f15e22494eb..6d70fff30e2 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -76,16 +76,11 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption if (currentQueryIndex >= queryWithoutCase.Length) break; - if (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) - { - acronymMatchData.Add(compareIndex); - currentQueryIndex++; - continue; - } switch (stringToCompare[compareIndex]) { - case char c when (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) + case char c when (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) + || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]): acronymMatchData.Add(compareIndex); currentQueryIndex++; From b07490271d74b6ea264a7015fa06af72870ab285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 18 Oct 2020 21:24:59 +0800 Subject: [PATCH 23/54] merge one extra condition to the switch case --- Flow.Launcher.Infrastructure/StringMatcher.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 6d70fff30e2..438988d63c8 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -76,10 +76,16 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption if (currentQueryIndex >= queryWithoutCase.Length) break; + if (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) + { + acronymMatchData.Add(compareIndex); + currentQueryIndex++; + continue; + } switch (stringToCompare[compareIndex]) { - case char c when (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) + case char c when compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex]) || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]): acronymMatchData.Add(compareIndex); From 272f411f81948020ec2d59daa2d4c61fe7654b48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 18 Oct 2020 21:31:08 +0800 Subject: [PATCH 24/54] Add return statement.... --- Flow.Launcher.Infrastructure/StringMatcher.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 438988d63c8..20b023d0623 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -102,6 +102,9 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption } } + if (acronymMatchData.Count == query.Length && acronymScore >= 60) + return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); + var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; From 787e569604c293cd08232d78836195febb5e9ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 20 Oct 2020 08:28:05 +0800 Subject: [PATCH 25/54] use ?. and ?? instead of if == null --- Flow.Launcher.Infrastructure/StringMatcher.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 20b023d0623..d0be4c41e5a 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -48,11 +48,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption query = query.Trim(); - if (_alphabet != null) - { - query = _alphabet.Translate(query); - stringToCompare = _alphabet.Translate(stringToCompare); - } + stringToCompare = _alphabet?.Translate(stringToCompare) ?? stringToCompare; // This also can be done by spliting the query From 8a76ad000d9ecd1953242a87b10e6e17e6dd7287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 24 Oct 2020 17:45:31 +0800 Subject: [PATCH 26/54] Add number support (treat number as part of acronuym) --- Flow.Launcher.Infrastructure/StringMatcher.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index d0be4c41e5a..1a6ff47a7c8 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -44,8 +44,8 @@ public MatchResult FuzzyMatch(string query, string stringToCompare) /// public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption opt) { - if (string.IsNullOrEmpty(stringToCompare) || string.IsNullOrEmpty(query)) return new MatchResult (false, UserSettingSearchPrecision); - + if (string.IsNullOrEmpty(stringToCompare) || string.IsNullOrEmpty(query)) return new MatchResult(false, UserSettingSearchPrecision); + query = query.Trim(); stringToCompare = _alphabet?.Translate(stringToCompare) ?? stringToCompare; @@ -83,7 +83,8 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption { case char c when compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex]) || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) - || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]): + || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]) + || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): acronymMatchData.Add(compareIndex); currentQueryIndex++; continue; @@ -92,7 +93,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption compareIndex++; acronymScore -= 10; break; - case char c when char.IsUpper(c): + case char c when char.IsUpper(c) || char.IsNumber(c): acronymScore -= 10; break; } @@ -103,7 +104,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; - + var querySubstrings = queryWithoutCase.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); int currentQuerySubstringIndex = 0; var currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; @@ -186,7 +187,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption currentQuerySubstringCharacterIndex = 0; } } - + // proceed to calculate score if every char or substring without whitespaces matched if (allQuerySubstringsMatched) { @@ -229,7 +230,7 @@ private static bool AllPreviousCharsMatched(int startIndexToVerify, int currentQ return allMatch; } - + private static List GetUpdatedIndexList(int startIndexToVerify, int currentQuerySubstringCharacterIndex, int firstMatchIndexInWord, List indexList) { var updatedList = new List(); From 59e61cebe38f45918fc8df73882f8691430be564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Tue, 22 Dec 2020 21:53:59 +0800 Subject: [PATCH 27/54] Add Mapping to original string after translation. Not sure about the performance, but seems satisfying. It requires at most n times loop (n: number of translated charater) mapping once. --- .../PinyinAlphabet.cs | 81 ++++++++++++++---- Flow.Launcher.Infrastructure/StringMatcher.cs | 84 +++++++++---------- 2 files changed, 108 insertions(+), 57 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 80fd1282035..4f1aedd4ab3 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -1,21 +1,77 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using System.Text; using JetBrains.Annotations; using Flow.Launcher.Infrastructure.UserSettings; +using Microsoft.AspNetCore.Localization; using ToolGood.Words.Pinyin; namespace Flow.Launcher.Infrastructure { + public class TranslationMapping + { + private bool constructed; + + private List originalIndexs = new List(); + private List translatedIndexs = new List(); + private int translaedLength = 0; + + public void AddNewIndex(int originalIndex, int translatedIndex, int length) + { + if (constructed) + throw new InvalidOperationException("Mapping shouldn't be changed after constructed"); + + originalIndexs.Add(originalIndex); + translatedIndexs.Add(translatedIndex); + translatedIndexs.Add(translatedIndex + length); + translaedLength += length - 1; + } + + public int? MapToOriginalIndex(int translatedIndex) + { + if (translatedIndex > translatedIndexs.Last()) + return translatedIndex - translaedLength - 1; + + for (var i = 0; i < originalIndexs.Count; i++) + { + if (translatedIndex >= translatedIndexs[i * 2] && translatedIndex < translatedIndexs[i * 2 + 1]) + return originalIndexs[i]; + if (translatedIndex < translatedIndexs[i * 2]) + { + int indexDiff = 0; + for (int j = 0; j < i; j++) + { + indexDiff += translatedIndexs[i * 2 + 1] - translatedIndexs[i * 2] - 1; + } + + return translatedIndex - indexDiff; + } + } + + return translatedIndex; + } + + public void endConstruct() + { + if (constructed) + throw new InvalidOperationException("Mapping has already been constructed"); + constructed = true; + } + } + public interface IAlphabet { - string Translate(string stringToTranslate); + public (string translation, TranslationMapping map) Translate(string stringToTranslate); } public class PinyinAlphabet : IAlphabet { - private ConcurrentDictionary _pinyinCache = new ConcurrentDictionary(); + private ConcurrentDictionary _pinyinCache = + new ConcurrentDictionary(); + + private Settings _settings; public void Initialize([NotNull] Settings settings) @@ -23,7 +79,7 @@ public void Initialize([NotNull] Settings settings) _settings = settings ?? throw new ArgumentNullException(nameof(settings)); } - public string Translate(string content) + public (string translation, TranslationMapping map) Translate(string content) { if (_settings.ShouldUsePinyin) { @@ -34,14 +90,7 @@ public string Translate(string content) var resultList = WordsHelper.GetPinyinList(content); StringBuilder resultBuilder = new StringBuilder(); - - for (int i = 0; i < resultList.Length; i++) - { - if (content[i] >= 0x3400 && content[i] <= 0x9FD5) - resultBuilder.Append(resultList[i].First()); - } - - resultBuilder.Append(' '); + TranslationMapping map = new TranslationMapping(); bool pre = false; @@ -49,6 +98,7 @@ public string Translate(string content) { if (content[i] >= 0x3400 && content[i] <= 0x9FD5) { + map.AddNewIndex(i, resultBuilder.Length, resultList[i].Length + 1); resultBuilder.Append(' '); resultBuilder.Append(resultList[i]); pre = true; @@ -60,15 +110,18 @@ public string Translate(string content) pre = false; resultBuilder.Append(' '); } + resultBuilder.Append(resultList[i]); } } - return _pinyinCache[content] = resultBuilder.ToString(); + map.endConstruct(); + + return _pinyinCache[content] = (resultBuilder.ToString(), map); } else { - return content; + return (content, null); } } else @@ -78,7 +131,7 @@ public string Translate(string content) } else { - return content; + return (content, null); } } } diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 1a6ff47a7c8..e885798b789 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -44,22 +44,12 @@ public MatchResult FuzzyMatch(string query, string stringToCompare) /// public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption opt) { - if (string.IsNullOrEmpty(stringToCompare) || string.IsNullOrEmpty(query)) return new MatchResult(false, UserSettingSearchPrecision); + if (string.IsNullOrEmpty(stringToCompare) || string.IsNullOrEmpty(query)) + return new MatchResult(false, UserSettingSearchPrecision); query = query.Trim(); - - stringToCompare = _alphabet?.Translate(stringToCompare) ?? stringToCompare; - - // This also can be done by spliting the query - - //(var spaceSplit, var upperSplit) = stringToCompare switch - //{ - // string s when s.Contains(' ') => (s.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(w => w.First()), - // default(IEnumerable)), - // string s when s.Any(c => char.IsUpper(c)) && s.Any(c => char.IsLower(c)) => - // (null, Regex.Split(s, @"(? w.First())), - // _ => ((IEnumerable)null, (IEnumerable)null) - //}; + TranslationMapping map; + (stringToCompare, map) = _alphabet?.Translate(stringToCompare) ?? (stringToCompare, null); var currentQueryIndex = 0; var acronymMatchData = new List(); @@ -72,28 +62,24 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption if (currentQueryIndex >= queryWithoutCase.Length) break; - if (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) - { - acronymMatchData.Add(compareIndex); - currentQueryIndex++; - continue; - } switch (stringToCompare[compareIndex]) { - case char c when compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex]) - || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) - || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]) - || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): - acronymMatchData.Add(compareIndex); + case var c when (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == + char.ToLower(stringToCompare[compareIndex])) + || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) + || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == + queryWithoutCase[currentQueryIndex]) + || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): + acronymMatchData.Add(map?.MapToOriginalIndex(compareIndex) ?? compareIndex); currentQueryIndex++; continue; - case char c when char.IsWhiteSpace(c): + case var c when char.IsWhiteSpace(c): compareIndex++; acronymScore -= 10; break; - case char c when char.IsUpper(c) || char.IsNumber(c): + case var c when char.IsUpper(c) || char.IsNumber(c): acronymScore -= 10; break; } @@ -105,7 +91,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; - var querySubstrings = queryWithoutCase.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + var querySubstrings = queryWithoutCase.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); int currentQuerySubstringIndex = 0; var currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; var currentQuerySubstringCharacterIndex = 0; @@ -120,9 +106,10 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var indexList = new List(); List spaceIndices = new List(); - for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++) + for (var compareStringIndex = 0; + compareStringIndex < fullStringToCompareWithoutCase.Length; + compareStringIndex++) { - // To maintain a list of indices which correspond to spaces in the string to compare // To populate the list only for the first query substring if (fullStringToCompareWithoutCase[compareStringIndex].Equals(' ') && currentQuerySubstringIndex == 0) @@ -130,7 +117,8 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption spaceIndices.Add(compareStringIndex); } - if (fullStringToCompareWithoutCase[compareStringIndex] != currentQuerySubstring[currentQuerySubstringCharacterIndex]) + if (fullStringToCompareWithoutCase[compareStringIndex] != + currentQuerySubstring[currentQuerySubstringCharacterIndex]) { matchFoundInPreviousLoop = false; continue; @@ -154,14 +142,16 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption // in order to do so we need to verify all previous chars are part of the pattern var startIndexToVerify = compareStringIndex - currentQuerySubstringCharacterIndex; - if (AllPreviousCharsMatched(startIndexToVerify, currentQuerySubstringCharacterIndex, fullStringToCompareWithoutCase, currentQuerySubstring)) + if (AllPreviousCharsMatched(startIndexToVerify, currentQuerySubstringCharacterIndex, + fullStringToCompareWithoutCase, currentQuerySubstring)) { matchFoundInPreviousLoop = true; // if it's the beginning character of the first query substring that is matched then we need to update start index firstMatchIndex = currentQuerySubstringIndex == 0 ? startIndexToVerify : firstMatchIndex; - indexList = GetUpdatedIndexList(startIndexToVerify, currentQuerySubstringCharacterIndex, firstMatchIndexInWord, indexList); + indexList = GetUpdatedIndexList(startIndexToVerify, currentQuerySubstringCharacterIndex, + firstMatchIndexInWord, indexList); } } @@ -174,11 +164,13 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption if (currentQuerySubstringCharacterIndex == currentQuerySubstring.Length) { // if any of the substrings was not matched then consider as all are not matched - allSubstringsContainedInCompareString = matchFoundInPreviousLoop && allSubstringsContainedInCompareString; + allSubstringsContainedInCompareString = + matchFoundInPreviousLoop && allSubstringsContainedInCompareString; currentQuerySubstringIndex++; - allQuerySubstringsMatched = AllQuerySubstringsMatched(currentQuerySubstringIndex, querySubstrings.Length); + allQuerySubstringsMatched = + AllQuerySubstringsMatched(currentQuerySubstringIndex, querySubstrings.Length); if (allQuerySubstringsMatched) break; @@ -188,13 +180,16 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption } } + // proceed to calculate score if every char or substring without whitespaces matched if (allQuerySubstringsMatched) { var nearestSpaceIndex = CalculateClosestSpaceIndex(spaceIndices, firstMatchIndex); - var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString); + var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, + lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString); - return new MatchResult(true, UserSettingSearchPrecision, indexList, score); + var resultList = indexList.Distinct().Select(x => map?.MapToOriginalIndex(x) ?? x).ToList(); + return new MatchResult(true, UserSettingSearchPrecision, resultList, score); } return new MatchResult(false, UserSettingSearchPrecision); @@ -209,14 +204,15 @@ private int CalculateClosestSpaceIndex(List spaceIndices, int firstMatchInd } else { - int? ind = spaceIndices.OrderBy(item => (firstMatchIndex - item)).Where(item => firstMatchIndex > item).FirstOrDefault(); + int? ind = spaceIndices.OrderBy(item => (firstMatchIndex - item)) + .FirstOrDefault(item => firstMatchIndex > item); int closestSpaceIndex = ind ?? -1; return closestSpaceIndex; } } private static bool AllPreviousCharsMatched(int startIndexToVerify, int currentQuerySubstringCharacterIndex, - string fullStringToCompareWithoutCase, string currentQuerySubstring) + string fullStringToCompareWithoutCase, string currentQuerySubstring) { var allMatch = true; for (int indexToCheck = 0; indexToCheck < currentQuerySubstringCharacterIndex; indexToCheck++) @@ -231,7 +227,8 @@ private static bool AllPreviousCharsMatched(int startIndexToVerify, int currentQ return allMatch; } - private static List GetUpdatedIndexList(int startIndexToVerify, int currentQuerySubstringCharacterIndex, int firstMatchIndexInWord, List indexList) + private static List GetUpdatedIndexList(int startIndexToVerify, int currentQuerySubstringCharacterIndex, + int firstMatchIndexInWord, List indexList) { var updatedList = new List(); @@ -252,7 +249,8 @@ private static bool AllQuerySubstringsMatched(int currentQuerySubstringIndex, in return currentQuerySubstringIndex >= querySubstringsLength; } - private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, bool allSubstringsContainedInCompareString) + private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, + bool allSubstringsContainedInCompareString) { // A match found near the beginning of a string is scored more than a match found near the end // A match is scored more if the characters in the patterns are closer to each other, @@ -347,7 +345,7 @@ public bool IsSearchPrecisionScoreMet() private bool IsSearchPrecisionScoreMet(int rawScore) { - return rawScore >= (int)SearchPrecision; + return rawScore >= (int) SearchPrecision; } private int ScoreAfterSearchPrecisionFilter(int rawScore) @@ -360,4 +358,4 @@ public class MatchOption { public bool IgnoreCase { get; set; } = true; } -} +} \ No newline at end of file From 1e016d7aab47f2959ce9d6e3787fa35ea0aca5fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Tue, 22 Dec 2020 22:58:27 +0800 Subject: [PATCH 28/54] optimize use --- Flow.Launcher.Infrastructure/StringMatcher.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index e885798b789..22334c4bdfc 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -71,7 +71,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]) || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): - acronymMatchData.Add(map?.MapToOriginalIndex(compareIndex) ?? compareIndex); + acronymMatchData.Add(compareIndex); currentQueryIndex++; continue; @@ -86,7 +86,10 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption } if (acronymMatchData.Count == query.Length && acronymScore >= 60) + { + acronymMatchData = acronymMatchData.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); + } var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; @@ -188,7 +191,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString); - var resultList = indexList.Distinct().Select(x => map?.MapToOriginalIndex(x) ?? x).ToList(); + var resultList = indexList.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); return new MatchResult(true, UserSettingSearchPrecision, resultList, score); } From 9aa4802542c5e066ed8378fa3f2af6e191336055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 26 Dec 2020 00:29:35 +0800 Subject: [PATCH 29/54] Use Binary Search instead of Linear search to reduce time complexity. Add Key Property for debugging. --- .../PinyinAlphabet.cs | 70 +++++++++++++++---- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 4f1aedd4ab3..be3c58f6618 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -18,6 +18,13 @@ public class TranslationMapping private List translatedIndexs = new List(); private int translaedLength = 0; + public string key { get; private set; } + + public void setKey(string key) + { + this.key = key; + } + public void AddNewIndex(int originalIndex, int translatedIndex, int length) { if (constructed) @@ -29,28 +36,64 @@ public void AddNewIndex(int originalIndex, int translatedIndex, int length) translaedLength += length - 1; } - public int? MapToOriginalIndex(int translatedIndex) + public int MapToOriginalIndex(int translatedIndex) { if (translatedIndex > translatedIndexs.Last()) return translatedIndex - translaedLength - 1; - - for (var i = 0; i < originalIndexs.Count; i++) + + int lowerBound = 0; + int upperBound = originalIndexs.Count - 1; + + int count = 0; + + + // Corner case handle + if (translatedIndex < translatedIndexs[0]) + return translatedIndex; + if (translatedIndex > translatedIndexs.Last()) + { + int indexDef = 0; + for (int k = 0; k < originalIndexs.Count; k++) + { + indexDef += translatedIndexs[k * 2 + 1] - translatedIndexs[k * 2]; + } + + return translatedIndex - indexDef - 1; + } + + // Binary Search with Range + for (int i = originalIndexs.Count / 2;; count++) { - if (translatedIndex >= translatedIndexs[i * 2] && translatedIndex < translatedIndexs[i * 2 + 1]) - return originalIndexs[i]; if (translatedIndex < translatedIndexs[i * 2]) { - int indexDiff = 0; - for (int j = 0; j < i; j++) + // move to lower middle + upperBound = i; + i = (i + lowerBound) / 2; + } + else if (translatedIndex > translatedIndexs[i * 2 + 1] - 1) + { + lowerBound = i; + // move to upper middle + // due to floor of integer division, move one up on corner case + i = (i + upperBound + 1) / 2; + } + else + return originalIndexs[i]; + + if (upperBound - lowerBound <= 1 && + translatedIndex > translatedIndexs[lowerBound * 2 + 1] && + translatedIndex < translatedIndexs[upperBound * 2]) + { + int indexDef = 0; + + for (int j = 0; j < upperBound; j++) { - indexDiff += translatedIndexs[i * 2 + 1] - translatedIndexs[i * 2] - 1; + indexDef += translatedIndexs[j * 2 + 1] - translatedIndexs[j * 2]; } - return translatedIndex - indexDiff; + return translatedIndex - indexDef - 1; } } - - return translatedIndex; } public void endConstruct() @@ -117,7 +160,10 @@ public void Initialize([NotNull] Settings settings) map.endConstruct(); - return _pinyinCache[content] = (resultBuilder.ToString(), map); + var key = resultBuilder.ToString(); + map.setKey(key); + + return _pinyinCache[content] = (key, map); } else { From 213059996af5edcabce739773d903a874ecfb186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sun, 27 Dec 2020 20:16:20 +0800 Subject: [PATCH 30/54] Use inner loop to evaluate acronym match (Big Change) Don't end loop before acronym match end since if acronym match exist, we will use that one. --- Flow.Launcher.Infrastructure/StringMatcher.cs | 99 ++++++++++++------- 1 file changed, 61 insertions(+), 38 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 22334c4bdfc..7ade76cdfe0 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -51,46 +51,13 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption TranslationMapping map; (stringToCompare, map) = _alphabet?.Translate(stringToCompare) ?? (stringToCompare, null); - var currentQueryIndex = 0; + var currentAcronymQueryIndex = 0; var acronymMatchData = new List(); var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; + // preset acronymScore int acronymScore = 100; - for (int compareIndex = 0; compareIndex < stringToCompare.Length; compareIndex++) - { - if (currentQueryIndex >= queryWithoutCase.Length) - break; - - - switch (stringToCompare[compareIndex]) - { - case var c when (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == - char.ToLower(stringToCompare[compareIndex])) - || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) - || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == - queryWithoutCase[currentQueryIndex]) - || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): - acronymMatchData.Add(compareIndex); - currentQueryIndex++; - continue; - - case var c when char.IsWhiteSpace(c): - compareIndex++; - acronymScore -= 10; - break; - case var c when char.IsUpper(c) || char.IsNumber(c): - acronymScore -= 10; - break; - } - } - - if (acronymMatchData.Count == query.Length && acronymScore >= 60) - { - acronymMatchData = acronymMatchData.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); - return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); - } - var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; @@ -109,24 +76,72 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var indexList = new List(); List spaceIndices = new List(); + bool spaceMet = false; + for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++) { + if (currentAcronymQueryIndex >= queryWithoutCase.Length + || allQuerySubstringsMatched && acronymScore < (int) UserSettingSearchPrecision) + break; + + // To maintain a list of indices which correspond to spaces in the string to compare // To populate the list only for the first query substring - if (fullStringToCompareWithoutCase[compareStringIndex].Equals(' ') && currentQuerySubstringIndex == 0) + if (fullStringToCompareWithoutCase[compareStringIndex] == ' ' && currentQuerySubstringIndex == 0) { spaceIndices.Add(compareStringIndex); } - if (fullStringToCompareWithoutCase[compareStringIndex] != + // Acronym check + if (char.IsUpper(stringToCompare[compareStringIndex]) || + char.IsNumber(stringToCompare[compareStringIndex]) || + char.IsWhiteSpace(stringToCompare[compareStringIndex]) || + spaceMet) + { + if (fullStringToCompareWithoutCase[compareStringIndex] == + queryWithoutCase[currentAcronymQueryIndex]) + { + currentAcronymQueryIndex++; + + if (!spaceMet) + { + char currentCompareChar = stringToCompare[compareStringIndex]; + spaceMet = char.IsWhiteSpace(currentCompareChar); + // if is space, no need to check whether upper or digit, though insignificant + if (!spaceMet && compareStringIndex == 0 || char.IsUpper(currentCompareChar) || + char.IsDigit(currentCompareChar)) + { + acronymMatchData.Add(compareStringIndex); + } + } + else if (!(spaceMet = char.IsWhiteSpace(stringToCompare[compareStringIndex]))) + { + acronymMatchData.Add(compareStringIndex); + } + } + else + { + spaceMet = char.IsWhiteSpace(stringToCompare[compareStringIndex]); + // Acronym Penalty + if (!spaceMet) + { + acronymScore -= 10; + } + } + } + // Acronym end + + if (allQuerySubstringsMatched || fullStringToCompareWithoutCase[compareStringIndex] != currentQuerySubstring[currentQuerySubstringCharacterIndex]) { matchFoundInPreviousLoop = false; + continue; } + if (firstMatchIndex < 0) { // first matched char will become the start of the compared string @@ -174,8 +189,9 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption allQuerySubstringsMatched = AllQuerySubstringsMatched(currentQuerySubstringIndex, querySubstrings.Length); + if (allQuerySubstringsMatched) - break; + continue; // otherwise move to the next query substring currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; @@ -183,6 +199,12 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption } } + // return acronym Match if possible + if (acronymMatchData.Count == query.Length && acronymScore >= (int) UserSettingSearchPrecision) + { + acronymMatchData = acronymMatchData.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); + return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); + } // proceed to calculate score if every char or substring without whitespaces matched if (allQuerySubstringsMatched) @@ -249,6 +271,7 @@ private static List GetUpdatedIndexList(int startIndexToVerify, int current private static bool AllQuerySubstringsMatched(int currentQuerySubstringIndex, int querySubstringsLength) { + // Acronym won't utilize the substring to match return currentQuerySubstringIndex >= querySubstringsLength; } From 1cd21c0ccb36827ca01eb57384b44710d5064561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Mon, 25 Jan 2021 06:04:05 +0800 Subject: [PATCH 31/54] Fix testing --- Flow.Launcher.Test/FuzzyMatcherTest.cs | 97 ++++++++++++++++++-------- 1 file changed, 66 insertions(+), 31 deletions(-) diff --git a/Flow.Launcher.Test/FuzzyMatcherTest.cs b/Flow.Launcher.Test/FuzzyMatcherTest.cs index 468b944573e..8925ae70856 100644 --- a/Flow.Launcher.Test/FuzzyMatcherTest.cs +++ b/Flow.Launcher.Test/FuzzyMatcherTest.cs @@ -40,7 +40,7 @@ public List GetPrecisionScores() Enum.GetValues(typeof(StringMatcher.SearchPrecisionScore)) .Cast() .ToList() - .ForEach(x => listToReturn.Add((int)x)); + .ForEach(x => listToReturn.Add((int) x)); return listToReturn; } @@ -92,7 +92,8 @@ public void WhenNotAllCharactersFoundInSearchString_ThenShouldReturnZeroScore(st [TestCase("cand")] [TestCase("cpywa")] [TestCase("ccs")] - public void GivenQueryString_WhenAppliedPrecisionFiltering_ThenShouldReturnGreaterThanPrecisionScoreResults(string searchTerm) + public void GivenQueryString_WhenAppliedPrecisionFiltering_ThenShouldReturnGreaterThanPrecisionScoreResults( + string searchTerm) { var results = new List(); var matcher = new StringMatcher(); @@ -108,9 +109,9 @@ public void GivenQueryString_WhenAppliedPrecisionFiltering_ThenShouldReturnGreat foreach (var precisionScore in GetPrecisionScores()) { var filteredResult = results.Where(result => result.Score >= precisionScore) - .Select(result => result) - .OrderByDescending(x => x.Score) - .ToList(); + .Select(result => result) + .OrderByDescending(x => x.Score) + .ToList(); Debug.WriteLine(""); Debug.WriteLine("###############################################"); @@ -119,6 +120,7 @@ public void GivenQueryString_WhenAppliedPrecisionFiltering_ThenShouldReturnGreat { Debug.WriteLine("SCORE: " + item.Score.ToString() + ", FoundString: " + item.Title); } + Debug.WriteLine("###############################################"); Debug.WriteLine(""); @@ -128,11 +130,11 @@ public void GivenQueryString_WhenAppliedPrecisionFiltering_ThenShouldReturnGreat [TestCase(Chrome, Chrome, 157)] [TestCase(Chrome, LastIsChrome, 147)] - [TestCase(Chrome, HelpCureHopeRaiseOnMindEntityChrome, 25)] + [TestCase(Chrome, HelpCureHopeRaiseOnMindEntityChrome, 90)] [TestCase(Chrome, UninstallOrChangeProgramsOnYourComputer, 21)] [TestCase(Chrome, CandyCrushSagaFromKing, 0)] - [TestCase("sql", MicrosoftSqlServerManagementStudio, 110)] - [TestCase("sql manag", MicrosoftSqlServerManagementStudio, 121)]//double spacing intended + [TestCase("sql", MicrosoftSqlServerManagementStudio, 90)] + [TestCase("sql manag", MicrosoftSqlServerManagementStudio, 121)] //double spacing intended public void WhenGivenQueryString_ThenShouldReturn_TheDesiredScoring( string queryString, string compareString, int expectedScore) { @@ -141,20 +143,20 @@ public void WhenGivenQueryString_ThenShouldReturn_TheDesiredScoring( var rawScore = matcher.FuzzyMatch(queryString, compareString).RawScore; // Should - Assert.AreEqual(expectedScore, rawScore, + Assert.AreEqual(expectedScore, rawScore, $"Expected score for compare string '{compareString}': {expectedScore}, Actual: {rawScore}"); } [TestCase("goo", "Google Chrome", StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("chr", "Google Chrome", StringMatcher.SearchPrecisionScore.Low, true)] [TestCase("chr", "Chrome", StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("chr", "Help cure hope raise on mind entity Chrome", StringMatcher.SearchPrecisionScore.Regular, false)] [TestCase("chr", "Help cure hope raise on mind entity Chrome", StringMatcher.SearchPrecisionScore.Low, true)] [TestCase("chr", "Candy Crush Saga from King", StringMatcher.SearchPrecisionScore.Regular, false)] [TestCase("chr", "Candy Crush Saga from King", StringMatcher.SearchPrecisionScore.None, true)] - [TestCase("ccs", "Candy Crush Saga from King", StringMatcher.SearchPrecisionScore.Low, true)] - [TestCase("cand", "Candy Crush Saga from King",StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("cand", "Help cure hope raise on mind entity Chrome", StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("ccs", "Candy Crush Saga from King", StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("cand", "Candy Crush Saga from King", StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("cand", "Help cure hope raise on mind entity Chrome", StringMatcher.SearchPrecisionScore.Regular, + false)] public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( string queryString, string compareString, @@ -170,7 +172,8 @@ public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( Debug.WriteLine(""); Debug.WriteLine("###############################################"); Debug.WriteLine($"QueryString: {queryString} CompareString: {compareString}"); - Debug.WriteLine($"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {expectedPrecisionScore} ({(int)expectedPrecisionScore})"); + Debug.WriteLine( + $"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {expectedPrecisionScore} ({(int) expectedPrecisionScore})"); Debug.WriteLine("###############################################"); Debug.WriteLine(""); @@ -179,13 +182,15 @@ public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( $"Query:{queryString}{Environment.NewLine} " + $"Compare:{compareString}{Environment.NewLine}" + $"Raw Score: {matchResult.RawScore}{Environment.NewLine}" + - $"Precision Score: {(int)expectedPrecisionScore}"); + $"Precision Score: {(int) expectedPrecisionScore}"); } [TestCase("exce", "OverLeaf-Latex: An online LaTeX editor", StringMatcher.SearchPrecisionScore.Regular, false)] [TestCase("term", "Windows Terminal (Preview)", StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("sql s managa", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("sql' s manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("sql s managa", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, + false)] + [TestCase("sql' s manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, + false)] [TestCase("sql s manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("sql manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("sql", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] @@ -195,15 +200,21 @@ public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( [TestCase("sql serv man", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("sql studio", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("mic", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("mssms", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("msms", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("chr", "Shutdown", StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("mssms", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("chr", "Change settings for text-to-speech and for speech recognition (if installed).", StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("ch r", "Change settings for text-to-speech and for speech recognition (if installed).", StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("chr", "Change settings for text-to-speech and for speech recognition (if installed).", + StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("ch r", "Change settings for text-to-speech and for speech recognition (if installed).", + StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("a test", "This is a test", StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("test", "This is a test", StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("cod", VisualStudioCode, StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("code", VisualStudioCode, StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("codes", "Visual Studio Codes", StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("vsc", VisualStudioCode, StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("vs", VisualStudioCode, StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("vc", VisualStudioCode, StringMatcher.SearchPrecisionScore.Regular, true)] public void WhenGivenQuery_ShouldReturnResults_ContainingAllQuerySubstrings( string queryString, string compareString, @@ -211,7 +222,7 @@ public void WhenGivenQuery_ShouldReturnResults_ContainingAllQuerySubstrings( bool expectedPrecisionResult) { // When - var matcher = new StringMatcher { UserSettingSearchPrecision = expectedPrecisionScore }; + var matcher = new StringMatcher {UserSettingSearchPrecision = expectedPrecisionScore}; // Given var matchResult = matcher.FuzzyMatch(queryString, compareString); @@ -219,7 +230,8 @@ public void WhenGivenQuery_ShouldReturnResults_ContainingAllQuerySubstrings( Debug.WriteLine(""); Debug.WriteLine("###############################################"); Debug.WriteLine($"QueryString: {queryString} CompareString: {compareString}"); - Debug.WriteLine($"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {expectedPrecisionScore} ({(int)expectedPrecisionScore})"); + Debug.WriteLine( + $"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {expectedPrecisionScore} ({(int) expectedPrecisionScore})"); Debug.WriteLine("###############################################"); Debug.WriteLine(""); @@ -228,7 +240,7 @@ public void WhenGivenQuery_ShouldReturnResults_ContainingAllQuerySubstrings( $"Query:{queryString}{Environment.NewLine} " + $"Compare:{compareString}{Environment.NewLine}" + $"Raw Score: {matchResult.RawScore}{Environment.NewLine}" + - $"Precision Score: {(int)expectedPrecisionScore}"); + $"Precision Score: {(int) expectedPrecisionScore}"); } [TestCase("man", "Task Manager", "eManual")] @@ -238,7 +250,7 @@ public void WhenGivenAQuery_Scoring_ShouldGiveMoreWeightToStartOfNewWord( string queryString, string compareString1, string compareString2) { // When - var matcher = new StringMatcher { UserSettingSearchPrecision = StringMatcher.SearchPrecisionScore.Regular }; + var matcher = new StringMatcher {UserSettingSearchPrecision = StringMatcher.SearchPrecisionScore.Regular}; // Given var compareString1Result = matcher.FuzzyMatch(queryString, compareString1); @@ -247,8 +259,10 @@ public void WhenGivenAQuery_Scoring_ShouldGiveMoreWeightToStartOfNewWord( Debug.WriteLine(""); Debug.WriteLine("###############################################"); Debug.WriteLine($"QueryString: \"{queryString}\"{Environment.NewLine}"); - Debug.WriteLine($"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}"); - Debug.WriteLine($"CompareString2: \"{compareString2}\", Score: {compareString2Result.Score}{Environment.NewLine}"); + Debug.WriteLine( + $"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}"); + Debug.WriteLine( + $"CompareString2: \"{compareString2}\", Score: {compareString2Result.Score}{Environment.NewLine}"); Debug.WriteLine("###############################################"); Debug.WriteLine(""); @@ -256,13 +270,13 @@ public void WhenGivenAQuery_Scoring_ShouldGiveMoreWeightToStartOfNewWord( Assert.True(compareString1Result.Score > compareString2Result.Score, $"Query: \"{queryString}\"{Environment.NewLine} " + $"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}" + - $"Should be greater than{ Environment.NewLine}" + + $"Should be greater than{Environment.NewLine}" + $"CompareString2: \"{compareString2}\", Score: {compareString1Result.Score}{Environment.NewLine}"); } [TestCase("vim", "Vim", "ignoreDescription", "ignore.exe", "Vim Diff", "ignoreDescription", "ignore.exe")] public void WhenMultipleResults_ExactMatchingResult_ShouldHaveGreatestScore( - string queryString, string firstName, string firstDescription, string firstExecutableName, + string queryString, string firstName, string firstDescription, string firstExecutableName, string secondName, string secondDescription, string secondExecutableName) { // Act @@ -275,15 +289,36 @@ public void WhenMultipleResults_ExactMatchingResult_ShouldHaveGreatestScore( var secondDescriptionMatch = matcher.FuzzyMatch(queryString, secondDescription).RawScore; var secondExecutableNameMatch = matcher.FuzzyMatch(queryString, secondExecutableName).RawScore; - var firstScore = new[] { firstNameMatch, firstDescriptionMatch, firstExecutableNameMatch }.Max(); - var secondScore = new[] { secondNameMatch, secondDescriptionMatch, secondExecutableNameMatch }.Max(); + var firstScore = new[] {firstNameMatch, firstDescriptionMatch, firstExecutableNameMatch}.Max(); + var secondScore = new[] {secondNameMatch, secondDescriptionMatch, secondExecutableNameMatch}.Max(); // Assert Assert.IsTrue(firstScore > secondScore, $"Query: \"{queryString}\"{Environment.NewLine} " + $"Name of first: \"{firstName}\", Final Score: {firstScore}{Environment.NewLine}" + - $"Should be greater than{ Environment.NewLine}" + + $"Should be greater than{Environment.NewLine}" + $"Name of second: \"{secondName}\", Final Score: {secondScore}{Environment.NewLine}"); } + + [TestCase("vsc","Visual Studio Code", 100)] + [TestCase("jbr","JetBrain Rider",100)] + [TestCase("jr","JetBrain Rider",90)] + [TestCase("vs","Visual Studio",100)] + [TestCase("vs","Visual Studio Preview",100)] + [TestCase("vsp","Visual Studio Preview",100)] + [TestCase("vsp","Visual Studio",0)] + [TestCase("pc","Postman Canary",100)] + + public void WhenGivenAnAcronymQuery_ShouldReturnAcronymScore(string queryString, string compareString, + int desiredScore) + { + var matcher = new StringMatcher(); + var score = matcher.FuzzyMatch(queryString, compareString).Score; + Assert.IsTrue(score == desiredScore, + $@"Query: ""{queryString}"" + CompareString: ""{compareString}"" + Score: {score} + Desired Score: {desiredScore}"); + } } } \ No newline at end of file From 900f009893487963248ae67d56b18fecaa5f3f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 26 Jan 2021 16:18:29 +0800 Subject: [PATCH 32/54] Revert DotNet 5 update --- Flow.Launcher.Core/Flow.Launcher.Core.csproj | 4 ++-- .../Flow.Launcher.Infrastructure.csproj | 5 +++-- Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj | 6 +++--- Flow.Launcher.Test/Flow.Launcher.Test.csproj | 3 ++- Flow.Launcher/Flow.Launcher.csproj | 4 ++-- .../PublishProfiles/Net5-SelfContained.pubxml | 2 +- .../Flow.Launcher.Plugin.BrowserBookmark.csproj | 14 ++++++++++---- .../Flow.Launcher.Plugin.Calculator.csproj | 4 ++-- .../Flow.Launcher.Plugin.ControlPanel.csproj | 4 ++-- .../Flow.Launcher.Plugin.Explorer.csproj | 4 ++-- .../Flow.Launcher.Plugin.PluginIndicator.csproj | 4 ++-- .../Flow.Launcher.Plugin.PluginsManager.csproj | 3 +-- .../Flow.Launcher.Plugin.ProcessKiller.csproj | 2 +- .../Flow.Launcher.Plugin.Program.csproj | 5 +++-- .../Flow.Launcher.Plugin.Shell.csproj | 5 +++-- .../Flow.Launcher.Plugin.Sys.csproj | 4 ++-- .../Flow.Launcher.Plugin.Url.csproj | 4 ++-- .../Flow.Launcher.Plugin.WebSearch.csproj | 14 +++++++++++--- Scripts/flowlauncher.nuspec | 2 +- global.json | 2 +- 20 files changed, 56 insertions(+), 39 deletions(-) diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj index 8eb411707a1..189a6669ec1 100644 --- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj +++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj @@ -1,7 +1,7 @@ - + - net5.0-windows + netcoreapp3.1 true true Library diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index 61433f92d1b..8153de6c8a4 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -1,6 +1,7 @@ - + + - net5.0-windows + netcoreapp3.1 {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3} Library true diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj index 830106d32cc..698802ba3e6 100644 --- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj +++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj @@ -1,7 +1,7 @@ - - + + - net5.0-windows + netcoreapp3.1 {8451ECDD-2EA4-4966-BB0A-7BBC40138E80} true Library diff --git a/Flow.Launcher.Test/Flow.Launcher.Test.csproj b/Flow.Launcher.Test/Flow.Launcher.Test.csproj index fb972d7d410..e970c47b958 100644 --- a/Flow.Launcher.Test/Flow.Launcher.Test.csproj +++ b/Flow.Launcher.Test/Flow.Launcher.Test.csproj @@ -1,7 +1,7 @@  - net5.0-windows10.0.19041.0 + netcoreapp3.1 {FF742965-9A80-41A5-B042-D6C7D3A21708} Library Properties @@ -54,6 +54,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + \ No newline at end of file diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index aeaa26e047c..56f0675d682 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -1,8 +1,8 @@ - + WinExe - net5.0-windows10.0.19041.0 + netcoreapp3.1 true true Flow.Launcher.App diff --git a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml index 3c5dcc8b23c..e98dba9886c 100644 --- a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml +++ b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml @@ -7,7 +7,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. FileSystem Release Any CPU - net5.0-windows10.0.19041.0 + netcoreapp3.1 ..\Output\Release\ win-x64 true diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj index ee27367561d..d2a8736a638 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj @@ -1,9 +1,8 @@ - + Library - net5.0-windows - true + netcoreapp3.1 {9B130CC5-14FB-41FF-B310-0A95B6894C37} Properties Flow.Launcher.Plugin.BrowserBookmark @@ -64,7 +63,14 @@ PreserveNewest - + + + + MSBuild:Compile + Designer + + + diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj index b3212794bd2..1090926fc8e 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj @@ -1,8 +1,8 @@ - + Library - net5.0-windows + netcoreapp3.1 {59BD9891-3837-438A-958D-ADC7F91F6F7E} Properties Flow.Launcher.Plugin.Caculator diff --git a/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj b/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj index d69547c6c2a..06969a1354e 100644 --- a/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj +++ b/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj @@ -1,8 +1,8 @@ - + Library - net5.0-windows + netcoreapp3.1 {1EE20B48-82FB-48A2-8086-675D6DDAB4F0} Properties Flow.Launcher.Plugin.ControlPanel 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 71c0463b5b5..9f0b46d9385 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -1,8 +1,8 @@ - + Library - net5.0-windows + netcoreapp3.1 true true true diff --git a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj index 54f0bbd9b4d..cc280b9a9cf 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj @@ -1,8 +1,8 @@ - + Library - net5.0-windows + netcoreapp3.1 {FDED22C8-B637-42E8-824A-63B5B6E05A3A} Properties Flow.Launcher.Plugin.PluginIndicator 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 d6ca96b46b6..cb2507a2b65 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj @@ -1,8 +1,7 @@  - Library - net5.0-windows + netcoreapp3.1 true true true diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj index f7a33a94b00..a643ebf868f 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj @@ -2,7 +2,7 @@ Library - net5.0-windows + netcoreapp3.1 Flow.Launcher.Plugin.ProcessKiller Flow.Launcher.Plugin.ProcessKiller Flow-Launcher diff --git a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj index 986ce218c90..12e11385597 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj +++ b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj @@ -1,8 +1,8 @@ - + Library - net5.0-windows10.0.19041.0 + netcoreapp3.1 {FDB3555B-58EF-4AE6-B5F1-904719637AB4} Properties Flow.Launcher.Plugin.Program @@ -69,6 +69,7 @@ + diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj index daae28cf657..6e72ebbe4ce 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj +++ b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj @@ -1,7 +1,8 @@ - + + Library - net5.0-windows + netcoreapp3.1 {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} Properties Flow.Launcher.Plugin.Shell diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj index 894d50cea30..88a23951fcc 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj +++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj @@ -1,8 +1,8 @@ - + Library - net5.0-windows + netcoreapp3.1 {0B9DE348-9361-4940-ADB6-F5953BFFCCEC} Properties Flow.Launcher.Plugin.Sys diff --git a/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj b/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj index 4fb0b1205a1..671a8b1c2c0 100644 --- a/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj +++ b/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj @@ -1,8 +1,8 @@ - + Library - net5.0-windows + netcoreapp3.1 {A3DCCBCA-ACC1-421D-B16E-210896234C26} true Properties diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj index 3eb03e52e1f..af86af84244 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj @@ -1,8 +1,8 @@ - + + Library - net5.0-windows - true + netcoreapp3.1 {403B57F2-1856-4FC7-8A24-36AB346B763E} Properties Flow.Launcher.Plugin.WebSearch @@ -43,6 +43,14 @@ PreserveNewest + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + diff --git a/Scripts/flowlauncher.nuspec b/Scripts/flowlauncher.nuspec index f1f58f2d18f..6c5deb86bf8 100644 --- a/Scripts/flowlauncher.nuspec +++ b/Scripts/flowlauncher.nuspec @@ -11,6 +11,6 @@ Flow Launcher - a launcher for windows - + diff --git a/global.json b/global.json index 2ad4d91009e..c3efffd4015 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "5.0.100", + "version": "3.1.201", "rollForward": "latestFeature" } } \ No newline at end of file From 597dc06b31110d3c04d5f248445617dadd5afee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 26 Jan 2021 16:24:30 +0800 Subject: [PATCH 33/54] revert unexpected personal change --- Flow.Launcher/Flow.Launcher.csproj | 4 ++-- ...-SelfContained.pubxml => NetCore3.1-SelfContained.pubxml} | 2 +- .../Flow.Launcher.Plugin.Shell.csproj | 5 ++++- .../Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj | 5 ++++- Scripts/post_build.ps1 | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) rename Flow.Launcher/Properties/PublishProfiles/{Net5-SelfContained.pubxml => NetCore3.1-SelfContained.pubxml} (92%) diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 56f0675d682..289a502d0f7 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -60,7 +60,7 @@ Designer PreserveNewest - + PreserveNewest @@ -78,7 +78,7 @@ - + all diff --git a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml similarity index 92% rename from Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml rename to Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml index e98dba9886c..2794a0cea1c 100644 --- a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml +++ b/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml @@ -12,7 +12,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. win-x64 true False - True + False False \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj index 6e72ebbe4ce..0e83427c0f6 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj +++ b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj @@ -8,7 +8,6 @@ Flow.Launcher.Plugin.Shell Flow.Launcher.Plugin.Shell true - true true false false @@ -55,6 +54,10 @@ PreserveNewest + + MSBuild:Compile + Designer + diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj index 88a23951fcc..aef78169388 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj +++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj @@ -8,7 +8,6 @@ Flow.Launcher.Plugin.Sys Flow.Launcher.Plugin.Sys true - true true false false @@ -49,6 +48,10 @@ PreserveNewest + + MSBuild:Compile + Designer + diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1 index 58d5c6a4ecd..b08fac8f67f 100644 --- a/Scripts/post_build.ps1 +++ b/Scripts/post_build.ps1 @@ -90,7 +90,7 @@ function Pack-Squirrel-Installer ($path, $version, $output) { function Publish-Self-Contained ($p) { $csproj = Join-Path "$p" "Flow.Launcher/Flow.Launcher.csproj" -Resolve - $profile = Join-Path "$p" "Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml" -Resolve + $profile = Join-Path "$p" "Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml" -Resolve # we call dotnet publish on the main project. # The other projects should have been built in Release at this point. From f4565957231f09144e7d19c98a6079d35853bcf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 26 Jan 2021 16:29:06 +0800 Subject: [PATCH 34/54] remove unexpected order change --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index efa70785048..870d17ca860 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -76,8 +76,8 @@ public MainViewModel(Settings settings) _selectedResults = Results; InitializeKeyCommands(); - RegisterResultsUpdatedEvent(); RegisterViewUpdate(); + RegisterResultsUpdatedEvent(); SetHotkey(_settings.Hotkey, OnHotkey); SetCustomPluginHotkey(); From f3479f6137137ee5d2311f8bcd5df7d3db08badd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 26 Jan 2021 16:31:35 +0800 Subject: [PATCH 35/54] fix testing due to API expand --- Flow.Launcher.Test/FuzzyMatcherTest.cs | 72 +++++++++++++------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Flow.Launcher.Test/FuzzyMatcherTest.cs b/Flow.Launcher.Test/FuzzyMatcherTest.cs index 8e1feca168a..dca8bf7a06f 100644 --- a/Flow.Launcher.Test/FuzzyMatcherTest.cs +++ b/Flow.Launcher.Test/FuzzyMatcherTest.cs @@ -148,15 +148,15 @@ public void WhenGivenQueryString_ThenShouldReturn_TheDesiredScoring( $"Expected score for compare string '{compareString}': {expectedScore}, Actual: {rawScore}"); } - [TestCase("goo", "Google Chrome", StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("chr", "Google Chrome", StringMatcher.SearchPrecisionScore.Low, true)] - [TestCase("chr", "Chrome", StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("chr", "Help cure hope raise on mind entity Chrome", StringMatcher.SearchPrecisionScore.Low, true)] - [TestCase("chr", "Candy Crush Saga from King", StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("chr", "Candy Crush Saga from King", StringMatcher.SearchPrecisionScore.None, true)] - [TestCase("ccs", "Candy Crush Saga from King", StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("cand", "Candy Crush Saga from King", StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("cand", "Help cure hope raise on mind entity Chrome", StringMatcher.SearchPrecisionScore.Regular, + [TestCase("goo", "Google Chrome", SearchPrecisionScore.Regular, true)] + [TestCase("chr", "Google Chrome", SearchPrecisionScore.Low, true)] + [TestCase("chr", "Chrome", SearchPrecisionScore.Regular, true)] + [TestCase("chr", "Help cure hope raise on mind entity Chrome", SearchPrecisionScore.Low, true)] + [TestCase("chr", "Candy Crush Saga from King", SearchPrecisionScore.Regular, false)] + [TestCase("chr", "Candy Crush Saga from King", SearchPrecisionScore.None, true)] + [TestCase("ccs", "Candy Crush Saga from King", SearchPrecisionScore.Regular, true)] + [TestCase("cand", "Candy Crush Saga from King", SearchPrecisionScore.Regular, true)] + [TestCase("cand", "Help cure hope raise on mind entity Chrome", SearchPrecisionScore.Regular, false)] public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( string queryString, @@ -186,36 +186,36 @@ public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( $"Precision Score: {(int) expectedPrecisionScore}"); } - [TestCase("exce", "OverLeaf-Latex: An online LaTeX editor", StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("term", "Windows Terminal (Preview)", StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("sql s managa", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, + [TestCase("exce", "OverLeaf-Latex: An online LaTeX editor", SearchPrecisionScore.Regular, false)] + [TestCase("term", "Windows Terminal (Preview)", SearchPrecisionScore.Regular, true)] + [TestCase("sql s managa", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, false)] - [TestCase("sql' s manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, + [TestCase("sql' s manag", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, false)] - [TestCase("sql s manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("sql manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("sql", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("sql serv", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("servez", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("sql servz", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("sql serv man", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("sql studio", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("mic", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("mssms", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("msms", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("chr", "Shutdown", StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("sql s manag", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] + [TestCase("sql manag", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] + [TestCase("sql", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] + [TestCase("sql serv", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] + [TestCase("servez", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, false)] + [TestCase("sql servz", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, false)] + [TestCase("sql serv man", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] + [TestCase("sql studio", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] + [TestCase("mic", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] + [TestCase("mssms", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] + [TestCase("msms", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] + [TestCase("chr", "Shutdown", SearchPrecisionScore.Regular, false)] [TestCase("chr", "Change settings for text-to-speech and for speech recognition (if installed).", - StringMatcher.SearchPrecisionScore.Regular, false)] + SearchPrecisionScore.Regular, false)] [TestCase("ch r", "Change settings for text-to-speech and for speech recognition (if installed).", - StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("a test", "This is a test", StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("test", "This is a test", StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("cod", VisualStudioCode, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("code", VisualStudioCode, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("codes", "Visual Studio Codes", StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("vsc", VisualStudioCode, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("vs", VisualStudioCode, StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("vc", VisualStudioCode, StringMatcher.SearchPrecisionScore.Regular, true)] + SearchPrecisionScore.Regular, true)] + [TestCase("a test", "This is a test", SearchPrecisionScore.Regular, true)] + [TestCase("test", "This is a test", SearchPrecisionScore.Regular, true)] + [TestCase("cod", VisualStudioCode, SearchPrecisionScore.Regular, true)] + [TestCase("code", VisualStudioCode, SearchPrecisionScore.Regular, true)] + [TestCase("codes", "Visual Studio Codes", SearchPrecisionScore.Regular, true)] + [TestCase("vsc", VisualStudioCode, SearchPrecisionScore.Regular, true)] + [TestCase("vs", VisualStudioCode, SearchPrecisionScore.Regular, true)] + [TestCase("vc", VisualStudioCode, SearchPrecisionScore.Regular, true)] public void WhenGivenQuery_ShouldReturnResults_ContainingAllQuerySubstrings( string queryString, string compareString, @@ -251,7 +251,7 @@ public void WhenGivenAQuery_Scoring_ShouldGiveMoreWeightToStartOfNewWord( string queryString, string compareString1, string compareString2) { // When - var matcher = new StringMatcher {UserSettingSearchPrecision = StringMatcher.SearchPrecisionScore.Regular}; + var matcher = new StringMatcher {UserSettingSearchPrecision = SearchPrecisionScore.Regular}; // Given var compareString1Result = matcher.FuzzyMatch(queryString, compareString1); From 81733d35a62510573c533f00da5d9b7e33fdb7e1 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 28 Jan 2021 14:05:09 +1100 Subject: [PATCH 36/54] fix formatting --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 1 - Flow.Launcher.Infrastructure/StringMatcher.cs | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index be3c58f6618..f1557c45ab9 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -5,7 +5,6 @@ using System.Text; using JetBrains.Annotations; using Flow.Launcher.Infrastructure.UserSettings; -using Microsoft.AspNetCore.Localization; using ToolGood.Words.Pinyin; namespace Flow.Launcher.Infrastructure diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 3777c6811d9..63722bd5477 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -59,7 +59,6 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; - var querySubstrings = queryWithoutCase.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); int currentQuerySubstringIndex = 0; var currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; @@ -77,15 +76,12 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption bool spaceMet = false; - for (var compareStringIndex = 0; - compareStringIndex < fullStringToCompareWithoutCase.Length; - compareStringIndex++) + for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++) { if (currentAcronymQueryIndex >= queryWithoutCase.Length || allQuerySubstringsMatched && acronymScore < (int) UserSettingSearchPrecision) break; - // To maintain a list of indices which correspond to spaces in the string to compare // To populate the list only for the first query substring if (fullStringToCompareWithoutCase[compareStringIndex] == ' ' && currentQuerySubstringIndex == 0) From 74f1b05257474cf50274d655f8c42fd883cb1bab Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 28 Jan 2021 20:41:33 +1100 Subject: [PATCH 37/54] make map variable more clear + formatting --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 2 -- Flow.Launcher.Infrastructure/StringMatcher.cs | 11 +++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index f1557c45ab9..6c2a94e8205 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -45,7 +45,6 @@ public int MapToOriginalIndex(int translatedIndex) int count = 0; - // Corner case handle if (translatedIndex < translatedIndexs[0]) return translatedIndex; @@ -113,7 +112,6 @@ public class PinyinAlphabet : IAlphabet private ConcurrentDictionary _pinyinCache = new ConcurrentDictionary(); - private Settings _settings; public void Initialize([NotNull] Settings settings) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 63722bd5477..916168dfe92 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -47,17 +47,17 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption return new MatchResult(false, UserSettingSearchPrecision); query = query.Trim(); - TranslationMapping map; - (stringToCompare, map) = _alphabet?.Translate(stringToCompare) ?? (stringToCompare, null); + TranslationMapping translationMapping; + (stringToCompare, translationMapping) = _alphabet?.Translate(stringToCompare) ?? (stringToCompare, null); var currentAcronymQueryIndex = 0; var acronymMatchData = new List(); - var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; // preset acronymScore int acronymScore = 100; var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; + var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; var querySubstrings = queryWithoutCase.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); int currentQuerySubstringIndex = 0; @@ -136,7 +136,6 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption continue; } - if (firstMatchIndex < 0) { // first matched char will become the start of the compared string @@ -197,7 +196,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption // return acronym Match if possible if (acronymMatchData.Count == query.Length && acronymScore >= (int) UserSettingSearchPrecision) { - acronymMatchData = acronymMatchData.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); + acronymMatchData = acronymMatchData.Select(x => translationMapping?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); } @@ -208,7 +207,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString); - var resultList = indexList.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); + var resultList = indexList.Select(x => translationMapping?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); return new MatchResult(true, UserSettingSearchPrecision, resultList, score); } From a6ce3506975212518f8b42178f94a360866d6126 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 28 Jan 2021 21:21:35 +1100 Subject: [PATCH 38/54] fix formatting --- Flow.Launcher.Infrastructure/StringMatcher.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 916168dfe92..9ded898e317 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -85,9 +85,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption // To maintain a list of indices which correspond to spaces in the string to compare // To populate the list only for the first query substring if (fullStringToCompareWithoutCase[compareStringIndex] == ' ' && currentQuerySubstringIndex == 0) - { spaceIndices.Add(compareStringIndex); - } // Acronym check if (char.IsUpper(stringToCompare[compareStringIndex]) || @@ -310,4 +308,4 @@ public class MatchOption { public bool IgnoreCase { get; set; } = true; } -} \ No newline at end of file +} From 4993edae2d1ab5c6592384258336709b4d149985 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 28 Jan 2021 21:41:20 +1100 Subject: [PATCH 39/54] fix formatting --- Flow.Launcher.Test/FuzzyMatcherTest.cs | 5 ++--- Flow.Launcher/ViewModel/MainViewModel.cs | 1 - .../Flow.Launcher.Plugin.Shell.csproj | 8 ++++---- .../Flow.Launcher.Plugin.Sys.csproj | 8 ++++---- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher.Test/FuzzyMatcherTest.cs b/Flow.Launcher.Test/FuzzyMatcherTest.cs index dca8bf7a06f..f2cdd7bacd4 100644 --- a/Flow.Launcher.Test/FuzzyMatcherTest.cs +++ b/Flow.Launcher.Test/FuzzyMatcherTest.cs @@ -241,7 +241,7 @@ public void WhenGivenQuery_ShouldReturnResults_ContainingAllQuerySubstrings( $"Query:{queryString}{Environment.NewLine} " + $"Compare:{compareString}{Environment.NewLine}" + $"Raw Score: {matchResult.RawScore}{Environment.NewLine}" + - $"Precision Score: {(int) expectedPrecisionScore}"); + $"Precision Score: {(int)expectedPrecisionScore}"); } [TestCase("man", "Task Manager", "eManual")] @@ -309,7 +309,6 @@ public void WhenMultipleResults_ExactMatchingResult_ShouldHaveGreatestScore( [TestCase("vsp","Visual Studio Preview",100)] [TestCase("vsp","Visual Studio",0)] [TestCase("pc","Postman Canary",100)] - public void WhenGivenAnAcronymQuery_ShouldReturnAcronymScore(string queryString, string compareString, int desiredScore) { @@ -322,4 +321,4 @@ public void WhenGivenAnAcronymQuery_ShouldReturnAcronymScore(string queryString, Desired Score: {desiredScore}"); } } -} \ No newline at end of file +} diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 870d17ca860..05dbb3a8b8b 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -19,7 +19,6 @@ using Flow.Launcher.Plugin.SharedCommands; using Flow.Launcher.Storage; using Flow.Launcher.Infrastructure.Logger; -using System.Threading.Tasks.Dataflow; namespace Flow.Launcher.ViewModel { diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj index 0e83427c0f6..d3042722b9f 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj +++ b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj @@ -54,10 +54,10 @@ PreserveNewest - - MSBuild:Compile - Designer - + + MSBuild:Compile + Designer + diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj index aef78169388..c25e759d39d 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj +++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj @@ -48,10 +48,10 @@ PreserveNewest - - MSBuild:Compile - Designer - + + MSBuild:Compile + Designer + From d81db91b72caf5c6b699939fe504ec0fcb7ec373 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 28 Jan 2021 21:48:44 +1100 Subject: [PATCH 40/54] fix formatting --- Flow.Launcher.Test/FuzzyMatcherTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Test/FuzzyMatcherTest.cs b/Flow.Launcher.Test/FuzzyMatcherTest.cs index f2cdd7bacd4..78c918b6150 100644 --- a/Flow.Launcher.Test/FuzzyMatcherTest.cs +++ b/Flow.Launcher.Test/FuzzyMatcherTest.cs @@ -41,7 +41,7 @@ public List GetPrecisionScores() Enum.GetValues(typeof(SearchPrecisionScore)) .Cast() .ToList() - .ForEach(x => listToReturn.Add((int) x)); + .ForEach(x => listToReturn.Add((int)x)); return listToReturn; } @@ -183,7 +183,7 @@ public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( $"Query:{queryString}{Environment.NewLine} " + $"Compare:{compareString}{Environment.NewLine}" + $"Raw Score: {matchResult.RawScore}{Environment.NewLine}" + - $"Precision Score: {(int) expectedPrecisionScore}"); + $"Precision Score: {(int)expectedPrecisionScore}"); } [TestCase("exce", "OverLeaf-Latex: An online LaTeX editor", SearchPrecisionScore.Regular, false)] From 58b717c00868afeb8b93287994f072ceaa87810f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 29 Jan 2021 17:31:52 +0800 Subject: [PATCH 41/54] Update summary --- Flow.Launcher.Infrastructure/StringMatcher.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 3777c6811d9..e332aeeefb0 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -31,7 +31,20 @@ public MatchResult FuzzyMatch(string query, string stringToCompare) } /// - /// Current method: + /// Current method includes two part, Acronym Match and Fuzzy Search: + /// + /// Acronym Match: + /// Charater lists below will be considered as Acronym + /// 1. Character on index 0 + /// 2. Character appears after a space + /// 3. Character that is UpperCase + /// 4. Character that is number + /// + /// Acronym Search will match all query when meeting with Acronyms in the stringToCompare + /// If any of the character in Query isn't matched with the string, Acronym Search fail. + /// Score will be calculated based on the number of mismatched acronym before all query has been matched + /// + /// Fuzzy Search: /// Character matching + substring matching; /// 1. Query search string is split into substrings, separator is whitespace. /// 2. Check each query substring's characters against full compare string, From c395cc74b59c208601af3f8c376b853b7bda8b68 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 1 Feb 2021 06:08:05 +1100 Subject: [PATCH 42/54] move control variable down for readability during debug --- Flow.Launcher.Infrastructure/StringMatcher.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 3225f9969a8..c8f22cf7c92 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -109,8 +109,6 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption if (fullStringToCompareWithoutCase[compareStringIndex] == queryWithoutCase[currentAcronymQueryIndex]) { - currentAcronymQueryIndex++; - if (!spaceMet) { char currentCompareChar = stringToCompare[compareStringIndex]; @@ -126,6 +124,8 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption { acronymMatchData.Add(compareStringIndex); } + + currentAcronymQueryIndex++; } else { From bb6a91124a8901e0d431a68d7a4d0681bbf01580 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 1 Feb 2021 06:50:53 +1100 Subject: [PATCH 43/54] add loop to check remaining acronyms if previous matched --- Flow.Launcher.Infrastructure/StringMatcher.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index c8f22cf7c92..2042b73f788 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -68,6 +68,8 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption // preset acronymScore int acronymScore = 100; + int acronymsRemainingNotMatched = 0; + int acronymsMatched = 0; var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; @@ -91,6 +93,15 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++) { + if (currentAcronymQueryIndex >= queryWithoutCase.Length && acronymsMatched > 0) + { + if (char.IsUpper(stringToCompare[compareStringIndex]) || + char.IsNumber(stringToCompare[compareStringIndex]) || + char.IsWhiteSpace(stringToCompare[compareStringIndex])) + acronymsRemainingNotMatched++; + continue; + } + if (currentAcronymQueryIndex >= queryWithoutCase.Length || allQuerySubstringsMatched && acronymScore < (int) UserSettingSearchPrecision) break; @@ -118,11 +129,13 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption char.IsDigit(currentCompareChar)) { acronymMatchData.Add(compareStringIndex); + acronymsMatched++; } } else if (!(spaceMet = char.IsWhiteSpace(stringToCompare[compareStringIndex]))) { acronymMatchData.Add(compareStringIndex); + acronymsMatched++; } currentAcronymQueryIndex++; From 99da6f207ae32da3533284fe89b8806089b457db Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 1 Feb 2021 21:34:35 +1100 Subject: [PATCH 44/54] move acronym check to method and update scoring to percentage based --- Flow.Launcher.Infrastructure/StringMatcher.cs | 85 +++++++++---------- Flow.Launcher.Test/FuzzyMatcherTest.cs | 46 +++++----- 2 files changed, 61 insertions(+), 70 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 2042b73f788..cdb5c4e6896 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -66,10 +66,8 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var currentAcronymQueryIndex = 0; var acronymMatchData = new List(); - // preset acronymScore - int acronymScore = 100; - int acronymsRemainingNotMatched = 0; - int acronymsMatched = 0; + decimal acronymsTotalCount = 0; + decimal acronymsMatched = 0; var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; @@ -89,21 +87,18 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var indexList = new List(); List spaceIndices = new List(); - bool spaceMet = false; - for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++) { - if (currentAcronymQueryIndex >= queryWithoutCase.Length && acronymsMatched > 0) + // If acronyms matching successfully finished, this gets the remaining not matched acronyms for score calculation + if (currentAcronymQueryIndex >= query.Length && acronymsMatched == query.Length) { - if (char.IsUpper(stringToCompare[compareStringIndex]) || - char.IsNumber(stringToCompare[compareStringIndex]) || - char.IsWhiteSpace(stringToCompare[compareStringIndex])) - acronymsRemainingNotMatched++; + if (IsAcronym(stringToCompare, compareStringIndex)) + acronymsTotalCount++; continue; } - if (currentAcronymQueryIndex >= queryWithoutCase.Length - || allQuerySubstringsMatched && acronymScore < (int) UserSettingSearchPrecision) + if (currentAcronymQueryIndex >= query.Length || + currentAcronymQueryIndex >= query.Length && allQuerySubstringsMatched) break; // To maintain a list of indices which correspond to spaces in the string to compare @@ -112,43 +107,18 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption spaceIndices.Add(compareStringIndex); // Acronym check - if (char.IsUpper(stringToCompare[compareStringIndex]) || - char.IsNumber(stringToCompare[compareStringIndex]) || - char.IsWhiteSpace(stringToCompare[compareStringIndex]) || - spaceMet) + if (IsAcronym(stringToCompare, compareStringIndex)) { if (fullStringToCompareWithoutCase[compareStringIndex] == queryWithoutCase[currentAcronymQueryIndex]) { - if (!spaceMet) - { - char currentCompareChar = stringToCompare[compareStringIndex]; - spaceMet = char.IsWhiteSpace(currentCompareChar); - // if is space, no need to check whether upper or digit, though insignificant - if (!spaceMet && compareStringIndex == 0 || char.IsUpper(currentCompareChar) || - char.IsDigit(currentCompareChar)) - { - acronymMatchData.Add(compareStringIndex); - acronymsMatched++; - } - } - else if (!(spaceMet = char.IsWhiteSpace(stringToCompare[compareStringIndex]))) - { - acronymMatchData.Add(compareStringIndex); - acronymsMatched++; - } + acronymMatchData.Add(compareStringIndex); + acronymsMatched++; currentAcronymQueryIndex++; } - else - { - spaceMet = char.IsWhiteSpace(stringToCompare[compareStringIndex]); - // Acronym Penalty - if (!spaceMet) - { - acronymScore -= 10; - } - } + + acronymsTotalCount++; } // Acronym end @@ -217,11 +187,16 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption } } - // return acronym Match if possible - if (acronymMatchData.Count == query.Length && acronymScore >= (int) UserSettingSearchPrecision) + // return acronym match if all query char matched + if (acronymsMatched > 0 && acronymsMatched == query.Length) { - acronymMatchData = acronymMatchData.Select(x => translationMapping?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); - return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); + int acronymScore = (int)(acronymsMatched / acronymsTotalCount * 100); + + if (acronymScore >= (int)UserSettingSearchPrecision) + { + acronymMatchData = acronymMatchData.Select(x => translationMapping?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); + return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); + } } // proceed to calculate score if every char or substring without whitespaces matched @@ -238,6 +213,22 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption return new MatchResult(false, UserSettingSearchPrecision); } + private bool IsAcronym(string stringToCompare, int compareStringIndex) + { + if (char.IsUpper(stringToCompare[compareStringIndex]) || + char.IsNumber(stringToCompare[compareStringIndex]) || + char.IsDigit(stringToCompare[compareStringIndex])) + return true; + + if (compareStringIndex == 0) + return true; + + if (compareStringIndex != 0 && char.IsWhiteSpace(stringToCompare[compareStringIndex - 1])) + return true; + + return false; + } + // To get the index of the closest space which preceeds the first matching index private int CalculateClosestSpaceIndex(List spaceIndices, int firstMatchIndex) { diff --git a/Flow.Launcher.Test/FuzzyMatcherTest.cs b/Flow.Launcher.Test/FuzzyMatcherTest.cs index 78c918b6150..32d2e8fdbf4 100644 --- a/Flow.Launcher.Test/FuzzyMatcherTest.cs +++ b/Flow.Launcher.Test/FuzzyMatcherTest.cs @@ -151,13 +151,17 @@ public void WhenGivenQueryString_ThenShouldReturn_TheDesiredScoring( [TestCase("goo", "Google Chrome", SearchPrecisionScore.Regular, true)] [TestCase("chr", "Google Chrome", SearchPrecisionScore.Low, true)] [TestCase("chr", "Chrome", SearchPrecisionScore.Regular, true)] + [TestCase("chr", "Help cure hope raise on mind entity Chrome", SearchPrecisionScore.Regular, false)] [TestCase("chr", "Help cure hope raise on mind entity Chrome", SearchPrecisionScore.Low, true)] [TestCase("chr", "Candy Crush Saga from King", SearchPrecisionScore.Regular, false)] [TestCase("chr", "Candy Crush Saga from King", SearchPrecisionScore.None, true)] - [TestCase("ccs", "Candy Crush Saga from King", SearchPrecisionScore.Regular, true)] + [TestCase("ccs", "Candy Crush Saga from King", SearchPrecisionScore.Low, true)] [TestCase("cand", "Candy Crush Saga from King", SearchPrecisionScore.Regular, true)] - [TestCase("cand", "Help cure hope raise on mind entity Chrome", SearchPrecisionScore.Regular, - false)] + [TestCase("cand", "Help cure hope raise on mind entity Chrome", SearchPrecisionScore.Regular, false)] + [TestCase("vsc", VisualStudioCode, SearchPrecisionScore.Regular, true)] + [TestCase("vs", VisualStudioCode, SearchPrecisionScore.Regular, true)] + [TestCase("vc", VisualStudioCode, SearchPrecisionScore.Regular, true)] + [TestCase("vts", VisualStudioCode, SearchPrecisionScore.Regular, false)] public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( string queryString, string compareString, @@ -188,10 +192,8 @@ public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( [TestCase("exce", "OverLeaf-Latex: An online LaTeX editor", SearchPrecisionScore.Regular, false)] [TestCase("term", "Windows Terminal (Preview)", SearchPrecisionScore.Regular, true)] - [TestCase("sql s managa", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, - false)] - [TestCase("sql' s manag", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, - false)] + [TestCase("sql s managa", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, false)] + [TestCase("sql' s manag", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, false)] [TestCase("sql s manag", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] [TestCase("sql manag", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] [TestCase("sql", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] @@ -204,18 +206,13 @@ public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( [TestCase("mssms", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] [TestCase("msms", MicrosoftSqlServerManagementStudio, SearchPrecisionScore.Regular, true)] [TestCase("chr", "Shutdown", SearchPrecisionScore.Regular, false)] - [TestCase("chr", "Change settings for text-to-speech and for speech recognition (if installed).", - SearchPrecisionScore.Regular, false)] - [TestCase("ch r", "Change settings for text-to-speech and for speech recognition (if installed).", - SearchPrecisionScore.Regular, true)] + [TestCase("chr", "Change settings for text-to-speech and for speech recognition (if installed).", SearchPrecisionScore.Regular, false)] + [TestCase("ch r", "Change settings for text-to-speech and for speech recognition (if installed).", SearchPrecisionScore.Regular, true)] [TestCase("a test", "This is a test", SearchPrecisionScore.Regular, true)] [TestCase("test", "This is a test", SearchPrecisionScore.Regular, true)] [TestCase("cod", VisualStudioCode, SearchPrecisionScore.Regular, true)] [TestCase("code", VisualStudioCode, SearchPrecisionScore.Regular, true)] [TestCase("codes", "Visual Studio Codes", SearchPrecisionScore.Regular, true)] - [TestCase("vsc", VisualStudioCode, SearchPrecisionScore.Regular, true)] - [TestCase("vs", VisualStudioCode, SearchPrecisionScore.Regular, true)] - [TestCase("vc", VisualStudioCode, SearchPrecisionScore.Regular, true)] public void WhenGivenQuery_ShouldReturnResults_ContainingAllQuerySubstrings( string queryString, string compareString, @@ -300,15 +297,18 @@ public void WhenMultipleResults_ExactMatchingResult_ShouldHaveGreatestScore( $"Should be greater than{Environment.NewLine}" + $"Name of second: \"{secondName}\", Final Score: {secondScore}{Environment.NewLine}"); } - - [TestCase("vsc","Visual Studio Code", 100)] - [TestCase("jbr","JetBrain Rider",100)] - [TestCase("jr","JetBrain Rider",90)] - [TestCase("vs","Visual Studio",100)] - [TestCase("vs","Visual Studio Preview",100)] - [TestCase("vsp","Visual Studio Preview",100)] - [TestCase("vsp","Visual Studio",0)] - [TestCase("pc","Postman Canary",100)] + + [TestCase("vsc", "Visual Studio Code", 100)] + [TestCase("jbr", "JetBrain Rider", 100)] + [TestCase("jr", "JetBrain Rider", 66)] + [TestCase("vs", "Visual Studio", 100)] + [TestCase("vs", "Visual Studio Preview", 66)] + [TestCase("vsp", "Visual Studio Preview", 100)] + [TestCase("pc", "postman canary", 100)] + [TestCase("psc", "Postman super canary", 100)] + [TestCase("psc", "Postman super Canary", 100)] + [TestCase("vsp", "Visual Studio", 0)] + [TestCase("vps", "Visual Studio", 0)] public void WhenGivenAnAcronymQuery_ShouldReturnAcronymScore(string queryString, string compareString, int desiredScore) { From 8fb2dad65c55d5b6704f85635fc2ae96b72acfe8 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 1 Feb 2021 22:22:48 +1100 Subject: [PATCH 45/54] add tests --- Flow.Launcher.Test/FuzzyMatcherTest.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Test/FuzzyMatcherTest.cs b/Flow.Launcher.Test/FuzzyMatcherTest.cs index 32d2e8fdbf4..61dacf38d67 100644 --- a/Flow.Launcher.Test/FuzzyMatcherTest.cs +++ b/Flow.Launcher.Test/FuzzyMatcherTest.cs @@ -131,16 +131,17 @@ public void GivenQueryString_WhenAppliedPrecisionFiltering_ThenShouldReturnGreat [TestCase(Chrome, Chrome, 157)] [TestCase(Chrome, LastIsChrome, 147)] - [TestCase(Chrome, HelpCureHopeRaiseOnMindEntityChrome, 90)] + [TestCase("chro", HelpCureHopeRaiseOnMindEntityChrome, 50)] + [TestCase("chr", HelpCureHopeRaiseOnMindEntityChrome, 30)] [TestCase(Chrome, UninstallOrChangeProgramsOnYourComputer, 21)] [TestCase(Chrome, CandyCrushSagaFromKing, 0)] - [TestCase("sql", MicrosoftSqlServerManagementStudio, 90)] + [TestCase("sql", MicrosoftSqlServerManagementStudio, 110)] [TestCase("sql manag", MicrosoftSqlServerManagementStudio, 121)] //double spacing intended public void WhenGivenQueryString_ThenShouldReturn_TheDesiredScoring( string queryString, string compareString, int expectedScore) { // When, Given - var matcher = new StringMatcher(); + var matcher = new StringMatcher {UserSettingSearchPrecision = SearchPrecisionScore.Regular}; var rawScore = matcher.FuzzyMatch(queryString, compareString).RawScore; // Should @@ -162,6 +163,7 @@ public void WhenGivenQueryString_ThenShouldReturn_TheDesiredScoring( [TestCase("vs", VisualStudioCode, SearchPrecisionScore.Regular, true)] [TestCase("vc", VisualStudioCode, SearchPrecisionScore.Regular, true)] [TestCase("vts", VisualStudioCode, SearchPrecisionScore.Regular, false)] + [TestCase("wt", "Windows Terminal From Microsoft Store", SearchPrecisionScore.Regular, false)] public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( string queryString, string compareString, @@ -184,8 +186,8 @@ public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( // Should Assert.AreEqual(expectedPrecisionResult, matchResult.IsSearchPrecisionScoreMet(), - $"Query:{queryString}{Environment.NewLine} " + - $"Compare:{compareString}{Environment.NewLine}" + + $"Query: {queryString}{Environment.NewLine} " + + $"Compare: {compareString}{Environment.NewLine}" + $"Raw Score: {matchResult.RawScore}{Environment.NewLine}" + $"Precision Score: {(int)expectedPrecisionScore}"); } @@ -309,6 +311,7 @@ public void WhenMultipleResults_ExactMatchingResult_ShouldHaveGreatestScore( [TestCase("psc", "Postman super Canary", 100)] [TestCase("vsp", "Visual Studio", 0)] [TestCase("vps", "Visual Studio", 0)] + [TestCase(Chrome, HelpCureHopeRaiseOnMindEntityChrome, 75)] public void WhenGivenAnAcronymQuery_ShouldReturnAcronymScore(string queryString, string compareString, int desiredScore) { From f32cbaf331dbb606f8e86c35d03bb790c0f148c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 1 Feb 2021 19:57:08 +0800 Subject: [PATCH 46/54] Split name matching and desciption matching due to fuzzy change --- .../Programs/UWP.cs | 54 ++++++++++++------- .../Programs/Win32.cs | 50 +++++++++++------ 2 files changed, 71 insertions(+), 33 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs index 3ea78156d77..ed81606fc68 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs @@ -206,12 +206,12 @@ private static IEnumerable CurrentUserPackages() } catch (Exception e) { - ProgramLogger.LogException("UWP" ,"CurrentUserPackages", $"id","An unexpected error occured and " + ProgramLogger.LogException("UWP", "CurrentUserPackages", $"id", "An unexpected error occured and " + $"unable to verify if package is valid", e); return false; } - - + + return valid; }); return ps; @@ -263,24 +263,42 @@ public class Application : IProgram public string LogoPath { get; set; } public UWP Package { get; set; } - public Application(){} + public Application() { } public Result Result(string query, IPublicAPI api) { - var title = (Name, Description) switch - { - (var n, null) => n, - (var n, var d) when d.StartsWith(n) => d, - (var n, var d) when n.StartsWith(d) => n, - (var n, var d) when !string.IsNullOrEmpty(d) => $"{n}: {d}", - _ => Name - }; + string title; + MatchResult matchResult; - var matchResult = StringMatcher.FuzzySearch(query, title); + // We suppose Name won't be null + if (Description == null || Name.StartsWith(Description)) + { + title = Name; + matchResult = StringMatcher.FuzzySearch(query, title); + } + else if (Description.StartsWith(Name)) + { + title = Description; + matchResult = StringMatcher.FuzzySearch(query, Description); + } + else + { + title = $"{Name}: {Description}"; + var nameMatch = StringMatcher.FuzzySearch(query, Name); + 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 ": " + } + matchResult = desciptionMatch; + } + else matchResult = nameMatch; + } - if (!matchResult.Success) - return null; + if (!matchResult.Success) return null; var result = new Result { @@ -311,7 +329,7 @@ public List ContextMenus(IPublicAPI api) Action = _ => { - Main.StartProcess(Process.Start, + Main.StartProcess(Process.Start, new ProcessStartInfo( !string.IsNullOrEmpty(Main._settings.CustomizedExplorer) ? Main._settings.CustomizedExplorer @@ -403,14 +421,14 @@ internal string ResourceFromPri(string packageFullName, string packageName, stri public string FormattedPriReferenceValue(string packageName, string rawPriReferenceValue) { const string prefix = "ms-resource:"; - + if (string.IsNullOrWhiteSpace(rawPriReferenceValue) || !rawPriReferenceValue.StartsWith(prefix)) return rawPriReferenceValue; string key = rawPriReferenceValue.Substring(prefix.Length); if (key.StartsWith("//")) return $"{prefix}{key}"; - + if (!key.StartsWith("/")) { key = $"/{key}"; diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index 77278330a47..fd994aeb347 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -12,6 +12,7 @@ using Flow.Launcher.Infrastructure; using Flow.Launcher.Plugin.Program.Logger; using Flow.Launcher.Plugin.SharedCommands; +using Flow.Launcher.Plugin.SharedModels; namespace Flow.Launcher.Plugin.Program.Programs { @@ -36,19 +37,38 @@ public class Win32 : IProgram public Result Result(string query, IPublicAPI api) { - var title = (Name, Description) switch + string title; + MatchResult matchResult; + + // We suppose Name won't be null + if (Description == null || Name.StartsWith(Description)) { - (var n, null) => n, - (var n, var d) when d.StartsWith(n) => d, - (var n, var d) when n.StartsWith(d) => n, - (var n, var d) when !string.IsNullOrEmpty(d) => $"{n}: {d}", - _ => Name - }; + title = Name; + matchResult = StringMatcher.FuzzySearch(query, title); + } + else if (Description.StartsWith(Name)) + { + title = Description; + matchResult = StringMatcher.FuzzySearch(query, Description); + } + else + { + title = $"{Name}: {Description}"; + var nameMatch = StringMatcher.FuzzySearch(query, Name); + 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 ": " + } + matchResult = desciptionMatch; + } + else matchResult = nameMatch; + } - var matchResult = StringMatcher.FuzzySearch(query, title); + if (!matchResult.Success) return null; - if (!matchResult.Success) - return null; var result = new Result { @@ -58,7 +78,7 @@ public Result Result(string query, IPublicAPI api) Score = matchResult.Score, TitleHighlightData = matchResult.MatchData, ContextData = this, - Action = e => + Action = _ => { var info = new ProcessStartInfo { @@ -268,10 +288,10 @@ private static IEnumerable ProgramPaths(string directory, string[] suffi try { var paths = Directory.EnumerateFiles(directory, "*", new EnumerationOptions - { - IgnoreInaccessible = true, - RecurseSubdirectories = true - }) + { + IgnoreInaccessible = true, + RecurseSubdirectories = true + }) .Where(x => suffixes.Contains(Extension(x))); return paths; From 19918244ad1dc0f91b8df7ee24de93ea9f2fdffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 1 Feb 2021 19:59:56 +0800 Subject: [PATCH 47/54] fix a using --- Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs index ed81606fc68..a1f8e52284a 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs @@ -18,6 +18,7 @@ using Flow.Launcher.Plugin.Program.Logger; using IStream = AppxPackaing.IStream; using Rect = System.Windows.Rect; +using Flow.Launcher.Plugin.SharedModels; namespace Flow.Launcher.Plugin.Program.Programs { From 838d0ec583af2690d485b6af126bd66b3cea6611 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 2 Feb 2021 05:45:24 +1100 Subject: [PATCH 48/54] combine condition --- Flow.Launcher.Infrastructure/StringMatcher.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index cdb5c4e6896..decfdb27ce4 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -217,10 +217,8 @@ private bool IsAcronym(string stringToCompare, int compareStringIndex) { if (char.IsUpper(stringToCompare[compareStringIndex]) || char.IsNumber(stringToCompare[compareStringIndex]) || - char.IsDigit(stringToCompare[compareStringIndex])) - return true; - - if (compareStringIndex == 0) + char.IsDigit(stringToCompare[compareStringIndex]) || + compareStringIndex == 0) //0 index means char is the start of the compare string, which is an acronym return true; if (compareStringIndex != 0 && char.IsWhiteSpace(stringToCompare[compareStringIndex - 1])) From d9a4836118d4da3d7a12f20cc72a472ea6c7f6cc Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 2 Feb 2021 05:50:27 +1100 Subject: [PATCH 49/54] remove spacing --- Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs index a1f8e52284a..159c3a9a0ad 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs @@ -212,7 +212,6 @@ private static IEnumerable CurrentUserPackages() return false; } - return valid; }); return ps; From 2bdf69b431475530e2b60a7c5258f1b0f08cedcc Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 2 Feb 2021 07:41:36 +1100 Subject: [PATCH 50/54] separate acronym count and check --- Flow.Launcher.Infrastructure/StringMatcher.cs | 48 ++++++++++++++++--- Flow.Launcher.Test/FuzzyMatcherTest.cs | 4 ++ 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index decfdb27ce4..7a5b09e1011 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -72,7 +72,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; - var querySubstrings = queryWithoutCase.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); + var querySubstrings = queryWithoutCase.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); int currentQuerySubstringIndex = 0; var currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; var currentQuerySubstringCharacterIndex = 0; @@ -92,7 +92,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption // If acronyms matching successfully finished, this gets the remaining not matched acronyms for score calculation if (currentAcronymQueryIndex >= query.Length && acronymsMatched == query.Length) { - if (IsAcronym(stringToCompare, compareStringIndex)) + if (IsAcronymCount(stringToCompare, compareStringIndex)) acronymsTotalCount++; continue; } @@ -117,9 +117,11 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption currentAcronymQueryIndex++; } + } + if (IsAcronymCount(stringToCompare, compareStringIndex)) acronymsTotalCount++; - } + // Acronym end if (allQuerySubstringsMatched || fullStringToCompareWithoutCase[compareStringIndex] != @@ -214,14 +216,46 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption } private bool IsAcronym(string stringToCompare, int compareStringIndex) + { + if (IsAcronymChar(stringToCompare, compareStringIndex) || IsAcronymNumber(stringToCompare, compareStringIndex)) + return true; + + return false; + } + + // When counting acronyms, treat a set of numbers as one acronym ie. Visual 2019 as 2 acronyms instead of 5 + private bool IsAcronymCount(string stringToCompare, int compareStringIndex) + { + if (IsAcronymChar(stringToCompare, compareStringIndex)) + return true; + + if (char.IsNumber(stringToCompare[compareStringIndex]) || char.IsDigit(stringToCompare[compareStringIndex])) + { + return compareStringIndex switch + { + int i when i == 0 => true, + int i when char.IsWhiteSpace(stringToCompare[i - 1]) => true, + _ => false, + }; + } + + return false; + } + + private bool IsAcronymChar(string stringToCompare, int compareStringIndex) { if (char.IsUpper(stringToCompare[compareStringIndex]) || - char.IsNumber(stringToCompare[compareStringIndex]) || - char.IsDigit(stringToCompare[compareStringIndex]) || - compareStringIndex == 0) //0 index means char is the start of the compare string, which is an acronym + compareStringIndex == 0 || //0 index means char is the start of the compare string, which is an acronym + compareStringIndex != 0 && char.IsWhiteSpace(stringToCompare[compareStringIndex - 1])) return true; - if (compareStringIndex != 0 && char.IsWhiteSpace(stringToCompare[compareStringIndex - 1])) + return false; + } + + private bool IsAcronymNumber(string stringToCompare, int compareStringIndex) + { + if (char.IsNumber(stringToCompare[compareStringIndex]) || + char.IsDigit(stringToCompare[compareStringIndex])) return true; return false; diff --git a/Flow.Launcher.Test/FuzzyMatcherTest.cs b/Flow.Launcher.Test/FuzzyMatcherTest.cs index 61dacf38d67..bbddcbd2ad4 100644 --- a/Flow.Launcher.Test/FuzzyMatcherTest.cs +++ b/Flow.Launcher.Test/FuzzyMatcherTest.cs @@ -163,7 +163,11 @@ public void WhenGivenQueryString_ThenShouldReturn_TheDesiredScoring( [TestCase("vs", VisualStudioCode, SearchPrecisionScore.Regular, true)] [TestCase("vc", VisualStudioCode, SearchPrecisionScore.Regular, true)] [TestCase("vts", VisualStudioCode, SearchPrecisionScore.Regular, false)] + [TestCase("vcs", VisualStudioCode, SearchPrecisionScore.Regular, false)] [TestCase("wt", "Windows Terminal From Microsoft Store", SearchPrecisionScore.Regular, false)] + [TestCase("vsp", "Visual Studio 2019 Preview", SearchPrecisionScore.Regular, true)] + [TestCase("vsp", "2019 Visual Studio Preview", SearchPrecisionScore.Regular, true)] + [TestCase("2019p", "Visual Studio 2019 Preview", SearchPrecisionScore.Regular, true)] public void WhenGivenDesiredPrecision_ThenShouldReturn_AllResultsGreaterOrEqual( string queryString, string compareString, From f9b7294b9341736fb91a509e5d86ac84e796f74a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 2 Feb 2021 12:38:41 +0800 Subject: [PATCH 51/54] Optimize code --- Flow.Launcher.Infrastructure/StringMatcher.cs | 51 +++++++------------ 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 7a5b09e1011..48d89b86207 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -229,52 +229,35 @@ private bool IsAcronymCount(string stringToCompare, int compareStringIndex) if (IsAcronymChar(stringToCompare, compareStringIndex)) return true; - if (char.IsNumber(stringToCompare[compareStringIndex]) || char.IsDigit(stringToCompare[compareStringIndex])) - { - return compareStringIndex switch - { - int i when i == 0 => true, - int i when char.IsWhiteSpace(stringToCompare[i - 1]) => true, - _ => false, - }; - } - - return false; - } + if (IsAcronymNumber(stringToCompare, compareStringIndex)) + return compareStringIndex == 0 || char.IsWhiteSpace(stringToCompare[compareStringIndex - 1]); - private bool IsAcronymChar(string stringToCompare, int compareStringIndex) - { - if (char.IsUpper(stringToCompare[compareStringIndex]) || - compareStringIndex == 0 || //0 index means char is the start of the compare string, which is an acronym - compareStringIndex != 0 && char.IsWhiteSpace(stringToCompare[compareStringIndex - 1])) - return true; return false; } - private bool IsAcronymNumber(string stringToCompare, int compareStringIndex) - { - if (char.IsNumber(stringToCompare[compareStringIndex]) || - char.IsDigit(stringToCompare[compareStringIndex])) - return true; + private bool IsAcronymChar(string stringToCompare, int compareStringIndex) + => char.IsUpper(stringToCompare[compareStringIndex]) || + compareStringIndex == 0 || // 0 index means char is the start of the compare string, which is an acronym + char.IsWhiteSpace(stringToCompare[compareStringIndex - 1]); - return false; - } + private bool IsAcronymNumber(string stringToCompare, int compareStringIndex) => stringToCompare[compareStringIndex] >= 0 && stringToCompare[compareStringIndex] <= 9; // To get the index of the closest space which preceeds the first matching index private int CalculateClosestSpaceIndex(List spaceIndices, int firstMatchIndex) { - if (spaceIndices.Count == 0) - { - return -1; - } - else + var closestSpaceIndex = -1; + + // spaceIndices should be ordered asc + foreach (var index in spaceIndices) { - int? ind = spaceIndices.OrderBy(item => (firstMatchIndex - item)) - .FirstOrDefault(item => firstMatchIndex > item); - int closestSpaceIndex = ind ?? -1; - return closestSpaceIndex; + if (index < firstMatchIndex) + closestSpaceIndex = index; + else + break; } + + return closestSpaceIndex; } private static bool AllPreviousCharsMatched(int startIndexToVerify, int currentQuerySubstringCharacterIndex, From 65a6548c56a23c043bb95afb75bef58c51ad2d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 2 Feb 2021 12:42:55 +0800 Subject: [PATCH 52/54] Use int instead of decimal --- Flow.Launcher.Infrastructure/StringMatcher.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 48d89b86207..6d53cc72204 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -66,8 +66,8 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var currentAcronymQueryIndex = 0; var acronymMatchData = new List(); - decimal acronymsTotalCount = 0; - decimal acronymsMatched = 0; + int acronymsTotalCount = 0; + int acronymsMatched = 0; var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; @@ -192,7 +192,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption // return acronym match if all query char matched if (acronymsMatched > 0 && acronymsMatched == query.Length) { - int acronymScore = (int)(acronymsMatched / acronymsTotalCount * 100); + int acronymScore = acronymsMatched * 100 / acronymsTotalCount; if (acronymScore >= (int)UserSettingSearchPrecision) { From 433139893242735e9980cd6b173c8e764b210ace Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 2 Feb 2021 20:28:52 +1100 Subject: [PATCH 53/54] update summary, comments & formatting --- Flow.Launcher.Infrastructure/StringMatcher.cs | 19 ++++++++----------- .../Programs/UWP.cs | 3 ++- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 6d53cc72204..3ffa9f7b11c 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -31,18 +31,18 @@ public MatchResult FuzzyMatch(string query, string stringToCompare) } /// - /// Current method includes two part, Acronym Match and Fuzzy Search: + /// Current method has two parts, Acronym Match and Fuzzy Search: /// /// Acronym Match: - /// Charater lists below will be considered as Acronym + /// Charater listed below will be considered as acronym /// 1. Character on index 0 /// 2. Character appears after a space /// 3. Character that is UpperCase /// 4. Character that is number /// - /// Acronym Search will match all query when meeting with Acronyms in the stringToCompare - /// If any of the character in Query isn't matched with the string, Acronym Search fail. - /// Score will be calculated based on the number of mismatched acronym before all query has been matched + /// Acronym Match will succeed when all query characters match with acronyms in stringToCompare. + /// If any of the characters in the query isn't matched with stringToCompare, Acronym Match will fail. + /// Score will be calculated based the percentage of all query characters matched with total acronyms in stringToCompare. /// /// Fuzzy Search: /// Character matching + substring matching; @@ -65,7 +65,6 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption var currentAcronymQueryIndex = 0; var acronymMatchData = new List(); - int acronymsTotalCount = 0; int acronymsMatched = 0; @@ -106,7 +105,7 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption if (fullStringToCompareWithoutCase[compareStringIndex] == ' ' && currentQuerySubstringIndex == 0) spaceIndices.Add(compareStringIndex); - // Acronym check + // Acronym Match if (IsAcronym(stringToCompare, compareStringIndex)) { if (fullStringToCompareWithoutCase[compareStringIndex] == @@ -122,8 +121,6 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption if (IsAcronymCount(stringToCompare, compareStringIndex)) acronymsTotalCount++; - // Acronym end - if (allQuerySubstringsMatched || fullStringToCompareWithoutCase[compareStringIndex] != currentQuerySubstring[currentQuerySubstringCharacterIndex]) { @@ -232,7 +229,6 @@ private bool IsAcronymCount(string stringToCompare, int compareStringIndex) if (IsAcronymNumber(stringToCompare, compareStringIndex)) return compareStringIndex == 0 || char.IsWhiteSpace(stringToCompare[compareStringIndex - 1]); - return false; } @@ -241,7 +237,8 @@ private bool IsAcronymChar(string stringToCompare, int compareStringIndex) compareStringIndex == 0 || // 0 index means char is the start of the compare string, which is an acronym char.IsWhiteSpace(stringToCompare[compareStringIndex - 1]); - private bool IsAcronymNumber(string stringToCompare, int compareStringIndex) => stringToCompare[compareStringIndex] >= 0 && stringToCompare[compareStringIndex] <= 9; + private bool IsAcronymNumber(string stringToCompare, int compareStringIndex) + => stringToCompare[compareStringIndex] >= 0 && stringToCompare[compareStringIndex] <= 9; // To get the index of the closest space which preceeds the first matching index private int CalculateClosestSpaceIndex(List spaceIndices, int firstMatchIndex) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs index 159c3a9a0ad..5db26aa70e6 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs @@ -298,7 +298,8 @@ public Result Result(string query, IPublicAPI api) else matchResult = nameMatch; } - if (!matchResult.Success) return null; + if (!matchResult.Success) + return null; var result = new Result { From 2602cc05c00fe98a9f2a3f72dd477f2617f75a45 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 2 Feb 2021 20:30:58 +1100 Subject: [PATCH 54/54] version bump Program plugin --- Plugins/Flow.Launcher.Plugin.Program/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/plugin.json b/Plugins/Flow.Launcher.Plugin.Program/plugin.json index 1dedd990966..f713a33ece5 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": "1.3.0", + "Version": "1.4.0", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Program.dll",