Skip to content

Commit 55d2bdd

Browse files
authored
Merge branch 'dev' into FixMemoryLeak
2 parents 3c1451e + 77fff6c commit 55d2bdd

File tree

23 files changed

+777
-56
lines changed

23 files changed

+777
-56
lines changed

Flow.Launcher.Infrastructure/Logger/Log.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Diagnostics;
1+
using System.Diagnostics;
22
using System.IO;
33
using System.Runtime.CompilerServices;
44
using NLog;

Flow.Launcher.Infrastructure/StringMatcher.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,11 @@ public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption
202202
if (allQuerySubstringsMatched)
203203
{
204204
var nearestSpaceIndex = CalculateClosestSpaceIndex(spaceIndices, firstMatchIndex);
205-
var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1,
205+
206+
// firstMatchIndex - nearestSpaceIndex - 1 is to set the firstIndex as the index of the first matched char
207+
// preceded by a space e.g. 'world' matching 'hello world' firstIndex would be 0 not 6
208+
// giving more weight than 'we or donald' by allowing the distance calculation to treat the starting position at after the space.
209+
var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, spaceIndices,
206210
lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString);
207211

208212
var resultList = indexList.Select(x => translationMapping?.MapToOriginalIndex(x) ?? x).Distinct().ToList();
@@ -296,14 +300,22 @@ private static bool AllQuerySubstringsMatched(int currentQuerySubstringIndex, in
296300
return currentQuerySubstringIndex >= querySubstringsLength;
297301
}
298302

299-
private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen,
303+
private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, List<int> spaceIndices, int matchLen,
300304
bool allSubstringsContainedInCompareString)
301305
{
302306
// A match found near the beginning of a string is scored more than a match found near the end
303307
// A match is scored more if the characters in the patterns are closer to each other,
304308
// while the score is lower if they are more spread out
305309
var score = 100 * (query.Length + 1) / ((1 + firstIndex) + (matchLen + 1));
306310

311+
// Give more weight to a match that is closer to the start of the string.
312+
// if the first matched char is immediately before space and all strings are contained in the compare string e.g. 'world' matching 'hello world'
313+
// and 'world hello', because both have 'world' immediately preceded by space, their firstIndex will be 0 when distance is calculated,
314+
// to prevent them scoring the same, we adjust the score by deducting the number of spaces it has from the start of the string, so 'world hello'
315+
// will score slightly higher than 'hello world' because 'hello world' has one additional space.
316+
if (firstIndex == 0 && allSubstringsContainedInCompareString)
317+
score -= spaceIndices.Count;
318+
307319
// A match with less characters assigning more weights
308320
if (stringToCompare.Length - query.Length < 5)
309321
{
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using System;
2+
using System.Text.Json.Serialization;
3+
4+
namespace Flow.Launcher.Infrastructure.UserSettings
5+
{
6+
public abstract class ShortcutBaseModel
7+
{
8+
public string Key { get; set; }
9+
10+
[JsonIgnore]
11+
public Func<string> Expand { get; set; } = () => { return ""; };
12+
13+
public override bool Equals(object obj)
14+
{
15+
return obj is ShortcutBaseModel other &&
16+
Key == other.Key;
17+
}
18+
19+
public override int GetHashCode()
20+
{
21+
return Key.GetHashCode();
22+
}
23+
}
24+
25+
public class CustomShortcutModel : ShortcutBaseModel
26+
{
27+
public string Value { get; set; }
28+
29+
[JsonConstructorAttribute]
30+
public CustomShortcutModel(string key, string value)
31+
{
32+
Key = key;
33+
Value = value;
34+
Expand = () => { return Value; };
35+
}
36+
37+
public void Deconstruct(out string key, out string value)
38+
{
39+
key = Key;
40+
value = Value;
41+
}
42+
43+
public static implicit operator (string Key, string Value)(CustomShortcutModel shortcut)
44+
{
45+
return (shortcut.Key, shortcut.Value);
46+
}
47+
48+
public static implicit operator CustomShortcutModel((string Key, string Value) shortcut)
49+
{
50+
return new CustomShortcutModel(shortcut.Key, shortcut.Value);
51+
}
52+
}
53+
54+
public class BuiltinShortcutModel : ShortcutBaseModel
55+
{
56+
public string Description { get; set; }
57+
58+
public BuiltinShortcutModel(string key, string description, Func<string> expand)
59+
{
60+
Key = key;
61+
Description = description;
62+
Expand = expand ?? (() => { return ""; });
63+
}
64+
}
65+
}

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.ObjectModel;
44
using System.Drawing;
55
using System.Text.Json.Serialization;
6+
using System.Windows;
67
using Flow.Launcher.Plugin;
78
using Flow.Launcher.Plugin.SharedModels;
89
using Flow.Launcher;
@@ -129,8 +130,7 @@ public CustomBrowserViewModel CustomBrowser
129130
PrivateArg = "-private",
130131
EnablePrivate = false,
131132
Editable = false
132-
}
133-
,
133+
},
134134
new()
135135
{
136136
Name = "MS Edge",
@@ -186,6 +186,13 @@ public string QuerySearchPrecisionString
186186

187187
public ObservableCollection<CustomPluginHotkey> CustomPluginHotkeys { get; set; } = new ObservableCollection<CustomPluginHotkey>();
188188

189+
public ObservableCollection<CustomShortcutModel> CustomShortcuts { get; set; } = new ObservableCollection<CustomShortcutModel>();
190+
191+
[JsonIgnore]
192+
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new ObservableCollection<BuiltinShortcutModel>() {
193+
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText)
194+
};
195+
189196
public bool DontPromptUpdateMsg { get; set; }
190197
public bool EnableUpdateLog { get; set; }
191198

Flow.Launcher.Plugin/Result.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ public class Result
3737
/// user's clipboard when Ctrl + C is pressed on a result. If the text is a file/directory path
3838
/// flow will copy the actual file/folder instead of just the path text.
3939
/// </summary>
40-
public string CopyText { get; set; } = string.Empty;
40+
public string CopyText
41+
{
42+
get => string.IsNullOrEmpty(_copyText) ? SubTitle : _copyText;
43+
set => _copyText = value;
44+
}
4145

4246
/// <summary>
4347
/// This holds the text which can be provided by plugin to help Flow autocomplete text
@@ -81,6 +85,7 @@ public string IcoPath
8185
/// Delegate to Get Image Source
8286
/// </summary>
8387
public IconDelegate Icon;
88+
private string _copyText = string.Empty;
8489

8590
/// <summary>
8691
/// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons)

Flow.Launcher.Test/FuzzyMatcherTest.cs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,20 @@ public void GivenQueryString_WhenAppliedPrecisionFiltering_ThenShouldReturnGreat
129129
}
130130
}
131131

132+
133+
/// <summary>
134+
/// These are standard match scenarios
135+
/// The intention of this test is provide a bench mark for how much the score has increased from a change.
136+
/// Usually the increase in scoring should not be drastic, increase of less than 10 is acceptable.
137+
/// </summary>
132138
[TestCase(Chrome, Chrome, 157)]
133-
[TestCase(Chrome, LastIsChrome, 147)]
139+
[TestCase(Chrome, LastIsChrome, 145)]
134140
[TestCase("chro", HelpCureHopeRaiseOnMindEntityChrome, 50)]
135141
[TestCase("chr", HelpCureHopeRaiseOnMindEntityChrome, 30)]
136142
[TestCase(Chrome, UninstallOrChangeProgramsOnYourComputer, 21)]
137143
[TestCase(Chrome, CandyCrushSagaFromKing, 0)]
138-
[TestCase("sql", MicrosoftSqlServerManagementStudio, 110)]
139-
[TestCase("sql manag", MicrosoftSqlServerManagementStudio, 121)] //double spacing intended
144+
[TestCase("sql", MicrosoftSqlServerManagementStudio, 109)]
145+
[TestCase("sql manag", MicrosoftSqlServerManagementStudio, 120)] //double spacing intended
140146
public void WhenGivenQueryString_ThenShouldReturn_TheDesiredScoring(
141147
string queryString, string compareString, int expectedScore)
142148
{
@@ -275,7 +281,40 @@ public void WhenGivenAQuery_Scoring_ShouldGiveMoreWeightToStartOfNewWord(
275281
$"Query: \"{queryString}\"{Environment.NewLine} " +
276282
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}" +
277283
$"Should be greater than{Environment.NewLine}" +
278-
$"CompareString2: \"{compareString2}\", Score: {compareString1Result.Score}{Environment.NewLine}");
284+
$"CompareString2: \"{compareString2}\", Score: {compareString2Result.Score}{Environment.NewLine}");
285+
}
286+
287+
[TestCase("red", "red colour", "metro red")]
288+
[TestCase("red", "this red colour", "this colour red")]
289+
[TestCase("red", "this red colour", "this colour is very red")]
290+
[TestCase("red", "this red colour", "this colour is surprisingly super awesome red and cool")]
291+
[TestCase("red", "this colour is surprisingly super red very and cool", "this colour is surprisingly super very red and cool")]
292+
public void WhenGivenTwoStrings_Scoring_ShouldGiveMoreWeightToTheStringCloserToIndexZero(
293+
string queryString, string compareString1, string compareString2)
294+
{
295+
// When
296+
var matcher = new StringMatcher { UserSettingSearchPrecision = SearchPrecisionScore.Regular };
297+
298+
// Given
299+
var compareString1Result = matcher.FuzzyMatch(queryString, compareString1);
300+
var compareString2Result = matcher.FuzzyMatch(queryString, compareString2);
301+
302+
Debug.WriteLine("");
303+
Debug.WriteLine("###############################################");
304+
Debug.WriteLine($"QueryString: \"{queryString}\"{Environment.NewLine}");
305+
Debug.WriteLine(
306+
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}");
307+
Debug.WriteLine(
308+
$"CompareString2: \"{compareString2}\", Score: {compareString2Result.Score}{Environment.NewLine}");
309+
Debug.WriteLine("###############################################");
310+
Debug.WriteLine("");
311+
312+
// Should
313+
Assert.True(compareString1Result.Score > compareString2Result.Score,
314+
$"Query: \"{queryString}\"{Environment.NewLine} " +
315+
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}" +
316+
$"Should be greater than{Environment.NewLine}" +
317+
$"CompareString2: \"{compareString2}\", Score: {compareString2Result.Score}{Environment.NewLine}");
279318
}
280319

281320
[TestCase("vim", "Vim", "ignoreDescription", "ignore.exe", "Vim Diff", "ignoreDescription", "ignore.exe")]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Globalization;
3+
using System.Windows.Data;
4+
using Flow.Launcher.Core.Resource;
5+
6+
namespace Flow.Launcher.Converters
7+
{
8+
public class TranlationConverter : IValueConverter
9+
{
10+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
11+
{
12+
var key = value.ToString();
13+
if (String.IsNullOrEmpty(key))
14+
return key;
15+
return InternationalizationManager.Instance.GetTranslation(key);
16+
}
17+
18+
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException();
19+
}
20+
}

0 commit comments

Comments
 (0)