From 67a59c89bfc71688b4b2283d0553d61f778a19ea Mon Sep 17 00:00:00 2001 From: Kieran Wallbanks Date: Tue, 7 Jan 2025 12:46:38 +0000 Subject: [PATCH] feature(api): Replace text ignoring hover events --- .../adventure/text/TextReplacementConfig.java | 13 +++++++++++++ .../text/TextReplacementConfigImpl.java | 11 ++++++++++- .../adventure/text/TextReplacementRenderer.java | 16 ++++++++++------ .../text/TextReplacementRendererTest.java | 12 ++++++++++++ 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/net/kyori/adventure/text/TextReplacementConfig.java b/api/src/main/java/net/kyori/adventure/text/TextReplacementConfig.java index 58ab50a20..5b8c2cc7e 100644 --- a/api/src/main/java/net/kyori/adventure/text/TextReplacementConfig.java +++ b/api/src/main/java/net/kyori/adventure/text/TextReplacementConfig.java @@ -28,6 +28,7 @@ import java.util.regex.MatchResult; import java.util.regex.Pattern; import net.kyori.adventure.builder.AbstractBuilder; +import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.util.Buildable; import net.kyori.adventure.util.IntFunction2; import net.kyori.examination.Examinable; @@ -220,6 +221,18 @@ default Builder matchLiteral(final String literal) { */ @Contract("_ -> this") @NotNull Builder replacement(final @NotNull BiFunction replacement); + + /** + * Set if the replacement should replace inside {@link HoverEvent hover events}. + * + *

This defaults to {@code true}.

+ * + * @param replace if it should replace inside hover events + * @return this builder + * @since 4.19.0 + */ + @Contract("_ -> this") + @NotNull Builder replaceInsideHoverEvents(final boolean replace); } /** diff --git a/api/src/main/java/net/kyori/adventure/text/TextReplacementConfigImpl.java b/api/src/main/java/net/kyori/adventure/text/TextReplacementConfigImpl.java index c673f8dbc..fd937f28e 100644 --- a/api/src/main/java/net/kyori/adventure/text/TextReplacementConfigImpl.java +++ b/api/src/main/java/net/kyori/adventure/text/TextReplacementConfigImpl.java @@ -38,11 +38,13 @@ final class TextReplacementConfigImpl implements TextReplacementConfig { private final Pattern matchPattern; private final BiFunction replacement; private final Condition continuer; + private final boolean replaceInsideHoverEvents; TextReplacementConfigImpl(final Builder builder) { this.matchPattern = builder.matchPattern; this.replacement = builder.replacement; this.continuer = builder.continuer; + this.replaceInsideHoverEvents = builder.replaceInsideHoverEvents; } @Override @@ -51,7 +53,7 @@ final class TextReplacementConfigImpl implements TextReplacementConfig { } TextReplacementRenderer.State createState() { - return new TextReplacementRenderer.State(this.matchPattern, this.replacement, this.continuer); + return new TextReplacementRenderer.State(this.matchPattern, this.replacement, this.continuer, this.replaceInsideHoverEvents); } @Override @@ -77,6 +79,7 @@ static final class Builder implements TextReplacementConfig.Builder { @Nullable Pattern matchPattern; @Nullable BiFunction replacement; TextReplacementConfig.Condition continuer = (matchResult, index, replacement) -> PatternReplacementResult.REPLACE; + boolean replaceInsideHoverEvents = true; Builder() { } @@ -105,6 +108,12 @@ static final class Builder implements TextReplacementConfig.Builder { return this; } + @Override + public TextReplacementConfig.@NotNull Builder replaceInsideHoverEvents(final boolean replace) { + this.replaceInsideHoverEvents = replace; + return this; + } + @Override public @NotNull TextReplacementConfig build() { if (this.matchPattern == null) throw new IllegalStateException("A pattern must be provided to match against"); diff --git a/api/src/main/java/net/kyori/adventure/text/TextReplacementRenderer.java b/api/src/main/java/net/kyori/adventure/text/TextReplacementRenderer.java index ae940aa19..d84feabff 100644 --- a/api/src/main/java/net/kyori/adventure/text/TextReplacementRenderer.java +++ b/api/src/main/java/net/kyori/adventure/text/TextReplacementRenderer.java @@ -155,11 +155,13 @@ private TextReplacementRenderer() { // Only visit children if we're running if (state.running) { // hover event - final HoverEvent event = oldStyle.hoverEvent(); - if (event != null) { - final HoverEvent rendered = event.withRenderedValue(this, state); - if (event != rendered) { - modified = modified.style(s -> s.hoverEvent(rendered)); + if (state.replaceInsideHoverEvents) { + final HoverEvent event = oldStyle.hoverEvent(); + if (event != null) { + final HoverEvent rendered = event.withRenderedValue(this, state); + if (event != rendered) { + modified = modified.style(s -> s.hoverEvent(rendered)); + } } } // Children @@ -200,15 +202,17 @@ static final class State { final Pattern pattern; final BiFunction replacement; final TextReplacementConfig.Condition continuer; + final boolean replaceInsideHoverEvents; boolean running = true; int matchCount = 0; int replaceCount = 0; boolean firstMatch = true; - State(final @NotNull Pattern pattern, final @NotNull BiFunction replacement, final TextReplacementConfig.@NotNull Condition continuer) { + State(final @NotNull Pattern pattern, final @NotNull BiFunction replacement, final TextReplacementConfig.@NotNull Condition continuer, final boolean replaceInsideHoverEvents) { this.pattern = pattern; this.replacement = replacement; this.continuer = continuer; + this.replaceInsideHoverEvents = replaceInsideHoverEvents; } } } diff --git a/api/src/test/java/net/kyori/adventure/text/TextReplacementRendererTest.java b/api/src/test/java/net/kyori/adventure/text/TextReplacementRendererTest.java index 739f74b82..7477e61c4 100644 --- a/api/src/test/java/net/kyori/adventure/text/TextReplacementRendererTest.java +++ b/api/src/test/java/net/kyori/adventure/text/TextReplacementRendererTest.java @@ -322,4 +322,16 @@ void testReplacementHoverWithOriginalHoverAlsoMatching() { TextAssertions.assertEquals(expected, replaced); } + + @Test + void testIgnoringHover() { + final Component original = Component.text("one") + .hoverEvent(Component.text("meow")); + + final Component replaced = original.replaceText(c -> c.match("meow") + .replacement(Component.text("woof")) + .replaceInsideHoverEvents(false)); + + TextAssertions.assertEquals(original, replaced); + } }