// Copyright (c) Microsoft Corporation // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedModels; using Microsoft.PowerToys.Run.Plugin.WindowsSettings.Properties; namespace Microsoft.PowerToys.Run.Plugin.WindowsSettings.Helper { /// /// Helper class to easier work with results /// internal static class ResultHelper { private static IPublicAPI? _api; public static void Init(IPublicAPI api) => _api = api; /// /// Return a list with s, based on the given list. /// /// The original result list to convert. /// The path to the icon of each entry. /// A list with . internal static List GetResultList( in IEnumerable list, Query query, string iconPath) { var resultList = new List(); foreach (var entry in list) { var result = Predicate(); if (result is null) continue; AddOptionalToolTip(entry, result); resultList.Add(result); Result NewSettingResult(int score) => new Result() { Action = _ => DoOpenSettingsAction(entry), IcoPath = iconPath, SubTitle = $"{Resources.Area} \"{entry.Area}\" {Resources.SubtitlePreposition} {entry.Type}", Title = entry.Name, ContextData = entry, Score = score }; Result? Predicate() { Debug.Assert(_api != null, nameof(_api) + " != null"); var nameMatch = _api.FuzzySearch(query.Search, entry.Name); if (nameMatch.IsSearchPrecisionScoreMet()) { var settingResult = NewSettingResult(nameMatch.Score); settingResult.TitleHighlightData = nameMatch.MatchData; return settingResult; } var areaMatch = _api.FuzzySearch(query.Search, entry.Area); if (areaMatch.IsSearchPrecisionScoreMet()) { var settingResult = NewSettingResult(areaMatch.Score); return settingResult; } return entry.AltNames? .Select(altName => _api.FuzzySearch(query.Search, altName)) .Where(match => match.IsSearchPrecisionScoreMet()) .Select(altNameMatch => NewSettingResult(altNameMatch.Score)) .FirstOrDefault(); } } return resultList; } /// /// Add a tool-tip to the given , based o the given . /// /// The that contain informations for the tool-tip. /// The that need a tool-tip. private static void AddOptionalToolTip(WindowsSetting entry, Result result) { var toolTipText = new StringBuilder(); toolTipText.AppendLine($"{Resources.Application}: {entry.Type}"); toolTipText.AppendLine($"{Resources.Area}: {entry.Area}"); if (entry.AltNames != null && entry.AltNames.Any()) { var altList = entry.AltNames.Aggregate((current, next) => $"{current}, {next}"); toolTipText.AppendLine($"{Resources.AlternativeName}: {altList}"); } toolTipText.Append($"{Resources.Command}: {entry.Command}"); if (!string.IsNullOrEmpty(entry.Note)) { toolTipText.AppendLine(string.Empty); toolTipText.AppendLine(string.Empty); toolTipText.Append($"{Resources.Note}: {entry.Note}"); } result.TitleToolTip = toolTipText.ToString(); } /// /// Open the settings page of the given . /// /// The that contain the information to open the setting on command level. /// if the settings could be opened, otherwise . private static bool DoOpenSettingsAction(WindowsSetting entry) { ProcessStartInfo processStartInfo; var command = entry.Command; if (command.Contains("%windir%", StringComparison.InvariantCultureIgnoreCase)) { var windowsFolder = Environment.GetFolderPath(Environment.SpecialFolder.Windows); command = command.Replace("%windir%", windowsFolder, StringComparison.InvariantCultureIgnoreCase); } if (command.Contains(' ')) { var commandSplit = command.Split(' '); var file = commandSplit.First(); var arguments = command[file.Length..].TrimStart(); processStartInfo = new ProcessStartInfo(file, arguments) { UseShellExecute = false, }; } else { processStartInfo = new ProcessStartInfo(command) { UseShellExecute = true, }; } try { Process.Start(processStartInfo); return true; } catch (Exception exception) { Log.Exception("can't open settings", exception, typeof(ResultHelper)); return false; } } /// /// Set the score (known as order number or ranking number) /// for all in the given list, based on the given query. /// /// A list with s that need scores. /// The query to calculated the score for the s. private static void SetScores(IEnumerable resultList, string query) { var lowScore = 1_000; var mediumScore = 5_000; var highScore = 10_000; foreach (var result in resultList) { if (!(result.ContextData is WindowsSetting windowsSetting)) { continue; } if (windowsSetting.Name.StartsWith(query, StringComparison.CurrentCultureIgnoreCase)) { result.Score = highScore--; continue; } // If query starts with second or next word of name, set score. if (windowsSetting.Name.Contains($" {query}", StringComparison.CurrentCultureIgnoreCase)) { result.Score = mediumScore--; continue; } if (windowsSetting.Area.StartsWith(query, StringComparison.CurrentCultureIgnoreCase)) { result.Score = lowScore--; continue; } if (windowsSetting.AltNames is null) { result.Score = lowScore--; continue; } if (windowsSetting.AltNames.Any(x => x.StartsWith(query, StringComparison.CurrentCultureIgnoreCase))) { result.Score = mediumScore--; continue; } result.Score = lowScore--; } } } }