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 01e963206..854fdc218 100644 --- a/api/src/main/java/net/kyori/adventure/text/TextReplacementRenderer.java +++ b/api/src/main/java/net/kyori/adventure/text/TextReplacementRenderer.java @@ -52,6 +52,7 @@ private TextReplacementRenderer() { final List oldChildren = component.children(); final int oldChildrenSize = oldChildren.size(); + Style oldStyle = component.style(); List children = null; Component modified = component; // replace the component itself @@ -78,6 +79,10 @@ private TextReplacementRenderer() { modified = replacement == null ? Component.empty() : replacement.asComponent(); + if (modified.style().hoverEvent() != null) { + oldStyle = oldStyle.hoverEvent(null); // Remove original hover if it has been replaced completely + } + // merge style of the match into this component to prevent unexpected loss of style modified = modified.style(modified.style().merge(component.style(), Style.Merge.Strategy.IF_ABSENT_ON_TARGET)); @@ -150,7 +155,7 @@ private TextReplacementRenderer() { // Only visit children if we're running if (state.running) { // hover event - final HoverEvent event = modified.style().hoverEvent(); + final HoverEvent event = oldStyle.hoverEvent(); if (event != null) { final HoverEvent rendered = event.withRenderedValue(this, state); if (event != rendered) { 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 b22676747..f8da4c6f1 100644 --- a/api/src/test/java/net/kyori/adventure/text/TextReplacementRendererTest.java +++ b/api/src/test/java/net/kyori/adventure/text/TextReplacementRendererTest.java @@ -279,4 +279,47 @@ void testDoesNotDuplicateComponents() { TextAssertions.assertEquals(expected, replaced); } + + // https://github.com/KyoriPowered/adventure/issues/638 + @Test + void testExactMatchHover() { + final Component expected = Component.text("two").hoverEvent(Component.text("one!")).append(Component.text("one?")); + final Component replacedExact = Component.text("one").replaceText(c -> c.match("one").replacement(expected)); + + final Component replacedNonExact = Component.text("one ").replaceText(c -> c.match("one").replacement(expected)); + final Component expectedNonExact = Component.text("") + .append(expected) + .append(Component.space()); + + TextAssertions.assertEquals(expected, replacedExact); + TextAssertions.assertEquals(expectedNonExact, replacedNonExact); + } + + @Test + void testHoverCollision() { + final Component original = Component.text("one") + .hoverEvent(Component.text("less important")); + + final Component replaced = original.replaceText(c -> c.match("one") + .replacement(Component.text("two").hoverEvent(Component.text("important")))); + + final Component expected = Component.text("two") + .hoverEvent(Component.text("important")); + + TextAssertions.assertEquals(expected, replaced); + } + + @Test + void testReplacementHoverWithOriginalHoverAlsoMatching() { + final Component original = Component.text("Hello") + .hoverEvent(Component.text("Hello Kyori")); + + final Component replaced = original.replaceText(c -> c.match("Hello") + .replacement(Component.text("Goodbye world").hoverEvent(Component.text("Hello world")))); + + final Component expected = Component.text("Goodbye world") + .hoverEvent(Component.text("Hello world")); + + TextAssertions.assertEquals(expected, replaced); + } }