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 &) {