mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-21 09:05:10 -07:00
[Card] Search cards by Scryfall Tagger tag
This commit is contained in:
parent
1803fce56c
commit
d65d23ffce
3 changed files with 63 additions and 1 deletions
|
|
@ -22,6 +22,11 @@ In this list of examples below, each entry has an explanation and can be clicked
|
|||
<dd>[t:basic](#t:basic) <small>(Any card with the type basic)</small></dd>
|
||||
<dd>[t:arcane t:instant](#t:arcane t:instant) <small>(Any card with the types arcane and instant)</small></dd>
|
||||
|
||||
<dt>Tags:</dt>
|
||||
<dd>[tags:ramp](#tags:ramp) <small>(Any card tagged "ramp" by the Scryfall Tagger community)</small></dd>
|
||||
<dd>[tags:draw tags:ramp](#tags:draw tags:ramp) <small>(Any card tagged both "draw" and "ramp")</small></dd>
|
||||
<dd>[tags:draw OR tags:ramp](#tags:draw OR tags:ramp) <small>(Any card tagged "draw" or "ramp")</small></dd>
|
||||
|
||||
<dt><u>C</u>olors:</dt>
|
||||
<dd>[c:w](#c:w) <small>(Any card that is white)</small></dd>
|
||||
<dd>[c:wu](#c:wu) <small>(Any card that is white or blue)</small></dd>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <QString>
|
||||
#include <functional>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/card/game_specific_terms.h>
|
||||
#include <libcockatrice/utility/peglib.h>
|
||||
|
||||
static peg::parser search(R"(
|
||||
|
|
@ -17,7 +18,7 @@ ComplexQueryPart <- SomewhatComplexQueryPart ws "OR" ws ComplexQueryPart / Somew
|
|||
|
||||
SomewhatComplexQueryPart <- [(] QueryPartList [)] / QueryPart
|
||||
|
||||
QueryPart <- NotQuery / SetQuery / RarityQuery / CMCQuery / FormatQuery / PowerQuery / ToughnessQuery / ColorQuery / TypeQuery / OracleQuery / FieldQuery / GenericQuery
|
||||
QueryPart <- NotQuery / SetQuery / RarityQuery / CMCQuery / FormatQuery / PowerQuery / ToughnessQuery / ColorQuery / TagQuery / TypeQuery / OracleQuery / FieldQuery / GenericQuery
|
||||
|
||||
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
|
||||
SetQuery <- ('e'/'set') SetExpression / ([:] FlexStringValue)
|
||||
|
|
@ -38,6 +39,8 @@ Legality <- [Ll] 'egal'? / [Bb] 'anned'? / [Rr] 'estricted'
|
|||
|
||||
TypeQuery <- [tT] 'ype'? [:] StringValue
|
||||
|
||||
TagQuery <- [tT]('ags'/'ag') [:] String
|
||||
|
||||
Color <- < [Ww] 'hite'? / [Uu] / [Bb] 'lack'? / [Rr] 'ed'? / [Gg] 'reen'? / [Bb] 'lue'? >
|
||||
ColorEx <- Color / [mc]
|
||||
|
||||
|
|
@ -133,6 +136,19 @@ static void setupParserRules()
|
|||
const auto matcher = std::any_cast<StringMatcher>(sv[0]);
|
||||
return [=](const CardData &x) -> bool { return matcher(x->getCardType()); };
|
||||
};
|
||||
search["TagQuery"] = [](const peg::SemanticValues &sv) -> Filter {
|
||||
// Tags are stored space-separated, so matching whole tokens keeps
|
||||
// `tags:ram` from matching `ramp`. Combine tags with AND:
|
||||
// `tags:draw tags:ramp`.
|
||||
const auto tag = std::any_cast<QString>(sv[0]).trimmed();
|
||||
return [=](const CardData &x) -> bool {
|
||||
const QString stored = x->getProperty(Mtg::Tags);
|
||||
if (stored.isEmpty() || tag.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return stored.split(" ", Qt::SkipEmptyParts).contains(tag, Qt::CaseInsensitive);
|
||||
};
|
||||
};
|
||||
search["SetQuery"] = [](const peg::SemanticValues &sv) -> Filter {
|
||||
if (sv.choice() == 1) {
|
||||
auto matcher = std::any_cast<StringMatcher>(sv[0]);
|
||||
|
|
|
|||
|
|
@ -124,6 +124,47 @@ TEST_F(CardQuery, SearchLanguageIsBoundPerInstance)
|
|||
ASSERT_TRUE(germanQuery.check(localized));
|
||||
}
|
||||
|
||||
CardInfoPtr taggedCard()
|
||||
{
|
||||
return CardInfo::newInstance("Tagged Card", "text", false, {{"tags", "ramp removal"}}, {}, {}, {}, {});
|
||||
}
|
||||
|
||||
TEST_F(CardQuery, TagsMatchWholeSlugs)
|
||||
{
|
||||
const CardData tagged = taggedCard();
|
||||
ASSERT_TRUE(FilterString("tags:ramp").check(tagged));
|
||||
ASSERT_TRUE(FilterString("tags:removal").check(tagged));
|
||||
ASSERT_TRUE(FilterString("tags:RAMP").check(tagged));
|
||||
ASSERT_TRUE(FilterString("tag:ramp").check(tagged));
|
||||
ASSERT_FALSE(FilterString("tags:squirrel").check(tagged));
|
||||
}
|
||||
|
||||
TEST_F(CardQuery, TagQueryDoesNotMatchPartialSlugs)
|
||||
{
|
||||
const CardData tagged = taggedCard();
|
||||
ASSERT_FALSE(FilterString("tags:ram").check(tagged));
|
||||
ASSERT_FALSE(FilterString("tags:mov").check(tagged));
|
||||
}
|
||||
|
||||
TEST_F(CardQuery, TagQueryCombinesWithAnd)
|
||||
{
|
||||
const CardData tagged = taggedCard();
|
||||
ASSERT_TRUE(FilterString("tags:ramp tags:removal").check(tagged));
|
||||
ASSERT_FALSE(FilterString("tags:ramp tags:squirrel").check(tagged));
|
||||
}
|
||||
|
||||
TEST_F(CardQuery, TagQueryTreatsCommasAsPartOfTheSlug)
|
||||
{
|
||||
// Tag lists are not a thing: `tags:draw` and `tags:ramp` are separate terms.
|
||||
const CardData tagged = taggedCard();
|
||||
ASSERT_FALSE(FilterString("tags:ramp,removal").check(tagged));
|
||||
}
|
||||
|
||||
TEST_F(CardQuery, TagQueryFalseWhenCardHasNoTags)
|
||||
{
|
||||
ASSERT_FALSE(FilterString("tags:ramp").check(cat));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue