From df9b09eeaeb87d41caa5f4fcdf08cd513c4c4915 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 00:09:03 +1000 Subject: [PATCH 01/17] Add tests for fuzzy search and CalScore method --- Wox.Test/FuzzyMatcherTest.cs | 128 ++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) diff --git a/Wox.Test/FuzzyMatcherTest.cs b/Wox.Test/FuzzyMatcherTest.cs index 2856a0fde..8796d83b3 100644 --- a/Wox.Test/FuzzyMatcherTest.cs +++ b/Wox.Test/FuzzyMatcherTest.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using NUnit.Framework; using Wox.Infrastructure; @@ -9,6 +10,27 @@ namespace Wox.Test [TestFixture] public class FuzzyMatcherTest { + public List GetSearchStrings() + => new List + { + "Chrome", + "Choose which programs you want Windows to use for activities like web browsing, editing photos, sending e-mail, and playing music.", + "Help cure hope raise on mind entity Chrome ", + "Candy Crush Saga from King", + "Uninstall or change programs on your computer", + "Add, change, and manage fonts on your computer", + "Last is chrome", + "1111" + }; + + public List GetPrecisionScores() + => new List + { + 0, //no precision + 20, //low + 50 //regular + }; + [Test] public void MatchTest() { @@ -39,5 +61,109 @@ namespace Wox.Test Assert.IsTrue(results[1].Title == "Install Package"); Assert.IsTrue(results[2].Title == "file open in browser-test"); } + + [TestCase("Chrome")] + public void WhenGivenNotAllCharactersFoundInSearchStringThenShouldReturnZeroScore(string searchString) + { + var compareString = "Can have rum only in my glass"; + + var scoreResult = FuzzyMatcher.Create(compareString).Evaluate(searchString).Score; + + Assert.True(scoreResult == 0); + } + + + //[TestCase("c", 50)] + //[TestCase("ch", 50)] + //[TestCase("chr", 50)] + [TestCase("chrom")] + [TestCase("chrome")] + //[TestCase("chrom", 0)] + //[TestCase("cand", 50)] + //[TestCase("cpywa", 0)] + [TestCase("ccs")] + public void WhenGivenStringsAndAppliedPrecisionFilteringThenShouldReturnGreaterThanPrecisionScoreResults(string searchTerm) + { + var results = new List(); + + foreach (var str in GetSearchStrings()) + { + results.Add(new Result + { + Title = str, + Score = FuzzyMatcher.Create(searchTerm).Evaluate(str).Score + }); + } + + StringMatcher.UserSettingSearchPrecision = "None"; + + StringMatcher.FuzzySearch(searchTerm, "blah", new MatchOption()).IsPreciciseMatch(); + + StringMatcher.UserSettingSearchPrecision = "Regular"; + + StringMatcher.FuzzySearch(searchTerm, "blah", new MatchOption()).IsPreciciseMatch(); + StringMatcher.FuzzySearch(searchTerm, "blah", new MatchOption()).IsPreciciseMatch(); + + foreach (var precisionScore in GetPrecisionScores()) + { + var filteredResult = results.Where(result => result.Score >= precisionScore).Select(result => result).OrderByDescending(x => x.Score).ToList(); + + Debug.WriteLine(""); + Debug.WriteLine("###############################################"); + Debug.WriteLine("SEARCHTERM: " + searchTerm + ", GreaterThanSearchPrecisionScore: " + precisionScore); + foreach (var item in filteredResult) + { + Debug.WriteLine("SCORE: " + item.Score.ToString() + ", FoundString: " + item.Title); + } + Debug.WriteLine("###############################################"); + Debug.WriteLine(""); + + Assert.IsFalse(filteredResult.Any(x => x.Score < precisionScore)); + } + } + + [TestCase("chrome")] + public void WhenGivenStringsForCalScoreMethodThenShouldAlwaysReturnSpecificScore(string searchTerm) + { + var searchStrings = new List + { + "Chrome",//SCORE: 107 + "Last is chrome",//SCORE: 53 + "Help cure hope raise on mind entity Chrome",//SCORE: 21 + "Uninstall or change programs on your computer", //SCORE: 15 + "Candy Crush Saga from King"//SCORE: 0 + } + .OrderByDescending(x => x) + .ToList(); + + var results = new List(); + + foreach (var str in searchStrings) + { + results.Add(new Result + { + Title = str, + Score = StringMatcher.FuzzySearch(searchTerm, str, new MatchOption()).Score + }); + } + + var orderedResults = results.OrderByDescending(x => x.Title).ToList(); + + Debug.WriteLine(""); + Debug.WriteLine("###############################################"); + Debug.WriteLine("SEARCHTERM: " + searchTerm); + foreach (var item in orderedResults) + { + Debug.WriteLine("SCORE: " + item.Score.ToString() + ", FoundString: " + item.Title); + } + Debug.WriteLine("###############################################"); + Debug.WriteLine(""); + + Assert.IsTrue(orderedResults[0].Score == 15 && orderedResults[0].Title == searchStrings[0]); + Assert.IsTrue(orderedResults[1].Score == 53 && orderedResults[1].Title == searchStrings[1]); + Assert.IsTrue(orderedResults[2].Score == 21 && orderedResults[2].Title == searchStrings[2]); + Assert.IsTrue(orderedResults[3].Score == 107 && orderedResults[3].Title == searchStrings[3]); + Assert.IsTrue(orderedResults[4].Score == 0 && orderedResults[4].Title == searchStrings[4]); + } } } From 2301478b3f9c96e0bc936c95dffa6847cbba03eb Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 00:09:56 +1000 Subject: [PATCH 02/17] update --- Wox.Test/Wox.Test.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/Wox.Test/Wox.Test.csproj b/Wox.Test/Wox.Test.csproj index 8337d5919..385fe023e 100644 --- a/Wox.Test/Wox.Test.csproj +++ b/Wox.Test/Wox.Test.csproj @@ -45,6 +45,7 @@ ..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll + From 9ab9ea4c2ee3750ab586f26301589b61f3fb51b7 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 13:27:28 +1000 Subject: [PATCH 03/17] Add precision score tests for new function --- Wox.Test/FuzzyMatcherTest.cs | 55 ++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/Wox.Test/FuzzyMatcherTest.cs b/Wox.Test/FuzzyMatcherTest.cs index 8796d83b3..5a54112f5 100644 --- a/Wox.Test/FuzzyMatcherTest.cs +++ b/Wox.Test/FuzzyMatcherTest.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -24,12 +25,16 @@ namespace Wox.Test }; public List GetPrecisionScores() - => new List - { - 0, //no precision - 20, //low - 50 //regular - }; + { + var listToReturn = new List(); + + Enum.GetValues(typeof(StringMatcher.SearchPrecisionScore)) + .Cast() + .ToList() + .ForEach(x => listToReturn.Add((int)x)); + + return listToReturn; + } [Test] public void MatchTest() @@ -50,7 +55,7 @@ namespace Wox.Test results.Add(new Result { Title = str, - Score = FuzzyMatcher.Create("inst").Evaluate(str).Score + Score = StringMatcher.FuzzySearch("inst", str, new MatchOption()).Score }); } @@ -67,7 +72,7 @@ namespace Wox.Test { var compareString = "Can have rum only in my glass"; - var scoreResult = FuzzyMatcher.Create(compareString).Evaluate(searchString).Score; + var scoreResult = StringMatcher.FuzzySearch(searchString, compareString, new MatchOption()).Score; Assert.True(scoreResult == 0); } @@ -75,7 +80,7 @@ namespace Wox.Test //[TestCase("c", 50)] //[TestCase("ch", 50)] - //[TestCase("chr", 50)] + [TestCase("chr")] [TestCase("chrom")] [TestCase("chrome")] //[TestCase("chrom", 0)] @@ -91,18 +96,9 @@ namespace Wox.Test results.Add(new Result { Title = str, - Score = FuzzyMatcher.Create(searchTerm).Evaluate(str).Score + Score = StringMatcher.FuzzySearch(searchTerm, str, new MatchOption()).Score }); - } - - StringMatcher.UserSettingSearchPrecision = "None"; - - StringMatcher.FuzzySearch(searchTerm, "blah", new MatchOption()).IsPreciciseMatch(); - - StringMatcher.UserSettingSearchPrecision = "Regular"; - - StringMatcher.FuzzySearch(searchTerm, "blah", new MatchOption()).IsPreciciseMatch(); - StringMatcher.FuzzySearch(searchTerm, "blah", new MatchOption()).IsPreciciseMatch(); + } foreach (var precisionScore in GetPrecisionScores()) { @@ -123,7 +119,7 @@ namespace Wox.Test } [TestCase("chrome")] - public void WhenGivenStringsForCalScoreMethodThenShouldAlwaysReturnSpecificScore(string searchTerm) + public void WhenGivenStringsForCalScoreMethodThenShouldReturnCurrentScoring(string searchTerm) { var searchStrings = new List { @@ -165,5 +161,22 @@ namespace Wox.Test Assert.IsTrue(orderedResults[3].Score == 107 && orderedResults[3].Title == searchStrings[3]); Assert.IsTrue(orderedResults[4].Score == 0 && orderedResults[4].Title == searchStrings[4]); } + + [TestCase("chr", "Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("chr", "Help cure hope raise on mind entity Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("chr", "Help cure hope raise on mind entity Chrome", (int)StringMatcher.SearchPrecisionScore.Low, true)] + [TestCase("chr", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("chr", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.Low, true)] + public void WhenGivenDesiredPrecisionIsRegularShouldReturnAllResultsEqualGreaterThanRegular(string queryString, string compareString, + int expectedPrecisionScore, bool expectedPrecisionResult) + { + var expectedPrecisionString = (StringMatcher.SearchPrecisionScore)expectedPrecisionScore; + StringMatcher.UserSettingSearchPrecision = expectedPrecisionString.ToString(); + var matchResult = StringMatcher.FuzzySearch(queryString, compareString, new MatchOption()); + var matchScore = matchResult.Score; + var matchPrecisionResult = matchResult.IsPreciciseMatch(); + Debug.WriteLine(matchScore); + Assert.IsTrue(matchPrecisionResult == expectedPrecisionResult); + } } } From e5753c54a63f0b355501508c9ad92e04692616a1 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 14:24:38 +1000 Subject: [PATCH 04/17] Convert StringMatcher class to static and move code from FuzzySearch --- Wox.Infrastructure/StringMatcher.cs | 146 +++++++++++++++++++++++++--- 1 file changed, 132 insertions(+), 14 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index 0ef4f1426..c619bc9a8 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -1,20 +1,21 @@ using System; -using System.Collections.Generic; using System.Linq; -using Wox.Infrastructure; +using System.Text; using Wox.Infrastructure.Logger; +using Wox.Infrastructure.UserSettings; namespace Wox.Infrastructure { public static class StringMatcher { + public static string UserSettingSearchPrecision { get; set; } + + [Obsolete("This method is obsolete and should not be used. Please use the static function StringMatcher.FuzzySearch")] public static int Score(string source, string target) { if (!string.IsNullOrEmpty(source) && !string.IsNullOrEmpty(target)) { - FuzzyMatcher matcher = FuzzyMatcher.Create(target); - var score = matcher.Evaluate(source).Score; - return score; + return FuzzySearch(target, source, new MatchOption()).Score; } else { @@ -22,6 +23,97 @@ namespace Wox.Infrastructure } } + [Obsolete("This method is obsolete and should not be used. Please use the static function StringMatcher.FuzzySearch")] + public static bool IsMatch(string source, string target) + { + return FuzzySearch(target, source, new MatchOption()).Score > 0; + } + + public enum SearchPrecisionScore + { + Regular = 50, + Low = 20, + None = 0 + } + + /// + /// refer to https://github.com/mattyork/fuzzy + /// + public static MatchResult FuzzySearch(string query, string stringToCompare, MatchOption opt) + { + if (string.IsNullOrEmpty(stringToCompare) || string.IsNullOrEmpty(query)) return new MatchResult { Success = false }; + + query.Trim(); + + var len = stringToCompare.Length; + var compareString = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; + var pattern = opt.IgnoreCase ? query.ToLower() : query; + + var sb = new StringBuilder(stringToCompare.Length + (query.Length * (opt.Prefix.Length + opt.Suffix.Length))); + var patternIdx = 0; + var firstMatchIndex = -1; + var lastMatchIndex = 0; + char ch; + for (var idx = 0; idx < len; idx++) + { + ch = stringToCompare[idx]; + if (compareString[idx] == pattern[patternIdx]) + { + if (firstMatchIndex < 0) + firstMatchIndex = idx; + lastMatchIndex = idx + 1; + + sb.Append(opt.Prefix + ch + opt.Suffix); + patternIdx += 1; + } + else + { + sb.Append(ch); + } + + // match success, append remain char + if (patternIdx == pattern.Length && (idx + 1) != compareString.Length) + { + sb.Append(stringToCompare.Substring(idx + 1)); + break; + } + } + + // return rendered string if we have a match for every char + if (patternIdx == pattern.Length) + { + return new MatchResult + { + Success = true, + Value = sb.ToString(), + Score = CalScore(query, stringToCompare, firstMatchIndex, lastMatchIndex - firstMatchIndex) + }; + } + + return new MatchResult { Success = false }; + } + + private static int CalScore(string query, string stringToCompare, int firstIndex, int matchLen) + { + //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, while the score is lower if they are more spread out + var score = 100 * (query.Length + 1) / ((1 + firstIndex) + (matchLen + 1)); + //a match with less characters assigning more weights + if (stringToCompare.Length - query.Length < 5) + score = score + 20; + else if (stringToCompare.Length - query.Length < 10) + score = score + 10; + + return score; + } + + public static bool IsPreciciseMatch(this MatchResult matchResult) + { + var precisionScore = (SearchPrecisionScore)Enum.Parse(typeof(SearchPrecisionScore), + UserSettingSearchPrecision ?? SearchPrecisionScore.Regular.ToString()); + return matchResult.Score >= (int)precisionScore; + } + public static int ScoreForPinyin(string source, string target) { if (!string.IsNullOrEmpty(source) && !string.IsNullOrEmpty(target)) @@ -34,12 +126,12 @@ namespace Wox.Infrastructure if (Alphabet.ContainsChinese(source)) { - FuzzyMatcher matcher = FuzzyMatcher.Create(target); - var combination = Alphabet.PinyinComination(source); - var pinyinScore = combination.Select(pinyin => matcher.Evaluate(string.Join("", pinyin)).Score) + var combination = Alphabet.PinyinComination(source); + var pinyinScore = combination + .Select(pinyin => FuzzySearch(target, string.Join("", pinyin), new MatchOption()).Score) .Max(); - var acronymScore = combination.Select(Alphabet.Acronym) - .Select(pinyin => matcher.Evaluate(pinyin).Score) + var acronymScore = combination.Select(Alphabet.Acronym) + .Select(pinyin => FuzzySearch(target, pinyin, new MatchOption()).Score) .Max(); var score = Math.Max(pinyinScore, acronymScore); return score; @@ -53,11 +145,37 @@ namespace Wox.Infrastructure { return 0; } + } + } + + public class MatchResult + { + public bool Success { get; set; } + public int Score { get; set; } + /// + /// hightlight string + /// + public string Value { get; set; } + } + + public class MatchOption + { + public MatchOption() + { + Prefix = ""; + Suffix = ""; + IgnoreCase = true; } - public static bool IsMatch(string source, string target) - { - return Score(source, target) > 0; - } + /// + /// prefix of match char, use for hightlight + /// + public string Prefix { get; set; } + /// + /// suffix of match char, use for hightlight + /// + public string Suffix { get; set; } + + public bool IgnoreCase { get; set; } } } From fbb5d4a4a65db3ed9359d028b859e1330b251338 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 14:26:15 +1000 Subject: [PATCH 05/17] Make FuzzMatcher class obsolete and keep backwards compatibility --- Wox.Infrastructure/FuzzyMatcher.cs | 100 +---------------------------- 1 file changed, 3 insertions(+), 97 deletions(-) diff --git a/Wox.Infrastructure/FuzzyMatcher.cs b/Wox.Infrastructure/FuzzyMatcher.cs index c2d7e02e9..cb1e735f5 100644 --- a/Wox.Infrastructure/FuzzyMatcher.cs +++ b/Wox.Infrastructure/FuzzyMatcher.cs @@ -1,10 +1,8 @@ -using System.Text; +using System; namespace Wox.Infrastructure { - /// - /// refer to https://github.com/mattyork/fuzzy - /// + [Obsolete("This class is obsolete and should not be used. Please use the static function StringMatcher.FuzzySearch")] public class FuzzyMatcher { private string query; @@ -28,99 +26,7 @@ namespace Wox.Infrastructure public MatchResult Evaluate(string str) { - if (string.IsNullOrEmpty(str) || string.IsNullOrEmpty(query)) return new MatchResult { Success = false }; - - var len = str.Length; - var compareString = opt.IgnoreCase ? str.ToLower() : str; - var pattern = opt.IgnoreCase ? query.ToLower() : query; - - var sb = new StringBuilder(str.Length + (query.Length * (opt.Prefix.Length + opt.Suffix.Length))); - var patternIdx = 0; - var firstMatchIndex = -1; - var lastMatchIndex = 0; - char ch; - for (var idx = 0; idx < len; idx++) - { - ch = str[idx]; - if (compareString[idx] == pattern[patternIdx]) - { - if (firstMatchIndex < 0) - firstMatchIndex = idx; - lastMatchIndex = idx + 1; - - sb.Append(opt.Prefix + ch + opt.Suffix); - patternIdx += 1; - } - else - { - sb.Append(ch); - } - - // match success, append remain char - if (patternIdx == pattern.Length && (idx + 1) != compareString.Length) - { - sb.Append(str.Substring(idx + 1)); - break; - } - } - - // return rendered string if we have a match for every char - if (patternIdx == pattern.Length) - { - return new MatchResult - { - Success = true, - Value = sb.ToString(), - Score = CalScore(str, firstMatchIndex, lastMatchIndex - firstMatchIndex) - }; - } - - return new MatchResult { Success = false }; + return StringMatcher.FuzzySearch(query, str, opt); } - - private int CalScore(string str, int firstIndex, int matchLen) - { - //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, while the score is lower if they are more spread out - var score = 100 * (query.Length + 1) / ((1 + firstIndex) + (matchLen + 1)); - //a match with less characters assigning more weights - if (str.Length - query.Length < 5) - score = score + 20; - else if (str.Length - query.Length < 10) - score = score + 10; - - return score; - } - } - - public class MatchResult - { - public bool Success { get; set; } - public int Score { get; set; } - /// - /// hightlight string - /// - public string Value { get; set; } - } - - public class MatchOption - { - public MatchOption() - { - Prefix = ""; - Suffix = ""; - IgnoreCase = true; - } - - /// - /// prefix of match char, use for hightlight - /// - public string Prefix { get; set; } - /// - /// suffix of match char, use for hightlight - /// - public string Suffix { get; set; } - - public bool IgnoreCase { get; set; } } } From d8a9630548423b30a57a10bfd2c42a3ea09daa59 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 14:27:07 +1000 Subject: [PATCH 06/17] Update test --- Wox.Test/FuzzyMatcherTest.cs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Wox.Test/FuzzyMatcherTest.cs b/Wox.Test/FuzzyMatcherTest.cs index 5a54112f5..f6b309d05 100644 --- a/Wox.Test/FuzzyMatcherTest.cs +++ b/Wox.Test/FuzzyMatcherTest.cs @@ -161,21 +161,32 @@ namespace Wox.Test Assert.IsTrue(orderedResults[3].Score == 107 && orderedResults[3].Title == searchStrings[3]); Assert.IsTrue(orderedResults[4].Score == 0 && orderedResults[4].Title == searchStrings[4]); } - + + [TestCase("goo", "Google Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("chr", "Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("chr", "Google Chrome", (int)StringMatcher.SearchPrecisionScore.Low, true)] [TestCase("chr", "Help cure hope raise on mind entity Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, false)] [TestCase("chr", "Help cure hope raise on mind entity Chrome", (int)StringMatcher.SearchPrecisionScore.Low, true)] [TestCase("chr", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("chr", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.Low, true)] + [TestCase("chr", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.None, true)] + [TestCase("ccs", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.Low, true)] + [TestCase("cand", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("cand", "Help cure hope raise on mind entity Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, false)] public void WhenGivenDesiredPrecisionIsRegularShouldReturnAllResultsEqualGreaterThanRegular(string queryString, string compareString, int expectedPrecisionScore, bool expectedPrecisionResult) { var expectedPrecisionString = (StringMatcher.SearchPrecisionScore)expectedPrecisionScore; StringMatcher.UserSettingSearchPrecision = expectedPrecisionString.ToString(); var matchResult = StringMatcher.FuzzySearch(queryString, compareString, new MatchOption()); - var matchScore = matchResult.Score; - var matchPrecisionResult = matchResult.IsPreciciseMatch(); - Debug.WriteLine(matchScore); + + Debug.WriteLine(""); + Debug.WriteLine("###############################################"); + Debug.WriteLine($"SearchTerm: {queryString} PrecisionLevelSetAt: {expectedPrecisionString} ({expectedPrecisionScore})"); + Debug.WriteLine($"SCORE: {matchResult.Score.ToString()}, ComparedString: {compareString}"); + Debug.WriteLine("###############################################"); + Debug.WriteLine(""); + + var matchPrecisionResult = matchResult.IsPreciciseMatch(); Assert.IsTrue(matchPrecisionResult == expectedPrecisionResult); } } From 3f90611edffa8cf5ec2dd3fcf99ddb5a6fea9d50 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 14:27:46 +1000 Subject: [PATCH 07/17] Initial prep of settings and start up default --- Wox.Infrastructure/UserSettings/Settings.cs | 12 +++++++++++- Wox/App.xaml.cs | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Wox.Infrastructure/UserSettings/Settings.cs b/Wox.Infrastructure/UserSettings/Settings.cs index fc676d783..5e22ca493 100644 --- a/Wox.Infrastructure/UserSettings/Settings.cs +++ b/Wox.Infrastructure/UserSettings/Settings.cs @@ -21,6 +21,17 @@ namespace Wox.Infrastructure.UserSettings public string ResultFontWeight { get; set; } public string ResultFontStretch { get; set; } + private string _querySearchPrecision { get; set; } = StringMatcher.SearchPrecisionScore.Regular.ToString(); + public string QuerySearchPrecision + { + get { return _querySearchPrecision; } + set + { + _querySearchPrecision = value; + StringMatcher.UserSettingSearchPrecision = value; + } + } + public bool AutoUpdates { get; set; } = false; public double WindowLeft { get; set; } @@ -63,7 +74,6 @@ namespace Wox.Infrastructure.UserSettings [JsonConverter(typeof(StringEnumConverter))] public LastQueryMode LastQueryMode { get; set; } = LastQueryMode.Selected; - } public enum LastQueryMode diff --git a/Wox/App.xaml.cs b/Wox/App.xaml.cs index 3407cf576..b66549b38 100644 --- a/Wox/App.xaml.cs +++ b/Wox/App.xaml.cs @@ -54,6 +54,8 @@ namespace Wox _settingsVM = new SettingWindowViewModel(); _settings = _settingsVM.Settings; + StringMatcher.UserSettingSearchPrecision = _settings.QuerySearchPrecision; + PluginManager.LoadPlugins(_settings.PluginSettings); _mainVM = new MainViewModel(_settings); var window = new MainWindow(_settings, _mainVM); From d0fac80eb4dcd60e5aa48d7f476481a6a4401fc7 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 14:30:33 +1000 Subject: [PATCH 08/17] Update browserbookmark plugin with new code --- Plugins/Wox.Plugin.BrowserBookmark/Main.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Plugins/Wox.Plugin.BrowserBookmark/Main.cs b/Plugins/Wox.Plugin.BrowserBookmark/Main.cs index 23f1135a6..041ba2ae4 100644 --- a/Plugins/Wox.Plugin.BrowserBookmark/Main.cs +++ b/Plugins/Wox.Plugin.BrowserBookmark/Main.cs @@ -40,9 +40,8 @@ namespace Wox.Plugin.BrowserBookmark if (!topResults) { - // Since we mixed chrome and firefox bookmarks, we should order them again - var fuzzyMatcher = FuzzyMatcher.Create(param); - returnList = cachedBookmarks.Where(o => MatchProgram(o, fuzzyMatcher)).ToList(); + // Since we mixed chrome and firefox bookmarks, we should order them again + returnList = cachedBookmarks.Where(o => MatchProgram(o, param)).ToList(); returnList = returnList.OrderByDescending(o => o.Score).ToList(); } @@ -61,11 +60,11 @@ namespace Wox.Plugin.BrowserBookmark }).ToList(); } - private bool MatchProgram(Bookmark bookmark, FuzzyMatcher matcher) + private bool MatchProgram(Bookmark bookmark, string queryString) { - if ((bookmark.Score = matcher.Evaluate(bookmark.Name).Score) > 0) return true; - if ((bookmark.Score = matcher.Evaluate(bookmark.PinyinName).Score) > 0) return true; - if ((bookmark.Score = matcher.Evaluate(bookmark.Url).Score / 10) > 0) return true; + if ((bookmark.Score = StringMatcher.FuzzySearch(queryString, bookmark.Name, new MatchOption()).Score) > 0) return true; + if ((bookmark.Score = StringMatcher.FuzzySearch(queryString, bookmark.PinyinName, new MatchOption).Score) > 0) return true; + if ((bookmark.Score = StringMatcher.FuzzySearch(queryString, bookmark.Url, new MatchOption()).Score / 10) > 0) return true; return false; } From a2e439a1550ac2f417e7493d48fdc4fb114a798a Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 14:42:34 +1000 Subject: [PATCH 09/17] Update browserbookmark plugin with new code --- Plugins/Wox.Plugin.BrowserBookmark/Main.cs | 6 +++--- Wox.Infrastructure/StringMatcher.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Plugins/Wox.Plugin.BrowserBookmark/Main.cs b/Plugins/Wox.Plugin.BrowserBookmark/Main.cs index 041ba2ae4..e18eb4953 100644 --- a/Plugins/Wox.Plugin.BrowserBookmark/Main.cs +++ b/Plugins/Wox.Plugin.BrowserBookmark/Main.cs @@ -62,9 +62,9 @@ namespace Wox.Plugin.BrowserBookmark private bool MatchProgram(Bookmark bookmark, string queryString) { - if ((bookmark.Score = StringMatcher.FuzzySearch(queryString, bookmark.Name, new MatchOption()).Score) > 0) return true; - if ((bookmark.Score = StringMatcher.FuzzySearch(queryString, bookmark.PinyinName, new MatchOption).Score) > 0) return true; - if ((bookmark.Score = StringMatcher.FuzzySearch(queryString, bookmark.Url, new MatchOption()).Score / 10) > 0) return true; + if (StringMatcher.FuzzySearch(queryString, bookmark.Name, new MatchOption()).IsSearchPrecisionScoreMet()) return true; + if ( StringMatcher.FuzzySearch(queryString, bookmark.PinyinName, new MatchOption()).IsSearchPrecisionScoreMet()) return true; + if (StringMatcher.FuzzySearch(queryString, bookmark.Url, new MatchOption()).IsSearchPrecisionScoreMet()) return true; return false; } diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index c619bc9a8..7380278e7 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -107,7 +107,7 @@ namespace Wox.Infrastructure return score; } - public static bool IsPreciciseMatch(this MatchResult matchResult) + public static bool IsSearchPrecisionScoreMet(this MatchResult matchResult) { var precisionScore = (SearchPrecisionScore)Enum.Parse(typeof(SearchPrecisionScore), UserSettingSearchPrecision ?? SearchPrecisionScore.Regular.ToString()); From acd42f9cc63ec17d50443489130ed060882a6351 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 14:43:49 +1000 Subject: [PATCH 10/17] Update test with updated method name --- Wox.Test/FuzzyMatcherTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wox.Test/FuzzyMatcherTest.cs b/Wox.Test/FuzzyMatcherTest.cs index f6b309d05..b08a5e48b 100644 --- a/Wox.Test/FuzzyMatcherTest.cs +++ b/Wox.Test/FuzzyMatcherTest.cs @@ -186,7 +186,7 @@ namespace Wox.Test Debug.WriteLine("###############################################"); Debug.WriteLine(""); - var matchPrecisionResult = matchResult.IsPreciciseMatch(); + var matchPrecisionResult = matchResult.IsSearchPrecisionScoreMet(); Assert.IsTrue(matchPrecisionResult == expectedPrecisionResult); } } From cc23495591d106dc59569c292cd3ddab752c97c3 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 15:03:30 +1000 Subject: [PATCH 11/17] Update Program plugin with new code --- Plugins/Wox.Plugin.Program/Programs/UWP.cs | 4 ++-- Plugins/Wox.Plugin.Program/Programs/Win32.cs | 6 +++--- Wox.Infrastructure/StringMatcher.cs | 21 +++++++++++++++----- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Plugins/Wox.Plugin.Program/Programs/UWP.cs b/Plugins/Wox.Plugin.Program/Programs/UWP.cs index bad8fece9..d5f72683f 100644 --- a/Plugins/Wox.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Wox.Plugin.Program/Programs/UWP.cs @@ -240,9 +240,9 @@ namespace Wox.Plugin.Program.Programs private int Score(string query) { - var score1 = StringMatcher.Score(DisplayName, query); + var score1 = StringMatcher.FuzzySearch(query, DisplayName).ScoreAfterSearchPrecisionFilter(); var score2 = StringMatcher.ScoreForPinyin(DisplayName, query); - var score3 = StringMatcher.Score(Description, query); + var score3 = StringMatcher.FuzzySearch(query, Description).ScoreAfterSearchPrecisionFilter(); var score4 = StringMatcher.ScoreForPinyin(Description, query); var score = new[] { score1, score2, score3, score4 }.Max(); return score; diff --git a/Plugins/Wox.Plugin.Program/Programs/Win32.cs b/Plugins/Wox.Plugin.Program/Programs/Win32.cs index 6ac53fa92..7b9b3a52f 100644 --- a/Plugins/Wox.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Wox.Plugin.Program/Programs/Win32.cs @@ -31,11 +31,11 @@ namespace Wox.Plugin.Program.Programs private int Score(string query) { - var score1 = StringMatcher.Score(Name, query); + var score1 = StringMatcher.FuzzySearch(query, Name).ScoreAfterSearchPrecisionFilter(); var score2 = StringMatcher.ScoreForPinyin(Name, query); - var score3 = StringMatcher.Score(Description, query); + var score3 = StringMatcher.FuzzySearch(query, Description).ScoreAfterSearchPrecisionFilter(); var score4 = StringMatcher.ScoreForPinyin(Description, query); - var score5 = StringMatcher.Score(ExecutableName, query); + var score5 = StringMatcher.FuzzySearch(query, ExecutableName).ScoreAfterSearchPrecisionFilter(); var score = new[] { score1, score2, score3, score4, score5 }.Max(); return score; } diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index 7380278e7..e0fc1c39a 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Text; using Wox.Infrastructure.Logger; @@ -29,11 +29,9 @@ namespace Wox.Infrastructure return FuzzySearch(target, source, new MatchOption()).Score > 0; } - public enum SearchPrecisionScore + public static MatchResult FuzzySearch(string query, string stringToCompare) { - Regular = 50, - Low = 20, - None = 0 + return FuzzySearch(query, stringToCompare, new MatchOption()); } /// @@ -107,6 +105,13 @@ namespace Wox.Infrastructure return score; } + public enum SearchPrecisionScore + { + Regular = 50, + Low = 20, + None = 0 + } + public static bool IsSearchPrecisionScoreMet(this MatchResult matchResult) { var precisionScore = (SearchPrecisionScore)Enum.Parse(typeof(SearchPrecisionScore), @@ -114,6 +119,12 @@ namespace Wox.Infrastructure return matchResult.Score >= (int)precisionScore; } + public static int ScoreAfterSearchPrecisionFilter(this MatchResult matchResult) + { + return matchResult.IsSearchPrecisionScoreMet() ? matchResult.Score : 0; + + } + public static int ScoreForPinyin(string source, string target) { if (!string.IsNullOrEmpty(source) && !string.IsNullOrEmpty(target)) From 6625a2afd34f66122563c05de53b33b7f8e777a2 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 15:17:40 +1000 Subject: [PATCH 12/17] Update mainview model with new code --- Wox/ViewModel/MainViewModel.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Wox/ViewModel/MainViewModel.cs b/Wox/ViewModel/MainViewModel.cs index afee65f06..2a7781e1b 100644 --- a/Wox/ViewModel/MainViewModel.cs +++ b/Wox/ViewModel/MainViewModel.cs @@ -305,8 +305,8 @@ namespace Wox.ViewModel { var filtered = results.Where ( - r => StringMatcher.IsMatch(r.Title, query) || - StringMatcher.IsMatch(r.SubTitle, query) + r => StringMatcher.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet() + || StringMatcher.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet() ).ToList(); ContextMenu.AddResults(filtered, id); } @@ -348,8 +348,8 @@ namespace Wox.ViewModel { var filtered = results.Where ( - r => StringMatcher.IsMatch(r.Title, query) || - StringMatcher.IsMatch(r.SubTitle, query) + r => StringMatcher.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet() || + StringMatcher.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet() ).ToList(); History.AddResults(filtered, id); } From 481bd4ac68a5eb403897c0a80b57110a99e989b4 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 15:18:05 +1000 Subject: [PATCH 13/17] Update Sys plugin with new code --- Plugins/Wox.Plugin.Sys/Main.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Wox.Plugin.Sys/Main.cs b/Plugins/Wox.Plugin.Sys/Main.cs index 7cb35c55f..6f43b8601 100644 --- a/Plugins/Wox.Plugin.Sys/Main.cs +++ b/Plugins/Wox.Plugin.Sys/Main.cs @@ -56,8 +56,8 @@ namespace Wox.Plugin.Sys var results = new List(); foreach (var c in commands) { - var titleScore = StringMatcher.Score(c.Title, query.Search); - var subTitleScore = StringMatcher.Score(c.SubTitle, query.Search); + var titleScore = StringMatcher.FuzzySearch(query.Search, c.Title).ScoreAfterSearchPrecisionFilter(); + var subTitleScore = StringMatcher.FuzzySearch(query.Search, c.SubTitle).ScoreAfterSearchPrecisionFilter(); var score = Math.Max(titleScore, subTitleScore); if (score > 0) { From d40a79576b7b16dd6f9285e211d6d620e7efbcbe Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 15:18:34 +1000 Subject: [PATCH 14/17] Update ControlPanel plugin with new code --- Plugins/Wox.Plugin.ControlPanel/Main.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Wox.Plugin.ControlPanel/Main.cs b/Plugins/Wox.Plugin.ControlPanel/Main.cs index 14b870da4..2e846b6ff 100644 --- a/Plugins/Wox.Plugin.ControlPanel/Main.cs +++ b/Plugins/Wox.Plugin.ControlPanel/Main.cs @@ -79,14 +79,14 @@ namespace Wox.Plugin.ControlPanel var scores = new List {0}; if (string.IsNullOrEmpty(item.LocalizedString)) { - var score1 = StringMatcher.Score(item.LocalizedString, query); + var score1 = StringMatcher.FuzzySearch(query, item.LocalizedString).ScoreAfterSearchPrecisionFilter(); var score2 = StringMatcher.ScoreForPinyin(item.LocalizedString, query); scores.Add(score1); scores.Add(score2); } if (!string.IsNullOrEmpty(item.InfoTip)) { - var score1 = StringMatcher.Score(item.InfoTip, query); + var score1 = StringMatcher.FuzzySearch(query, item.InfoTip).ScoreAfterSearchPrecisionFilter(); var score2 = StringMatcher.ScoreForPinyin(item.InfoTip, query); scores.Add(score1); scores.Add(score2); From 9658af4aa940ae3f5dc59180f7a3e3706c0fb691 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 15:18:50 +1000 Subject: [PATCH 15/17] update --- Wox.Infrastructure/StringMatcher.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index e0fc1c39a..0f2657a49 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Text; using Wox.Infrastructure.Logger; @@ -15,7 +15,7 @@ namespace Wox.Infrastructure { if (!string.IsNullOrEmpty(source) && !string.IsNullOrEmpty(target)) { - return FuzzySearch(target, source, new MatchOption()).Score; + return FuzzySearch(target, source, new MatchOption()).Score; } else { From 8717cd077cb98e61e13e86974ebca81ba582f543 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 29 Sep 2019 20:04:30 +1000 Subject: [PATCH 16/17] Add ui for user preference selection --- Wox/SettingWindow.xaml | 6 ++++++ Wox/ViewModel/SettingWindowViewModel.cs | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/Wox/SettingWindow.xaml b/Wox/SettingWindow.xaml index bf25e3e60..577b3ea9e 100644 --- a/Wox/SettingWindow.xaml +++ b/Wox/SettingWindow.xaml @@ -55,6 +55,12 @@ Checked="OnAutoStartupChecked" Unchecked="OnAutoStartupUncheck"> + + + + QuerySearchPrecisionStrings + { + get + { + var precisionStrings = new List(); + + var enumList = Enum.GetValues(typeof(StringMatcher.SearchPrecisionScore)).Cast().ToList(); + + enumList.ForEach(x => precisionStrings.Add(x.ToString())); + + return precisionStrings; + } + } + private Internationalization _translater => InternationalizationManager.Instance; public List Languages => _translater.LoadAvailableLanguages(); public IEnumerable MaxResultsRange => Enumerable.Range(2, 16); From aae7987df0b7a098f3c84adc61ba77d680e9a1a8 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 30 Sep 2019 21:51:15 +1000 Subject: [PATCH 17/17] update --- Wox.Test/FuzzyMatcherTest.cs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Wox.Test/FuzzyMatcherTest.cs b/Wox.Test/FuzzyMatcherTest.cs index b08a5e48b..9aeca0534 100644 --- a/Wox.Test/FuzzyMatcherTest.cs +++ b/Wox.Test/FuzzyMatcherTest.cs @@ -76,16 +76,12 @@ namespace Wox.Test Assert.True(scoreResult == 0); } - - - //[TestCase("c", 50)] - //[TestCase("ch", 50)] + [TestCase("chr")] [TestCase("chrom")] - [TestCase("chrome")] - //[TestCase("chrom", 0)] - //[TestCase("cand", 50)] - //[TestCase("cpywa", 0)] + [TestCase("chrome")] + [TestCase("cand")] + [TestCase("cpywa")] [TestCase("ccs")] public void WhenGivenStringsAndAppliedPrecisionFilteringThenShouldReturnGreaterThanPrecisionScoreResults(string searchTerm) { @@ -162,9 +158,9 @@ namespace Wox.Test Assert.IsTrue(orderedResults[4].Score == 0 && orderedResults[4].Title == searchStrings[4]); } - [TestCase("goo", "Google Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("chr", "Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("goo", "Google Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("chr", "Google Chrome", (int)StringMatcher.SearchPrecisionScore.Low, true)] + [TestCase("chr", "Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("chr", "Help cure hope raise on mind entity Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, false)] [TestCase("chr", "Help cure hope raise on mind entity Chrome", (int)StringMatcher.SearchPrecisionScore.Low, true)] [TestCase("chr", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.Regular, false)] @@ -172,7 +168,7 @@ namespace Wox.Test [TestCase("ccs", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.Low, true)] [TestCase("cand", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("cand", "Help cure hope raise on mind entity Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, false)] - public void WhenGivenDesiredPrecisionIsRegularShouldReturnAllResultsEqualGreaterThanRegular(string queryString, string compareString, + public void WhenGivenDesiredPrecisionThenShouldReturnAllResultsGreaterOrEqual(string queryString, string compareString, int expectedPrecisionScore, bool expectedPrecisionResult) { var expectedPrecisionString = (StringMatcher.SearchPrecisionScore)expectedPrecisionScore;