From 2d99a0c36a9da88ab2505d3aa7f81c54747d15a3 Mon Sep 17 00:00:00 2001 From: filoghost Date: Wed, 4 Aug 2021 19:40:50 +0200 Subject: [PATCH] Simplify placeholder replacement --- .../placeholderapi/PlaceholderAPIHook.java | 2 +- .../plugin/hologram/tracking/DisplayText.java | 33 ++-- .../parsing/PlaceholderReplaceFunction.java | 6 +- .../parsing/StringWithPlaceholders.java | 165 +++++++++++------- .../tracking/PlaceholderTracker.java | 2 +- .../parsing/StringWithPlaceholdersTest.java | 4 +- 6 files changed, 129 insertions(+), 83 deletions(-) diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/bridge/placeholderapi/PlaceholderAPIHook.java b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/bridge/placeholderapi/PlaceholderAPIHook.java index 840f2019..6d95d442 100644 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/bridge/placeholderapi/PlaceholderAPIHook.java +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/bridge/placeholderapi/PlaceholderAPIHook.java @@ -22,7 +22,7 @@ public class PlaceholderAPIHook { enabled = true; } - public static boolean containsPlaceholders(String text) { + public static boolean containsPlaceholderPattern(String text) { if (Strings.isEmpty(text)) { return false; } diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/DisplayText.java b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/DisplayText.java index c5f69691..7a4b7b23 100644 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/DisplayText.java +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/hologram/tracking/DisplayText.java @@ -20,35 +20,43 @@ class DisplayText { private final PlaceholderTracker placeholderTracker; private @NotNull StringWithPlaceholders textWithoutReplacements; private @NotNull StringWithPlaceholders textWithGlobalReplacements; + private boolean containsPlaceholderAPIPattern; DisplayText(PlaceholderTracker placeholderTracker) { this.placeholderTracker = placeholderTracker; this.textWithoutReplacements = StringWithPlaceholders.of(null); - this.textWithGlobalReplacements = StringWithPlaceholders.of(null); + this.textWithGlobalReplacements = textWithoutReplacements; } void setWithoutReplacements(@Nullable String textString) { textWithoutReplacements = StringWithPlaceholders.of(textString); textWithGlobalReplacements = textWithoutReplacements; + containsPlaceholderAPIPattern = textWithoutReplacements.anyLiteralPartMatch(PlaceholderAPIHook::containsPlaceholderPattern); } String getWithoutReplacements() { - return textWithoutReplacements.getUnreplacedString(); + return textWithoutReplacements.getString(); } String getWithGlobalReplacements() { - return textWithGlobalReplacements.getUnreplacedString(); + return textWithGlobalReplacements.getString(); } String getWithIndividualReplacements(Player player) { - String textWithIndividualReplacements = textWithGlobalReplacements.replacePlaceholders((PlaceholderOccurrence occurrence) -> - placeholderTracker.updateAndGetIndividualReplacement(occurrence, player)); - - if (PlaceholderAPIHook.isEnabled() && PlaceholderAPIHook.containsPlaceholders(textWithIndividualReplacements)) { - textWithIndividualReplacements = PlaceholderAPIHook.replacePlaceholders(player, textWithIndividualReplacements); - } - - return textWithIndividualReplacements; + return textWithGlobalReplacements.replaceParts( + (PlaceholderOccurrence placeholderOccurrence) -> { + return placeholderTracker.updateAndGetIndividualReplacement(placeholderOccurrence, player); + }, + (String literalPart) -> { + if (containsPlaceholderAPIPattern + && PlaceholderAPIHook.isEnabled() + && PlaceholderAPIHook.containsPlaceholderPattern(literalPart)) { + return PlaceholderAPIHook.replacePlaceholders(player, literalPart); + } else { + return literalPart; + } + } + ); } boolean updateGlobalReplacements() { @@ -68,8 +76,7 @@ class DisplayText { } boolean containsIndividualPlaceholders() { - return placeholderTracker.containsIndividualPlaceholders(textWithoutReplacements) - || PlaceholderAPIHook.containsPlaceholders(textWithoutReplacements.getUnreplacedString()); + return containsPlaceholderAPIPattern || placeholderTracker.containsIndividualPlaceholders(textWithoutReplacements); } } diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/placeholder/parsing/PlaceholderReplaceFunction.java b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/placeholder/parsing/PlaceholderReplaceFunction.java index 6411b338..1e07b1c3 100644 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/placeholder/parsing/PlaceholderReplaceFunction.java +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/placeholder/parsing/PlaceholderReplaceFunction.java @@ -5,9 +5,13 @@ */ package me.filoghost.holographicdisplays.plugin.placeholder.parsing; +import org.jetbrains.annotations.Nullable; + @FunctionalInterface public interface PlaceholderReplaceFunction { - String getReplacement(PlaceholderOccurrence placeholderOccurrence); + PlaceholderReplaceFunction NO_REPLACEMENTS = placeholderOccurrence -> null; + + @Nullable String getReplacement(PlaceholderOccurrence placeholderOccurrence); } diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/placeholder/parsing/StringWithPlaceholders.java b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/placeholder/parsing/StringWithPlaceholders.java index 3749beed..491885eb 100644 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/placeholder/parsing/StringWithPlaceholders.java +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/placeholder/parsing/StringWithPlaceholders.java @@ -11,8 +11,8 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.UnaryOperator; public final class StringWithPlaceholders { @@ -36,23 +36,39 @@ public final class StringWithPlaceholders { this.stringParts = stringParts; } - public @Nullable String getUnreplacedString() { + public @Nullable String getString() { return string; } public boolean containsPlaceholders() { - return stringParts != null; + return string != null && stringParts != null; } - public boolean anyMatch(Predicate filter) { + public boolean anyPlaceholderMatch(Predicate filter) { if (!containsPlaceholders()) { return false; } for (StringPart stringPart : stringParts) { - if (stringPart instanceof PlaceholderStringPart) { - PlaceholderStringPart placeholderStringPart = (PlaceholderStringPart) stringPart; - if (filter.test(placeholderStringPart.placeholderOccurrence)) { + if (stringPart instanceof PlaceholderPart) { + PlaceholderPart placeholderPart = (PlaceholderPart) stringPart; + if (filter.test(placeholderPart.getPlaceholderOccurrence())) { + return true; + } + } + } + + return false; + } + + public boolean anyLiteralPartMatch(Predicate filter) { + if (!containsPlaceholders()) { + return filter.test(string); + } + + for (StringPart stringPart : stringParts) { + if (stringPart instanceof LiteralPart) { + if (filter.test(stringPart.getRawValue())) { return true; } } @@ -66,75 +82,49 @@ public final class StringWithPlaceholders { return this; } - StringBuilder output = new StringBuilder(); - StringBuilder fullOutput = new StringBuilder(); - List newStringParts = null; // Lazy initialization - + List newStringParts = new ArrayList<>(stringParts.size()); for (StringPart part : stringParts) { - if (part instanceof PlaceholderStringPart) { - PlaceholderStringPart placeholderStringPart = (PlaceholderStringPart) part; - String replacement = replaceFunction.getReplacement(placeholderStringPart.placeholderOccurrence); + if (part instanceof PlaceholderPart) { + String replacement = replaceFunction.getReplacement(((PlaceholderPart) part).getPlaceholderOccurrence()); if (replacement != null) { - output.append(replacement); - fullOutput.append(replacement); + // Do not use LiteralPart to avoid potentially replacing it again later + newStringParts.add(new ReplacementPart(replacement)); } else { // Placeholder was not replaced, may be replaced later - if (newStringParts == null) { - newStringParts = new ArrayList<>(); - } - // Append leading literal string, if present - if (output.length() > 0) { - newStringParts.add(new LiteralStringPart(output.toString())); - output.setLength(0); - } - newStringParts.add(placeholderStringPart); - fullOutput.append(placeholderStringPart.unreplacedString); + newStringParts.add(part); } } else { - LiteralStringPart literalStringPart = (LiteralStringPart) part; - output.append(literalStringPart.literalString); - fullOutput.append(literalStringPart.literalString); + newStringParts.add(part); } } - if (output.length() > 0 && newStringParts != null) { - newStringParts.add(new LiteralStringPart(output.toString())); - } - - return new StringWithPlaceholders(fullOutput.toString(), newStringParts); + return new StringWithPlaceholders(joinParts(newStringParts), newStringParts); } public @Nullable String replacePlaceholders(PlaceholderReplaceFunction replaceFunction) { - if (!containsPlaceholders()) { - return string; - } - - StringBuilder output = new StringBuilder(); - for (StringPart part : stringParts) { - output.append(part.getValue(replaceFunction)); - } - - return output.toString(); + return replaceParts(replaceFunction, UnaryOperator.identity()); } - public String replaceLiteralParts(Function transformFunction) { - if (!containsPlaceholders() || string == null) { - return transformFunction.apply(string); + public String replaceLiteralParts(UnaryOperator replaceFunction) { + return replaceParts(PlaceholderReplaceFunction.NO_REPLACEMENTS, replaceFunction); + } + + public String replaceParts(PlaceholderReplaceFunction placeholderReplaceFunction, UnaryOperator literalPartReplaceFunction) { + if (!containsPlaceholders()) { + return literalPartReplaceFunction.apply(string); } - StringBuilder stringOutput = new StringBuilder(string.length()); + StringBuilder output = new StringBuilder(string.length()); for (StringPart part : stringParts) { - if (part instanceof LiteralStringPart) { - LiteralStringPart literalStringPart = (LiteralStringPart) part; - String transformedPart = transformFunction.apply(literalStringPart.literalString); - stringOutput.append(transformedPart); + if (part instanceof LiteralPart) { + output.append(literalPartReplaceFunction.apply(part.getRawValue())); } else { - stringOutput.append(((PlaceholderStringPart) part).unreplacedString); + output.append(part.getValue(placeholderReplaceFunction)); } } - return stringOutput.toString(); + return output.toString(); } private static @Nullable List splitToParts(@NotNull String string) { @@ -163,11 +153,11 @@ public final class StringWithPlaceholders { // Append leading literal part (if any) if (placeholderStartIndex != lastAppendIndex) { - stringParts.add(new LiteralStringPart(string.substring(lastAppendIndex, placeholderStartIndex))); + stringParts.add(new LiteralPart(string.substring(lastAppendIndex, placeholderStartIndex))); } // Append placeholder part - stringParts.add(new PlaceholderStringPart(content, unparsedString)); + stringParts.add(new PlaceholderPart(content, unparsedString)); lastAppendIndex = endIndex; placeholderStartIndex = -1; @@ -185,12 +175,20 @@ public final class StringWithPlaceholders { // Append trailing literal part (if any) if (lastAppendIndex != string.length() && stringParts != null) { - stringParts.add(new LiteralStringPart(string.substring(lastAppendIndex))); + stringParts.add(new LiteralPart(string.substring(lastAppendIndex))); } return stringParts; } + private static String joinParts(@NotNull List stringParts) { + StringBuilder stringBuilder = new StringBuilder(); + for (StringPart stringPart : stringParts) { + stringBuilder.append(stringPart.getRawValue()); + } + return stringBuilder.toString(); + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -214,31 +212,59 @@ public final class StringWithPlaceholders { String getValue(PlaceholderReplaceFunction placeholderReplaceFunction); + String getRawValue(); + } - private static class LiteralStringPart implements StringPart { + private static class LiteralPart implements StringPart { - private final String literalString; + private final String value; - LiteralStringPart(String literalString) { - this.literalString = literalString; + LiteralPart(@NotNull String value) { + this.value = value; } @Override public String getValue(PlaceholderReplaceFunction placeholderReplaceFunction) { - return literalString; + return value; + } + + @Override + public String getRawValue() { + return value; } } - private static class PlaceholderStringPart implements StringPart { + private static class ReplacementPart implements StringPart { + + private final String replacement; + + ReplacementPart(@NotNull String replacement) { + this.replacement = replacement; + } + + @Override + public String getValue(PlaceholderReplaceFunction placeholderReplaceFunction) { + return replacement; + } + + @Override + public String getRawValue() { + return replacement; + } + + } + + + private static class PlaceholderPart implements StringPart { private final PlaceholderOccurrence placeholderOccurrence; private final String unreplacedString; - PlaceholderStringPart(PlaceholderOccurrence placeholderOccurrence, String unreplacedString) { + PlaceholderPart(@NotNull PlaceholderOccurrence placeholderOccurrence, @NotNull String unreplacedString) { this.placeholderOccurrence = placeholderOccurrence; this.unreplacedString = unreplacedString; } @@ -249,11 +275,20 @@ public final class StringWithPlaceholders { if (replacement != null) { return replacement; } else { - // If no replacement is provided, leave the unreplaced placeholder string + // If no replacement is provided return the unreplaced placeholder string return unreplacedString; } } + @Override + public String getRawValue() { + return unreplacedString; + } + + public PlaceholderOccurrence getPlaceholderOccurrence() { + return placeholderOccurrence; + } + } } diff --git a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/placeholder/tracking/PlaceholderTracker.java b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/placeholder/tracking/PlaceholderTracker.java index b1e04c7f..6aeef63e 100644 --- a/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/placeholder/tracking/PlaceholderTracker.java +++ b/plugin/src/main/java/me/filoghost/holographicdisplays/plugin/placeholder/tracking/PlaceholderTracker.java @@ -102,7 +102,7 @@ public class PlaceholderTracker { } public boolean containsIndividualPlaceholders(StringWithPlaceholders textWithPlaceholders) { - return textWithPlaceholders.anyMatch(occurrence -> { + return textWithPlaceholders.anyPlaceholderMatch(occurrence -> { PlaceholderExpansion placeholderExpansion = registry.find(occurrence); return placeholderExpansion != null && placeholderExpansion.isIndividual(); }); diff --git a/plugin/src/test/java/me/filoghost/holographicdisplays/plugin/placeholder/parsing/StringWithPlaceholdersTest.java b/plugin/src/test/java/me/filoghost/holographicdisplays/plugin/placeholder/parsing/StringWithPlaceholdersTest.java index 9a87776d..30917e0a 100644 --- a/plugin/src/test/java/me/filoghost/holographicdisplays/plugin/placeholder/parsing/StringWithPlaceholdersTest.java +++ b/plugin/src/test/java/me/filoghost/holographicdisplays/plugin/placeholder/parsing/StringWithPlaceholdersTest.java @@ -34,7 +34,7 @@ class StringWithPlaceholdersTest { boolean expectedContainsPlaceholders = expectedOutput.contains("#"); StringWithPlaceholders s = StringWithPlaceholders.of(input); - assertThat(s.partiallyReplacePlaceholders(occurrence -> "#").getUnreplacedString()).isEqualTo(expectedOutput); + assertThat(s.partiallyReplacePlaceholders(occurrence -> "#").getString()).isEqualTo(expectedOutput); assertThat(s.partiallyReplacePlaceholders(occurrence -> null).replacePlaceholders(occurrence -> "#")).isEqualTo(expectedOutput); assertThat(s.containsPlaceholders()).isEqualTo(expectedContainsPlaceholders); } @@ -82,7 +82,7 @@ class StringWithPlaceholdersTest { List placeholders = new ArrayList<>(); s.replacePlaceholders(occurrence -> { - placeholders.add(occurrence); // Just save occurrences + placeholders.add(occurrence); // Just collect occurrences return null; }); assertThat(placeholders).hasSize(1);