From f733d1ec1fcf08a147d24aeab20d3e8187936c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 3 Mar 2021 21:58:34 +0100 Subject: [PATCH] Expose and document query parser and helpers --- .../Rulesets/Filter/IRulesetFilterCriteria.cs | 11 +++ osu.Game/Screens/Select/FilterQueryParser.cs | 89 +++++++++++++++---- 2 files changed, 84 insertions(+), 16 deletions(-) diff --git a/osu.Game/Rulesets/Filter/IRulesetFilterCriteria.cs b/osu.Game/Rulesets/Filter/IRulesetFilterCriteria.cs index a83f87d72b..13cc41f8e0 100644 --- a/osu.Game/Rulesets/Filter/IRulesetFilterCriteria.cs +++ b/osu.Game/Rulesets/Filter/IRulesetFilterCriteria.cs @@ -31,6 +31,17 @@ public interface IRulesetFilterCriteria /// {key}{op}{value} /// /// + /// + /// + /// For adding optional string criteria, can be used for matching, + /// along with for parsing. + /// + /// + /// For adding numerical-type range criteria, can be used for matching, + /// along with + /// and - and -typed overloads for parsing. + /// + /// /// The key (name) of the criterion. /// The operator in the criterion. /// The value of the criterion. diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index ce937d07b1..ea7f233bea 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -9,7 +9,10 @@ namespace osu.Game.Screens.Select { - internal static class FilterQueryParser + /// + /// Utility class used for parsing song select filter queries entered via the search box. + /// + public static class FilterQueryParser { private static readonly Regex query_syntax_regex = new Regex( @"\b(?\w+)(?(:|=|(>|<)(:|=)?))(?("".*"")|(\S*))", @@ -35,36 +38,36 @@ private static bool tryParseKeywordCriteria(FilterCriteria criteria, string key, switch (key) { case "stars": - return tryUpdateCriteriaRange(ref criteria.StarDifficulty, op, value, 0.01d / 2); + return TryUpdateCriteriaRange(ref criteria.StarDifficulty, op, value, 0.01d / 2); case "ar": - return tryUpdateCriteriaRange(ref criteria.ApproachRate, op, value); + return TryUpdateCriteriaRange(ref criteria.ApproachRate, op, value); case "dr": case "hp": - return tryUpdateCriteriaRange(ref criteria.DrainRate, op, value); + return TryUpdateCriteriaRange(ref criteria.DrainRate, op, value); case "cs": - return tryUpdateCriteriaRange(ref criteria.CircleSize, op, value); + return TryUpdateCriteriaRange(ref criteria.CircleSize, op, value); case "bpm": - return tryUpdateCriteriaRange(ref criteria.BPM, op, value, 0.01d / 2); + return TryUpdateCriteriaRange(ref criteria.BPM, op, value, 0.01d / 2); case "length": return tryUpdateLengthRange(criteria, op, value); case "divisor": - return tryUpdateCriteriaRange(ref criteria.BeatDivisor, op, value, tryParseInt); + return TryUpdateCriteriaRange(ref criteria.BeatDivisor, op, value, tryParseInt); case "status": - return tryUpdateCriteriaRange(ref criteria.OnlineStatus, op, value, + return TryUpdateCriteriaRange(ref criteria.OnlineStatus, op, value, (string s, out BeatmapSetOnlineStatus val) => Enum.TryParse(value, true, out val)); case "creator": - return tryUpdateCriteriaText(ref criteria.Creator, op, value); + return TryUpdateCriteriaText(ref criteria.Creator, op, value); case "artist": - return tryUpdateCriteriaText(ref criteria.Artist, op, value); + return TryUpdateCriteriaText(ref criteria.Artist, op, value); default: return criteria.RulesetCriteria?.TryParseCustomKeywordCriteria(key, op, value) ?? false; @@ -113,7 +116,18 @@ private static bool tryParseDoubleWithPoint(string value, out double result) => private static bool tryParseInt(string value, out int result) => int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result); - private static bool tryUpdateCriteriaText(ref FilterCriteria.OptionalTextFilter textFilter, Operator op, string value) + /// + /// Attempts to parse a keyword filter with the specified and textual . + /// If the value indicates a valid textual filter, the function returns true and the resulting data is stored into + /// . + /// + /// The to store the parsed data into, if successful. + /// + /// The operator for the keyword filter. + /// Only is valid for textual filters. + /// + /// The value of the keyword filter. + public static bool TryUpdateCriteriaText(ref FilterCriteria.OptionalTextFilter textFilter, Operator op, string value) { switch (op) { @@ -126,7 +140,20 @@ private static bool tryUpdateCriteriaText(ref FilterCriteria.OptionalTextFilter } } - private static bool tryUpdateCriteriaRange(ref FilterCriteria.OptionalRange range, Operator op, string val, float tolerance = 0.05f) + /// + /// Attempts to parse a keyword filter of type + /// from the specified and . + /// If can be parsed as a , the function returns true + /// and the resulting range constraint is stored into . + /// + /// + /// The -typed + /// to store the parsed data into, if successful. + /// + /// The operator for the keyword filter. + /// The value of the keyword filter. + /// Allowed tolerance of the parsed range boundary value. + public static bool TryUpdateCriteriaRange(ref FilterCriteria.OptionalRange range, Operator op, string val, float tolerance = 0.05f) => tryParseFloatWithPoint(val, out float value) && tryUpdateCriteriaRange(ref range, op, value, tolerance); private static bool tryUpdateCriteriaRange(ref FilterCriteria.OptionalRange range, Operator op, float value, float tolerance = 0.05f) @@ -161,7 +188,20 @@ private static bool tryUpdateCriteriaRange(ref FilterCriteria.OptionalRange range, Operator op, string val, double tolerance = 0.05) + /// + /// Attempts to parse a keyword filter of type + /// from the specified and . + /// If can be parsed as a , the function returns true + /// and the resulting range constraint is stored into . + /// + /// + /// The -typed + /// to store the parsed data into, if successful. + /// + /// The operator for the keyword filter. + /// The value of the keyword filter. + /// Allowed tolerance of the parsed range boundary value. + public static bool TryUpdateCriteriaRange(ref FilterCriteria.OptionalRange range, Operator op, string val, double tolerance = 0.05) => tryParseDoubleWithPoint(val, out double value) && tryUpdateCriteriaRange(ref range, op, value, tolerance); private static bool tryUpdateCriteriaRange(ref FilterCriteria.OptionalRange range, Operator op, double value, double tolerance = 0.05) @@ -196,11 +236,28 @@ private static bool tryUpdateCriteriaRange(ref FilterCriteria.OptionalRange(string val, out T value); + /// + /// Used to determine whether the string value can be converted to type . + /// If conversion can be performed, the delegate returns true + /// and the conversion result is returned in the out parameter . + /// + /// The string value to attempt parsing for. + /// The parsed value, if conversion is possible. + public delegate bool TryParseFunction(string val, out T parsed); - private static bool tryUpdateCriteriaRange(ref FilterCriteria.OptionalRange range, Operator op, string value, TryParseFunction conversionFunc) + /// + /// Attempts to parse a keyword filter of type , + /// from the specified and . + /// If can be parsed into using , the function returns true + /// and the resulting range constraint is stored into . + /// + /// The to store the parsed data into, if successful. + /// The operator for the keyword filter. + /// The value of the keyword filter. + /// Function used to determine if can be converted to type . + public static bool TryUpdateCriteriaRange(ref FilterCriteria.OptionalRange range, Operator op, string val, TryParseFunction parseFunction) where T : struct - => conversionFunc.Invoke(value, out var converted) && tryUpdateCriteriaRange(ref range, op, converted); + => parseFunction.Invoke(val, out var converted) && tryUpdateCriteriaRange(ref range, op, converted); private static bool tryUpdateCriteriaRange(ref FilterCriteria.OptionalRange range, Operator op, T value) where T : struct