diff --git a/forge-gui/CHANGES.txt b/forge-gui/CHANGES.txt index 90f5ae1e1e1..8b2edbc67be 100644 --- a/forge-gui/CHANGES.txt +++ b/forge-gui/CHANGES.txt @@ -16,6 +16,15 @@ Forge now includes many of the new Commander 2014 cards. It may take a few days/ The game now correctly calculates whether an attack declaration is legal, based upon the restrictions and requirements present on the possible attacking creatures. AI support is not yet fully implemented, but the AI can always default to a legal attack declaration. +- Support for surrounding search expressions with quotations - +You can now wrap all or part of a search expression in the Deck Editor or other ItemManagers in quotations to prevent matching on anything that doesn't contain all words within the quotes in order. +For example, while searching for this expression: + creatures you don't control +will match on any cards that contains all 4 of those words in any configuration (24/14330 implemented), this expression: + "creatures you don't control" +will only match on cards that contain those exact words in that exact order with no other words in between (4/14330 implemented). + + --------- New Cards --------- diff --git a/forge-gui/src/main/java/forge/itemmanager/SFilterUtil.java b/forge-gui/src/main/java/forge/itemmanager/SFilterUtil.java index d040ebdcabe..98c9b705c9d 100644 --- a/forge-gui/src/main/java/forge/itemmanager/SFilterUtil.java +++ b/forge-gui/src/main/java/forge/itemmanager/SFilterUtil.java @@ -37,9 +37,8 @@ public class SFilterUtil { if (text.isEmpty()) { return Predicates.alwaysTrue(); } - - if (BooleanExpression.isExpression(text)) { + if (BooleanExpression.isExpression(text)) { BooleanExpression expression = new BooleanExpression(text, inName, inType, inText, inCost); try { @@ -47,15 +46,14 @@ public class SFilterUtil { if (filter != null) { return Predicates.compose(invert ? Predicates.not(filter) : filter, PaperCard.FN_GET_RULES); } - } catch (Exception ignored) { + } + catch (Exception ignored) { ignored.printStackTrace(); //Continue with standard filtering if the expression is not valid. } - } - - String[] splitText = text.replaceAll(",", "").replaceAll(" ", " ").split(" "); + List splitText = getSplitText(text); List> terms = new ArrayList<>(); for (String s : splitText) { List> subands = new ArrayList<>(); @@ -72,6 +70,45 @@ public class SFilterUtil { return Predicates.compose(textFilter, PaperCard.FN_GET_RULES); } + private static List getSplitText(String text) { + boolean inQuotes = false; + String entry = ""; + List splitText = new ArrayList(); + for (int i = 0; i < text.length(); i++) { + char ch = text.charAt(i); + switch (ch) { + case ' ': + if (!inQuotes) { //if not in quotes, end current entry + if (entry.length() > 0) { + splitText.add(entry); + entry = ""; + } + continue; + } + break; + case '"': + inQuotes = !inQuotes; + continue; //don't append quotation character itself + case '\\': + if (i < text.length() - 1 && text.charAt(i + 1) == '"') { + ch = '"'; //allow appending escaped quotation character + i++; //prevent chaging inQuotes for that character + } + break; + case ',': + if (!inQuotes) { //ignore commas outside quotes + continue; + } + break; + } + entry += ch; + } + if (entry.length() > 0) { + splitText.add(entry); + } + return splitText; + } + public static Predicate buildItemTextFilter(String text) { if (text.trim().isEmpty()) { return Predicates.alwaysTrue(); @@ -81,12 +118,12 @@ public class SFilterUtil { } private static class ItemTextPredicate implements Predicate { - private final String[] splitText; + private final List splitText; private ItemTextPredicate(String text) { - splitText = text.toLowerCase().replaceAll(",", "").replaceAll(" ", " ").split(" "); + splitText = getSplitText(text.toLowerCase()); } - + @Override public boolean apply(T input) { String name = input.getName().toLowerCase();