mirror of
https://github.com/ppy/osu.git
synced 2024-11-13 16:13:34 +08:00
Merge branch 'master' into hud/kc-skinnable
This commit is contained in:
commit
af66ccbfdf
@ -159,6 +159,31 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
||||
Assert.AreEqual(filtered, carouselItem.Filtered.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("\"artist\"", false)]
|
||||
[TestCase("\"arti\"", true)]
|
||||
[TestCase("\"artist title author\"", true)]
|
||||
[TestCase("\"artist\" \"title\" \"author\"", false)]
|
||||
[TestCase("\"an artist\"", true)]
|
||||
[TestCase("\"tags too\"", false)]
|
||||
[TestCase("\"tags to\"", true)]
|
||||
[TestCase("\"version\"", false)]
|
||||
[TestCase("\"an auteur\"", true)]
|
||||
[TestCase("\"\\\"", true)] // nasty case, covers properly escaping user input in underlying regex.
|
||||
public void TestCriteriaMatchingExactTerms(string terms, bool filtered)
|
||||
{
|
||||
var exampleBeatmapInfo = getExampleBeatmap();
|
||||
var criteria = new FilterCriteria
|
||||
{
|
||||
Ruleset = new RulesetInfo { OnlineID = 6 },
|
||||
AllowConvertedBeatmaps = true,
|
||||
SearchText = terms
|
||||
};
|
||||
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
||||
carouselItem.Filter(criteria);
|
||||
Assert.AreEqual(filtered, carouselItem.Filtered.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("", false)]
|
||||
[TestCase("The", false)]
|
||||
|
@ -23,6 +23,31 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
||||
Assert.AreEqual(4, filterCriteria.SearchTerms.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestApplyQueriesBareWordsWithExactMatch()
|
||||
{
|
||||
const string query = "looking for \"a beatmap\" like \"this\"";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("looking for \"a beatmap\" like \"this\"", filterCriteria.SearchText);
|
||||
Assert.AreEqual(5, filterCriteria.SearchTerms.Length);
|
||||
|
||||
Assert.That(filterCriteria.SearchTerms[0].SearchTerm, Is.EqualTo("a beatmap"));
|
||||
Assert.That(filterCriteria.SearchTerms[0].Exact, Is.True);
|
||||
|
||||
Assert.That(filterCriteria.SearchTerms[1].SearchTerm, Is.EqualTo("this"));
|
||||
Assert.That(filterCriteria.SearchTerms[1].Exact, Is.True);
|
||||
|
||||
Assert.That(filterCriteria.SearchTerms[2].SearchTerm, Is.EqualTo("looking"));
|
||||
Assert.That(filterCriteria.SearchTerms[2].Exact, Is.False);
|
||||
|
||||
Assert.That(filterCriteria.SearchTerms[3].SearchTerm, Is.EqualTo("for"));
|
||||
Assert.That(filterCriteria.SearchTerms[3].Exact, Is.False);
|
||||
|
||||
Assert.That(filterCriteria.SearchTerms[4].SearchTerm, Is.EqualTo("like"));
|
||||
Assert.That(filterCriteria.SearchTerms[4].Exact, Is.False);
|
||||
}
|
||||
|
||||
/*
|
||||
* The following tests have been written a bit strangely (they don't check exact
|
||||
* bound equality with what the filter says).
|
||||
@ -235,6 +260,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
||||
Assert.AreEqual("find me songs by please", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(5, filterCriteria.SearchTerms.Length);
|
||||
Assert.AreEqual("singer", filterCriteria.Artist.SearchTerm);
|
||||
Assert.That(filterCriteria.Artist.Exact, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -246,6 +272,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
||||
Assert.AreEqual("really like yes", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(3, filterCriteria.SearchTerms.Length);
|
||||
Assert.AreEqual("name with space", filterCriteria.Artist.SearchTerm);
|
||||
Assert.That(filterCriteria.Artist.Exact, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -210,7 +210,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddAssert("collection filter still selected", () => control.CreateCriteria().CollectionBeatmapMD5Hashes.Any());
|
||||
AddAssert("collection filter still selected", () => control.CreateCriteria().CollectionBeatmapMD5Hashes?.Any() == true);
|
||||
|
||||
AddAssert("filter request not fired", () => !received);
|
||||
}
|
||||
|
@ -378,9 +378,6 @@ namespace osu.Game.Screens.Play
|
||||
IsBreakTime.BindTo(breakTracker.IsBreakTime);
|
||||
IsBreakTime.BindValueChanged(onBreakTimeChanged, true);
|
||||
|
||||
if (Configuration.AutomaticallySkipIntro)
|
||||
skipIntroOverlay.SkipWhenReady();
|
||||
|
||||
loadLeaderboard();
|
||||
}
|
||||
|
||||
@ -1086,6 +1083,9 @@ namespace osu.Game.Screens.Play
|
||||
throw new InvalidOperationException($"{nameof(StartGameplay)} should not be called when the gameplay clock is already running");
|
||||
|
||||
GameplayClockContainer.Reset(startClock: true);
|
||||
|
||||
if (Configuration.AutomaticallySkipIntro)
|
||||
skipIntroOverlay.SkipWhenReady();
|
||||
}
|
||||
|
||||
public override void OnSuspending(ScreenTransitionEvent e)
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
@ -65,16 +64,16 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
|
||||
if (criteria.SearchTerms.Length > 0)
|
||||
{
|
||||
var terms = BeatmapInfo.GetSearchableTerms();
|
||||
var searchableTerms = BeatmapInfo.GetSearchableTerms();
|
||||
|
||||
foreach (string criteriaTerm in criteria.SearchTerms)
|
||||
foreach (FilterCriteria.OptionalTextFilter criteriaTerm in criteria.SearchTerms)
|
||||
{
|
||||
bool any = false;
|
||||
|
||||
// ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
|
||||
foreach (string term in terms)
|
||||
foreach (string searchTerm in searchableTerms)
|
||||
{
|
||||
if (!term.Contains(criteriaTerm, StringComparison.InvariantCultureIgnoreCase)) continue;
|
||||
if (!criteriaTerm.Matches(searchTerm)) continue;
|
||||
|
||||
any = true;
|
||||
break;
|
||||
@ -98,7 +97,6 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
if (!match) return false;
|
||||
|
||||
match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true;
|
||||
|
||||
if (match && criteria.RulesetCriteria != null)
|
||||
match &= criteria.RulesetCriteria.Matches(BeatmapInfo);
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using System.Text.RegularExpressions;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Collections;
|
||||
using osu.Game.Rulesets;
|
||||
@ -20,7 +18,7 @@ namespace osu.Game.Screens.Select
|
||||
public GroupMode Group;
|
||||
public SortMode Sort;
|
||||
|
||||
public BeatmapSetInfo SelectedBeatmapSet;
|
||||
public BeatmapSetInfo? SelectedBeatmapSet;
|
||||
|
||||
public OptionalRange<double> StarDifficulty;
|
||||
public OptionalRange<float> ApproachRate;
|
||||
@ -40,12 +38,12 @@ namespace osu.Game.Screens.Select
|
||||
IsUpperInclusive = true
|
||||
};
|
||||
|
||||
public string[] SearchTerms = Array.Empty<string>();
|
||||
public OptionalTextFilter[] SearchTerms = Array.Empty<OptionalTextFilter>();
|
||||
|
||||
public RulesetInfo Ruleset;
|
||||
public RulesetInfo? Ruleset;
|
||||
public bool AllowConvertedBeatmaps;
|
||||
|
||||
private string searchText;
|
||||
private string searchText = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="SearchText"/> as a number (if it can be parsed as one).
|
||||
@ -58,11 +56,29 @@ namespace osu.Game.Screens.Select
|
||||
set
|
||||
{
|
||||
searchText = value;
|
||||
SearchTerms = searchText.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToArray();
|
||||
|
||||
List<OptionalTextFilter> terms = new List<OptionalTextFilter>();
|
||||
|
||||
string remainingText = value;
|
||||
|
||||
// First handle quoted segments to ensure we keep inline spaces in exact matches.
|
||||
foreach (Match quotedSegment in Regex.Matches(searchText, "(\"[^\"]+\")"))
|
||||
{
|
||||
terms.Add(new OptionalTextFilter { SearchTerm = quotedSegment.Value });
|
||||
remainingText = remainingText.Replace(quotedSegment.Value, string.Empty);
|
||||
}
|
||||
|
||||
// Then handle the rest splitting on any spaces.
|
||||
terms.AddRange(remainingText.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(s => new OptionalTextFilter
|
||||
{
|
||||
SearchTerm = s
|
||||
}));
|
||||
|
||||
SearchTerms = terms.ToArray();
|
||||
|
||||
SearchNumber = null;
|
||||
|
||||
if (SearchTerms.Length == 1 && int.TryParse(SearchTerms[0], out int parsed))
|
||||
if (SearchTerms.Length == 1 && int.TryParse(SearchTerms[0].SearchTerm, out int parsed))
|
||||
SearchNumber = parsed;
|
||||
}
|
||||
}
|
||||
@ -70,11 +86,9 @@ namespace osu.Game.Screens.Select
|
||||
/// <summary>
|
||||
/// Hashes from the <see cref="BeatmapCollection"/> to filter to.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public IEnumerable<string> CollectionBeatmapMD5Hashes { get; set; }
|
||||
public IEnumerable<string>? CollectionBeatmapMD5Hashes { get; set; }
|
||||
|
||||
[CanBeNull]
|
||||
public IRulesetFilterCriteria RulesetCriteria { get; set; }
|
||||
public IRulesetFilterCriteria? RulesetCriteria { get; set; }
|
||||
|
||||
public struct OptionalRange<T> : IEquatable<OptionalRange<T>>
|
||||
where T : struct
|
||||
@ -124,6 +138,8 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
public bool HasFilter => !string.IsNullOrEmpty(SearchTerm);
|
||||
|
||||
public bool Exact { get; private set; }
|
||||
|
||||
public bool Matches(string value)
|
||||
{
|
||||
if (!HasFilter)
|
||||
@ -133,10 +149,23 @@ namespace osu.Game.Screens.Select
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return false;
|
||||
|
||||
if (Exact)
|
||||
return Regex.IsMatch(value, $@"(^|\s){Regex.Escape(searchTerm)}($|\s)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
|
||||
return value.Contains(SearchTerm, StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public string SearchTerm;
|
||||
private string searchTerm;
|
||||
|
||||
public string SearchTerm
|
||||
{
|
||||
get => searchTerm;
|
||||
set
|
||||
{
|
||||
searchTerm = value.Trim('"');
|
||||
Exact = searchTerm != value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(OptionalTextFilter other) => SearchTerm == other.SearchTerm;
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ namespace osu.Game.Screens.Select
|
||||
switch (op)
|
||||
{
|
||||
case Operator.Equal:
|
||||
textFilter.SearchTerm = value.Trim('"');
|
||||
textFilter.SearchTerm = value;
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user