From 8d0b36d2d4cef1fccde0e6ea3f5db45a19756dac Mon Sep 17 00:00:00 2001 From: RickyRister <42636155+RickyRister@users.noreply.github.com> Date: Thu, 12 Jun 2025 18:16:35 -0700 Subject: [PATCH] [VDS] add deck search query options for name, filename, and path (#5975) * implement search expressions * update syntax help --- cockatrice/resources/help/deck_search.md | 14 ++++++++++ .../src/game/filters/deck_filter_string.cpp | 28 ++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/cockatrice/resources/help/deck_search.md b/cockatrice/resources/help/deck_search.md index e2fa4fe37..95c237b16 100644 --- a/cockatrice/resources/help/deck_search.md +++ b/cockatrice/resources/help/deck_search.md @@ -8,6 +8,20 @@ searches are case insensitive.
[red deck wins](#red deck wins) (Any deck with a display name containing the words red, deck, and wins)
["red deck wins"](#%22red deck wins%22) (Any deck with a display name containing the exact phrase "red deck wins")
+
Deck Name:
+
[n:aggro](#n:aggro) (Any deck with a name containing the word aggro)
+
[n:red n:deck n:wins](#n:red n:deck n:wins) (Any deck with a name containing the words red, deck, and wins)
+
[n:"red deck wins"](#n:%22red deck wins%22) (Any deck with a name containing the exact phrase "red deck wins")
+ +
File Name:
+
[f:aggro](#f:aggro) (Any deck with a filename containing the word aggro)
+
[f:red f:deck f:wins](#f:red f:deck f:wins) (Any deck with a filename containing the words red, deck, and wins)
+
[f:"red deck wins"](#f:%22red deck wins%22) (Any deck with a filename containing the exact phrase "red deck wins")
+ +
Relative Path (starting from the deck folder):
+
[p:aggro](#p:aggro) (Any deck that has "aggro" somewhere in its relative path)
+
[p:edh/](#p:edh/) (Any deck with "edh/" in its relative path, A.K.A. decks in the "edh" folder)
+
Deck Contents (Uses [card search expressions](#cardSearchSyntaxHelp)):
[[plains]] (Any deck that contains at least one card with "plains" in its name)
[[t:legendary]] (Any deck that contains at least one legendary)
diff --git a/cockatrice/src/game/filters/deck_filter_string.cpp b/cockatrice/src/game/filters/deck_filter_string.cpp index 13c39910d..4d493e5f1 100644 --- a/cockatrice/src/game/filters/deck_filter_string.cpp +++ b/cockatrice/src/game/filters/deck_filter_string.cpp @@ -12,7 +12,7 @@ QueryPartList <- ComplexQueryPart ( ws ("AND" ws)? ComplexQueryPart)* ws* ComplexQueryPart <- SomewhatComplexQueryPart ws "OR" ws ComplexQueryPart / SomewhatComplexQueryPart SomewhatComplexQueryPart <- [(] QueryPartList [)] / QueryPart -QueryPart <- NotQuery / DeckContentQuery / GenericQuery +QueryPart <- NotQuery / DeckContentQuery / DeckNameQuery / FileNameQuery / PathQuery / GenericQuery NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart @@ -20,6 +20,10 @@ DeckContentQuery <- CardSearch NumericExpression? CardSearch <- '[[' CardFilterString ']]' CardFilterString <- (!']]'.)* +DeckNameQuery <- ([Dd] 'eck')? [Nn] 'ame'? [:] String +FileNameQuery <- [Ff] ('ile' 'name'?)? [:] String +PathQuery <- [Pp] 'ath'? [:] String + GenericQuery <- String NonDoubleQuoteUnlessEscaped <- '\\\"'. / !["]. @@ -129,6 +133,28 @@ static void setupParserRules() return QString::fromStdString(std::string(sv.sv())); }; + search["DeckNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { + auto name = std::any_cast(sv[0]); + return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) { + return deck->deckLoader->getName().contains(name, Qt::CaseInsensitive); + }; + }; + + search["FileNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { + auto name = std::any_cast(sv[0]); + return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) { + auto filename = QFileInfo(deck->filePath).fileName(); + return filename.contains(name, Qt::CaseInsensitive); + }; + }; + + search["PathQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { + auto name = std::any_cast(sv[0]); + return [=](const DeckPreviewWidget *, const ExtraDeckSearchInfo &info) { + return info.relativeFilePath.contains(name, Qt::CaseInsensitive); + }; + }; + search["GenericQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { auto name = std::any_cast(sv[0]); return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {