diff --git a/Plugins/Wox.Plugin.BrowserBookmark/Main.cs b/Plugins/Wox.Plugin.BrowserBookmark/Main.cs index 23f1135a6..e18eb4953 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 (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/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); 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/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) { 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; } } } diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index 0ef4f1426..0f2657a49 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,108 @@ 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 static MatchResult FuzzySearch(string query, string stringToCompare) + { + return FuzzySearch(query, stringToCompare, new MatchOption()); + } + + /// + /// 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 enum SearchPrecisionScore + { + Regular = 50, + Low = 20, + None = 0 + } + + public static bool IsSearchPrecisionScoreMet(this MatchResult matchResult) + { + var precisionScore = (SearchPrecisionScore)Enum.Parse(typeof(SearchPrecisionScore), + UserSettingSearchPrecision ?? SearchPrecisionScore.Regular.ToString()); + 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)) @@ -34,12 +137,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 +156,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; } } } 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.Test/FuzzyMatcherTest.cs b/Wox.Test/FuzzyMatcherTest.cs index 2856a0fde..9aeca0534 100644 --- a/Wox.Test/FuzzyMatcherTest.cs +++ b/Wox.Test/FuzzyMatcherTest.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using NUnit.Framework; using Wox.Infrastructure; @@ -9,6 +11,31 @@ 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() + { + var listToReturn = new List(); + + Enum.GetValues(typeof(StringMatcher.SearchPrecisionScore)) + .Cast() + .ToList() + .ForEach(x => listToReturn.Add((int)x)); + + return listToReturn; + } + [Test] public void MatchTest() { @@ -28,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 }); } @@ -39,5 +66,124 @@ 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 = StringMatcher.FuzzySearch(searchString, compareString, new MatchOption()).Score; + + Assert.True(scoreResult == 0); + } + + [TestCase("chr")] + [TestCase("chrom")] + [TestCase("chrome")] + [TestCase("cand")] + [TestCase("cpywa")] + [TestCase("ccs")] + public void WhenGivenStringsAndAppliedPrecisionFilteringThenShouldReturnGreaterThanPrecisionScoreResults(string searchTerm) + { + var results = new List(); + + foreach (var str in GetSearchStrings()) + { + results.Add(new Result + { + Title = str, + Score = StringMatcher.FuzzySearch(searchTerm, str, new MatchOption()).Score + }); + } + + 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 WhenGivenStringsForCalScoreMethodThenShouldReturnCurrentScoring(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]); + } + + [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)] + [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 WhenGivenDesiredPrecisionThenShouldReturnAllResultsGreaterOrEqual(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()); + + 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.IsSearchPrecisionScoreMet(); + Assert.IsTrue(matchPrecisionResult == expectedPrecisionResult); + } } } 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 + 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); 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"> + + + + 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); } diff --git a/Wox/ViewModel/SettingWindowViewModel.cs b/Wox/ViewModel/SettingWindowViewModel.cs index 7c4f5ad80..67b8d7af0 100644 --- a/Wox/ViewModel/SettingWindowViewModel.cs +++ b/Wox/ViewModel/SettingWindowViewModel.cs @@ -70,6 +70,20 @@ namespace Wox.ViewModel } } + public List 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);