[PTRun]Settings for result order tuning (#18978)

* Change to allow new settings for results tuning.

* Change to allow new settings for results tuning.

* Added WeightBoost

* Fixed null-ref crash in QueryResults

* Change based on stefansjfw review. Remove PowerLauncher_PluginWeightBoost.Content

* Fixed another of my dumb null-refs...

* Updated some text

* Moved global sort order and set enable/disabled as needed.

* Fixed enabled-state of "Global sort order score modifier" setting.
This commit is contained in:
Jeff Lord
2022-07-04 10:12:56 -04:00
committed by GitHub
parent 0c238a8eea
commit 0da616f917
19 changed files with 379 additions and 31 deletions

View File

@@ -212,7 +212,7 @@ namespace PowerLauncher
private void OnThemeChanged(Theme oldTheme, Theme newTheme)
{
ImageLoader.UpdateIconPath(newTheme);
_mainVM.Query();
_mainVM.Query(new MainViewModel.QueryTuningOptions());
}
/// <summary>

View File

@@ -159,7 +159,6 @@ namespace PowerLauncher
SearchBox.QueryTextBox.DataContext = _viewModel;
SearchBox.QueryTextBox.PreviewKeyDown += Launcher_KeyDown;
SetupSearchTextBoxReactiveness(_viewModel.GetSearchQueryResultsWithDelaySetting(), _viewModel.GetSearchInputDelaySetting());
_viewModel.RegisterSettingsChangeListener(
(s, prop_e) =>
@@ -489,8 +488,15 @@ namespace PowerLauncher
}
else
{
var options = new MainViewModel.QueryTuningOptions
{
SearchClickedItemWeight = _viewModel.GetSearchClickedItemWeight(),
SearchQueryTuningEnabled = _viewModel.GetSearchQueryTuningEnabled(),
SearchWaitForSlowResults = _viewModel.GetSearchWaitForSlowResults(),
};
_viewModel.QueryText = text;
_viewModel.Query();
_viewModel.Query(options);
}
}

View File

@@ -205,6 +205,14 @@ namespace PowerLauncher.Plugin
metadata.QueryCount += 1;
metadata.AvgQueryTime = metadata.QueryCount == 1 ? milliseconds : (metadata.AvgQueryTime + milliseconds) / 2;
if (results != null)
{
foreach (var result in results)
{
result.Metadata = pair.Metadata;
}
}
return results;
}
catch (Exception e)

View File

@@ -115,6 +115,21 @@ namespace PowerLauncher
_settings.SearchInputDelay = overloadSettings.Properties.SearchInputDelay;
}
if (_settings.SearchClickedItemWeight != overloadSettings.Properties.SearchClickedItemWeight)
{
_settings.SearchClickedItemWeight = overloadSettings.Properties.SearchClickedItemWeight;
}
if (_settings.SearchQueryTuningEnabled != overloadSettings.Properties.SearchQueryTuningEnabled)
{
_settings.SearchQueryTuningEnabled = overloadSettings.Properties.SearchQueryTuningEnabled;
}
if (_settings.SearchWaitForSlowResults != overloadSettings.Properties.SearchWaitForSlowResults)
{
_settings.SearchWaitForSlowResults = overloadSettings.Properties.SearchWaitForSlowResults;
}
if (_settings.MaxResultsToShow != overloadSettings.Properties.MaximumNumberOfResults)
{
_settings.MaxResultsToShow = overloadSettings.Properties.MaximumNumberOfResults;

View File

@@ -11,8 +11,15 @@ namespace PowerLauncher.Storage
{
public class UserSelectedRecord
{
public class UserSelectedRecordItem
{
public int SelectedCount { get; set; }
public DateTime LastSelected { get; set; }
}
[JsonInclude]
public Dictionary<string, int> Records { get; private set; } = new Dictionary<string, int>();
public Dictionary<string, UserSelectedRecordItem> Records { get; private set; } = new Dictionary<string, UserSelectedRecordItem>();
public void Add(Result result)
{
@@ -22,29 +29,30 @@ namespace PowerLauncher.Storage
}
var key = result.ToString();
if (Records.TryGetValue(key, out int value))
if (Records.TryGetValue(key, out var value))
{
Records[key] = value + 1;
Records[key].SelectedCount = Records[key].SelectedCount + 1;
Records[key].LastSelected = DateTime.UtcNow;
}
else
{
Records.Add(key, 1);
Records.Add(key, new UserSelectedRecordItem { SelectedCount = 1, LastSelected = DateTime.UtcNow });
}
}
public int GetSelectedCount(Result result)
public UserSelectedRecordItem GetSelectedData(Result result)
{
if (result == null)
{
throw new ArgumentNullException(nameof(result));
}
if (result != null && Records.TryGetValue(result.ToString(), out int value))
if (result != null && Records.TryGetValue(result.ToString(), out var value))
{
return value;
}
return 0;
return new UserSelectedRecordItem { SelectedCount = 0, LastSelected = DateTime.MinValue };
}
}
}

View File

@@ -362,14 +362,14 @@ namespace PowerLauncher.ViewModel
/// </summary>
/// <param name="queryText">Text that is being queried from user</param>
/// <param name="requery">Optional Parameter that if true, will automatically execute a query against the updated text</param>
public void ChangeQueryText(string queryText, bool requery = false)
public void ChangeQueryText(string queryText, bool requery = false, QueryTuningOptions tuningOptions = null)
{
SystemQueryText = queryText;
if (requery)
{
QueryText = queryText;
Query();
Query(tuningOptions);
}
}
@@ -463,11 +463,20 @@ namespace PowerLauncher.ViewModel
public ICommand ClearQueryCommand { get; private set; }
public void Query()
public class QueryTuningOptions
{
public int SearchClickedItemWeight { get; set; }
public bool SearchQueryTuningEnabled { get; set; }
public bool SearchWaitForSlowResults { get; set; }
}
public void Query(QueryTuningOptions options)
{
if (SelectedIsFromQueryResults())
{
QueryResults();
QueryResults(options);
}
else if (HistorySelected())
{
@@ -518,8 +527,10 @@ namespace PowerLauncher.ViewModel
}
}
private void QueryResults()
private void QueryResults(QueryTuningOptions queryTuning)
{
var doFinalSort = queryTuning.SearchQueryTuningEnabled && queryTuning.SearchWaitForSlowResults;
if (!string.IsNullOrEmpty(QueryText))
{
var queryTimer = new System.Diagnostics.Stopwatch();
@@ -536,7 +547,8 @@ namespace PowerLauncher.ViewModel
{
queryText = pluginQueryPairs.Values.First().RawQuery;
_currentQuery = queryText;
Task.Run(
var queryResultsTask = Task.Factory.StartNew(
() =>
{
Thread.Sleep(20);
@@ -577,12 +589,18 @@ namespace PowerLauncher.ViewModel
currentCancellationToken.ThrowIfCancellationRequested();
numResults = Results.Results.Count;
Results.Sort();
Results.SelectedItem = Results.Results.FirstOrDefault();
if (!doFinalSort)
{
Results.Sort(queryTuning);
Results.SelectedItem = Results.Results.FirstOrDefault();
}
}
currentCancellationToken.ThrowIfCancellationRequested();
UpdateResultsListViewAfterQuery(queryText);
if (!doFinalSort)
{
UpdateResultsListViewAfterQuery(queryText);
}
}
bool noInitialResults = numResults == 0;
@@ -616,11 +634,17 @@ namespace PowerLauncher.ViewModel
currentCancellationToken.ThrowIfCancellationRequested();
numResults = Results.Results.Count;
Results.Sort();
if (!doFinalSort)
{
Results.Sort(queryTuning);
}
}
currentCancellationToken.ThrowIfCancellationRequested();
UpdateResultsListViewAfterQuery(queryText, noInitialResults, true);
if (!doFinalSort)
{
UpdateResultsListViewAfterQuery(queryText, noInitialResults, true);
}
}
}
}
@@ -644,6 +668,19 @@ namespace PowerLauncher.ViewModel
};
PowerToysTelemetry.Log.WriteEvent(queryEvent);
}, currentCancellationToken);
if (doFinalSort)
{
Task.Factory.ContinueWhenAll(
new Task[] { queryResultsTask },
completedTasks =>
{
Results.Sort(queryTuning);
Results.SelectedItem = Results.Results.FirstOrDefault();
UpdateResultsListViewAfterQuery(queryText, false, false);
},
currentCancellationToken);
}
}
}
else
@@ -944,7 +981,9 @@ namespace PowerLauncher.ViewModel
foreach (var result in list)
{
result.Score += _userSelectedRecord.GetSelectedCount(result) * 5;
var selectedData = _userSelectedRecord.GetSelectedData(result);
result.SelectedCount = selectedData.SelectedCount;
result.LastSelected = selectedData.LastSelected;
}
// Using CurrentCultureIgnoreCase since this is user facing
@@ -1117,5 +1156,20 @@ namespace PowerLauncher.ViewModel
{
return _settings.SearchInputDelay;
}
public int GetSearchClickedItemWeight()
{
return _settings.SearchClickedItemWeight;
}
public bool GetSearchQueryTuningEnabled()
{
return _settings.SearchQueryTuningEnabled;
}
public bool GetSearchWaitForSlowResults()
{
return _settings.SearchWaitForSlowResults;
}
}
}

View File

@@ -253,9 +253,19 @@ namespace PowerLauncher.ViewModel
Results.AddRange(newResults);
}
public void Sort()
public void Sort(MainViewModel.QueryTuningOptions options)
{
var sorted = Results.OrderByDescending(x => x.Result.Score).ToList();
List<ResultViewModel> sorted = null;
if (options.SearchQueryTuningEnabled)
{
sorted = Results.OrderByDescending(x => (x.Result.Metadata.WeightBoost + x.Result.Score + (x.Result.SelectedCount * options.SearchClickedItemWeight))).ToList();
}
else
{
sorted = Results.OrderByDescending(x => (x.Result.Metadata.WeightBoost + x.Result.Score + (x.Result.SelectedCount * 5))).ToList();
}
Clear();
Results.AddRange(sorted);
}

View File

@@ -82,6 +82,12 @@ namespace Wox.Infrastructure.UserSettings
private int _searchInputDelay = 150;
private int _searchClickedItemWeight = 5;
private bool _searchQueryTuningEnabled;
private bool _searchWaitForSlowResults;
public int SearchInputDelay
{
get
@@ -99,6 +105,57 @@ namespace Wox.Infrastructure.UserSettings
}
}
public bool SearchQueryTuningEnabled
{
get
{
return _searchQueryTuningEnabled;
}
set
{
if (_searchQueryTuningEnabled != value)
{
_searchQueryTuningEnabled = value;
OnPropertyChanged(nameof(SearchQueryTuningEnabled));
}
}
}
public bool SearchWaitForSlowResults
{
get
{
return _searchWaitForSlowResults;
}
set
{
if (_searchWaitForSlowResults != value)
{
_searchWaitForSlowResults = value;
OnPropertyChanged(nameof(_searchWaitForSlowResults));
}
}
}
public int SearchClickedItemWeight
{
get
{
return _searchClickedItemWeight;
}
set
{
if (_searchClickedItemWeight != value)
{
_searchClickedItemWeight = value;
OnPropertyChanged(nameof(SearchClickedItemWeight));
}
}
}
public string Language { get; set; } = "en";
public Theme Theme { get; set; } = Theme.System;

View File

@@ -56,6 +56,8 @@ namespace Wox.Plugin
public string ActionKeyword { get; set; }
public int WeightBoost { get; set; }
public bool IsGlobal { get; set; }
public string IcoPathDark { get; set; }

View File

@@ -79,6 +79,8 @@ namespace Wox.Plugin
}
Metadata.ActionKeyword = setting.ActionKeyword;
Metadata.WeightBoost = setting.WeightBoost;
Metadata.IsGlobal = setting.IsGlobal;
(Plugin as ISettingProvider)?.UpdateSettings(setting);

View File

@@ -103,6 +103,8 @@ namespace Wox.Plugin
/// </summary>
public const string GlobalPluginWildcardSign = "*";
public int WeightBoost { get; set; }
public string ActionKeyword { get; set; }
/// <summary>

View File

@@ -21,6 +21,8 @@ namespace Wox.Plugin
private string _pluginDirectory;
private string _icoPath;
public PluginMetadata Metadata { get; set; }
public string Title
{
get
@@ -100,6 +102,10 @@ namespace Wox.Plugin
public int Score { get; set; }
public int SelectedCount { get; set; }
public DateTime LastSelected { get; set; } = DateTime.MinValue;
public Result(IList<int> titleHighlightData = null, IList<int> subTitleHighlightData = null)
{
TitleHighlightData = titleHighlightData;

View File

@@ -22,6 +22,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string ActionKeyword { get; set; }
public int WeightBoost { get; set; }
public string IconPathDark { get; set; }
public string IconPathLight { get; set; }

View File

@@ -57,6 +57,15 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonPropertyName("search_input_delay")]
public int SearchInputDelay { get; set; }
[JsonPropertyName("search_clicked_item_weight")]
public int SearchClickedItemWeight { get; set; }
[JsonPropertyName("search_query_tuning_enabled")]
public bool SearchQueryTuningEnabled { get; set; }
[JsonPropertyName("search_wait_for_slow_results")]
public bool SearchWaitForSlowResults { get; set; }
public PowerLauncherProperties()
{
OpenPowerLauncher = new HotkeySettings(false, false, true, false, 32);
@@ -73,6 +82,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library
UseCentralizedKeyboardHook = false;
SearchQueryResultsWithDelay = true;
SearchInputDelay = 150;
SearchClickedItemWeight = 5;
SearchQueryTuningEnabled = false;
SearchWaitForSlowResults = false;
}
}
}

View File

@@ -85,6 +85,25 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
}
}
public int WeightBoost
{
get
{
return settings.WeightBoost;
}
set
{
if (settings.WeightBoost != value)
{
settings.WeightBoost = value;
NotifyPropertyChanged();
NotifyPropertyChanged(nameof(ShowNotAccessibleWarning));
NotifyPropertyChanged(nameof(ShowNotAllowedKeywordWarning));
}
}
}
public string ActionKeyword
{
get

View File

@@ -330,6 +330,57 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
}
}
public bool SearchQueryTuningEnabled
{
get
{
return settings.Properties.SearchQueryTuningEnabled;
}
set
{
if (settings.Properties.SearchQueryTuningEnabled != value)
{
settings.Properties.SearchQueryTuningEnabled = value;
UpdateSettings();
}
}
}
public bool SearchWaitForSlowResults
{
get
{
return settings.Properties.SearchWaitForSlowResults;
}
set
{
if (settings.Properties.SearchWaitForSlowResults != value)
{
settings.Properties.SearchWaitForSlowResults = value;
UpdateSettings();
}
}
}
public int SearchClickedItemWeight
{
get
{
return settings.Properties.SearchClickedItemWeight;
}
set
{
if (settings.Properties.SearchClickedItemWeight != value)
{
settings.Properties.SearchClickedItemWeight = value;
UpdateSettings();
}
}
}
public HotkeySettings OpenFileLocation
{
get

View File

@@ -2125,6 +2125,30 @@ From there, simply click on one of the supported files in the File Explorer and
<data name="FancyZones_DisableRoundCornersOnWindowSnap.Content" xml:space="preserve">
<value>Disable round corners when window is snapped</value>
</data>
<data name="PowerLauncher_SearchQueryTuningEnabled.Description" xml:space="preserve">
<value>Fine tune results ordering</value>
</data>
<data name="PowerLauncher_SearchQueryTuningEnabled.Header" xml:space="preserve">
<value>Results order tuning</value>
</data>
<data name="PowerLauncher_SearchClickedItemWeight.Description" xml:space="preserve">
<value>Use a higher number to get selected results to rise faster. The default is 5, 0 to disable.</value>
</data>
<data name="PowerLauncher_SearchClickedItemWeight.Header" xml:space="preserve">
<value>Selected item weight</value>
</data>
<data name="PowerLauncher_WaitForSlowResults.Description" xml:space="preserve">
<value>Selecting this can help preselect the top, more relevent result, but at the risk of jumpiness</value>
</data>
<data name="PowerLauncher_WaitForSlowResults.Header" xml:space="preserve">
<value>Wait on slower plugin results before selecting top item in results</value>
</data>
<data name="PowerLauncher_PluginWeightBoost.Description" xml:space="preserve">
<value>Use a higher number to have this plugin's result show higher in the global results. Default is 0.</value>
</data>
<data name="PowerLauncher_PluginWeightBoost.Header" xml:space="preserve">
<value>Global sort order score modifier</value>
</data>
<data name="AlwaysOnTop_RoundCorners.Content" xml:space="preserve">
<value>Enable round corners</value>
</data>

View File

@@ -7,6 +7,7 @@
<!-- Thickness -->
<Thickness x:Key="ExpanderContentPadding">0</Thickness>
<Thickness x:Key="ExpanderSettingMargin">56, 8, 40, 8</Thickness>
<Thickness x:Key="ExpanderSettingMarginTight">86, 0, 40, 8</Thickness>
<SolidColorBrush x:Key="ExpanderChevronPointerOverBackground">Transparent</SolidColorBrush>
@@ -33,6 +34,16 @@
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
<Style x:Key="ExpanderContentSettingStyleTight" TargetType="controls:Setting">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0,0,0,0" />
<Setter Property="BorderBrush" Value="{ThemeResource CardBorderBrush}" />
<Setter Property="CornerRadius" Value="0" />
<Setter Property="Padding" Value="{StaticResource ExpanderSettingMarginTight}" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
<!-- Setting expander style -->
<Style x:Key="SettingExpanderStyle" TargetType="muxc:Expander">
<Setter Property="Background" Value="{ThemeResource CardBackgroundBrush}" />

View File

@@ -132,6 +132,49 @@
<CheckBox x:Uid="PowerLauncher_ClearInputOnLaunch" IsChecked="{x:Bind Mode=TwoWay, Path=ViewModel.ClearInputOnLaunch}" Margin="{StaticResource ExpanderSettingMargin}" />
</controls:SettingExpander.Content>
</controls:SettingExpander>
<controls:SettingExpander IsExpanded="True">
<controls:SettingExpander.Header>
<controls:Setting x:Uid="PowerLauncher_SearchQueryTuningEnabled" Icon="&#xE14C;" Style="{StaticResource ExpanderHeaderSettingStyle}" >
<controls:Setting.ActionContent>
<ToggleSwitch IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.SearchQueryTuningEnabled}"/>
</controls:Setting.ActionContent>
</controls:Setting>
</controls:SettingExpander.Header>
<controls:SettingExpander.Content>
<StackPanel>
<controls:Setting x:Uid="PowerLauncher_SearchClickedItemWeight" Style="{StaticResource ExpanderContentSettingStyle}" IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.SearchQueryTuningEnabled}">
<controls:Setting.ActionContent>
<muxc:NumberBox Minimum="0"
Maximum="1000"
Value="{x:Bind Mode=TwoWay, Path=ViewModel.SearchClickedItemWeight}"
MinWidth="{StaticResource SettingActionControlMinWidth}"
SpinButtonPlacementMode="Compact"
HorizontalAlignment="Left"
SmallChange="5"
LargeChange="50"/>
</controls:Setting.ActionContent>
</controls:Setting>
<!--<controls:Setting x:Uid="PowerLauncher_WaitForSlowResults" Style="{StaticResource ExpanderContentSettingStyle}">
<controls:Setting.ActionContent>
<CheckBox
IsChecked="{x:Bind Mode=TwoWay, Path=ViewModel.SearchWaitForSlowResults}"
Margin="{StaticResource ExpanderSettingMargin}" />
</controls:Setting.ActionContent>
</controls:Setting>-->
<Rectangle Style="{StaticResource ExpanderSeparatorStyle}" />
<controls:CheckBoxWithDescriptionControl
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.SearchQueryTuningEnabled}"
IsChecked="{x:Bind Mode=TwoWay, Path=ViewModel.SearchWaitForSlowResults}"
Margin="56, -2, 40, 14"
x:Uid="PowerLauncher_WaitForSlowResults"/>
</StackPanel>
</controls:SettingExpander.Content>
</controls:SettingExpander>
</controls:SettingsGroup>
<!--<ComboBox x:Uid="PowerLauncher_SearchResultPreference"
@@ -246,6 +289,7 @@
MinWidth="{StaticResource SettingActionControlMinWidth}" />
</controls:Setting.ActionContent>
</controls:Setting>
<muxc:InfoBar Severity="Error" x:Uid="Run_NotAccessibleWarning"
IsTabStop="{x:Bind ShowNotAccessibleWarning}"
IsOpen="{x:Bind ShowNotAccessibleWarning}"
@@ -256,19 +300,34 @@
IsOpen="{x:Bind ShowNotAllowedKeywordWarning}"
IsClosable="False" />
<Rectangle Style="{StaticResource ExpanderSeparatorStyle}" />
<CheckBox AutomationProperties.Name="{Binding ElementName=IncludeInGlobalResultTitle, Path=Text}"
<StackPanel Orientation="Vertical">
<CheckBox AutomationProperties.Name="{Binding ElementName=IncludeInGlobalResultTitle, Path=Text}"
IsChecked="{x:Bind Path=IsGlobal, Mode=TwoWay}"
IsEnabled="{x:Bind Enabled, Mode=OneWay}"
Margin="56, 0, 40, 16">
<StackPanel Orientation="Vertical">
<TextBlock x:Name="IncludeInGlobalResultTitle"
<StackPanel Orientation="Vertical">
<TextBlock x:Name="IncludeInGlobalResultTitle"
Margin="0,10,0,0"
x:Uid="PowerLauncher_IncludeInGlobalResultTitle" />
<controls:IsEnabledTextBlock x:Uid="PowerLauncher_IncludeInGlobalResultDescription"
<controls:IsEnabledTextBlock x:Uid="PowerLauncher_IncludeInGlobalResultDescription"
FontSize="{StaticResource SecondaryTextFontSize}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
</StackPanel>
</CheckBox>
</StackPanel>
</CheckBox>
<controls:Setting x:Uid="PowerLauncher_PluginWeightBoost"
Style="{StaticResource ExpanderContentSettingStyleTight}"
IsEnabled="{x:Bind Enabled, Mode=OneWay}">
<controls:Setting.ActionContent>
<TextBox Text="{x:Bind Path=WeightBoost, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
MinWidth="{StaticResource SettingActionControlMinWidth}" />
</controls:Setting.ActionContent>
</controls:Setting>
</StackPanel>
<ListView ItemsSource="{x:Bind Path=AdditionalOptions}"
SelectionMode="None"