diff --git a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/Context.java b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/Context.java index dc16e3203..538591742 100644 --- a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/Context.java +++ b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/Context.java @@ -23,6 +23,7 @@ */ package net.kyori.adventure.text.minimessage; +import net.kyori.adventure.pointer.Pointered; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; @@ -40,6 +41,40 @@ @ApiStatus.NonExtendable public interface Context { + /** + * The target of the parse context, if provided. + * Can be used for tags that provide information relating to the target of the resulting message. + * + * @return the target, if provided + * @since 4.17.0 + */ + public @Nullable Pointered target(); + + /** + * The target of the parse context. + * Can be used for tags that provide information relating to the target of the resulting message. + * + *
If the caller did not provide a target, a parse exception is thrown with a default message.
+ * + * @return the target, if provided + * @since 4.17.0 + */ + public @NotNull Pointered targetOrThrow(); + + /** + * The target of the parse context, casted to a provided type. + * Can be used for tags that provide information relating to the target of the resulting message. + * + *If the caller did not provide a target, or the target is not of the provided type, a parse + * exception is thrown with a default message.
+ * + * @paramTags will be resolved from the resolver parameter before the resolver provided in the builder is used.
+ * + * @param input the input string + * @param target the target of the deserialization + * @param tagResolver the tag resolver for any additional tags to handle + * @return the output component + * @since 4.17.0 + */ + @NotNull Component deserialize(final @NotNull String input, final @NotNull Pointered target, final @NotNull TagResolver tagResolver); + + /** + * Deserializes a string into a component, with tag resolvers to parse tags of the form {@codeTags will be resolved from the resolver parameters before the resolver provided in the builder is used.
* @@ -159,7 +183,22 @@ public interface MiniMessage extends ComponentSerializerTags will be resolved from the resolver parameters before the resolver provided in the builder is used.
+ * + * @param input the input string + * @param target the target of the deserialization + * @param tagResolvers a series of tag resolvers to apply extra tags from, last specified taking priority + * @return the output component + * @since 4.17.0 + */ + default @NotNull Component deserialize(final @NotNull String input, final @NotNull Pointered target, final @NotNull TagResolver... tagResolvers) { + return this.deserialize(input, target, TagResolver.resolver(tagResolvers)); + } + + /** + * Deserializes a string into a tree of parsed elements. * This is intended for inspecting the output of the parser for debugging purposes. * * @param input the input string @@ -168,6 +207,17 @@ public interface MiniMessage extends ComponentSerializerTags will be resolved from the resolver parameter before the resolver provided in the builder is used.
+ * + * @param input the input string + * @param target the target of the deserialization + * @param tagResolver the tag resolver for any additional tags to handle + * @return the root of the resulting tree + * @since 4.17.0 + */ + Node.@NotNull Root deserializeToTree(final @NotNull String input, final @NotNull Pointered target, final @NotNull TagResolver tagResolver); + /** * Deserializes a string into a tree of parsed elements, with a tag resolver to parse tags of the form {@codeTags will be resolved from the resolver parameter before the resolver provided in the builder is used.
+ * + * @param input the input string + * @param target the target of the deserialization + * @param tagResolvers a series of tag resolvers to apply extra tags from, last specified taking priority + * @return the root of the resulting tree + * @since 4.17.0 + */ + default Node.@NotNull Root deserializeToTree(final @NotNull String input, final @NotNull Pointered target, final @NotNull TagResolver... tagResolvers) { + return this.deserializeToTree(input, target, TagResolver.resolver(tagResolvers)); + } + /** * Returns if this MiniMessage instance is in strict mode. * diff --git a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessageImpl.java b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessageImpl.java index 372fcde6d..099da5bd4 100644 --- a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessageImpl.java +++ b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessageImpl.java @@ -27,6 +27,7 @@ import java.util.Optional; import java.util.function.Consumer; import java.util.function.UnaryOperator; +import net.kyori.adventure.pointer.Pointered; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.internal.serializer.SerializableResolver; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; @@ -76,22 +77,42 @@ static final class Instances { @Override public @NotNull Component deserialize(final @NotNull String input) { - return this.parser.parseFormat(this.newContext(input, null)); + return this.parser.parseFormat(this.newContext(input, null, null)); + } + + @Override + public @NotNull Component deserialize(final @NotNull String input, final @NotNull Pointered target) { + return this.parser.parseFormat(this.newContext(input, requireNonNull(target, "target"), null)); } @Override public @NotNull Component deserialize(final @NotNull String input, final @NotNull TagResolver tagResolver) { - return this.parser.parseFormat(this.newContext(input, requireNonNull(tagResolver, "tagResolver"))); + return this.parser.parseFormat(this.newContext(input, null, requireNonNull(tagResolver, "tagResolver"))); + } + + @Override + public @NotNull Component deserialize(final @NotNull String input, final @NotNull Pointered target, final @NotNull TagResolver tagResolver) { + return this.parser.parseFormat(this.newContext(input, requireNonNull(target, "target"), requireNonNull(tagResolver, "tagResolver"))); } @Override public Node.@NotNull Root deserializeToTree(final @NotNull String input) { - return this.parser.parseToTree(this.newContext(input, null)); + return this.parser.parseToTree(this.newContext(input, null, null)); + } + + @Override + public Node.@NotNull Root deserializeToTree(final @NotNull String input, final @NotNull Pointered target) { + return this.parser.parseToTree(this.newContext(input, requireNonNull(target, "target"), null)); } @Override public Node.@NotNull Root deserializeToTree(final @NotNull String input, final @NotNull TagResolver tagResolver) { - return this.parser.parseToTree(this.newContext(input, requireNonNull(tagResolver, "tagResolver"))); + return this.parser.parseToTree(this.newContext(input, null, requireNonNull(tagResolver, "tagResolver"))); + } + + @Override + public Node.@NotNull Root deserializeToTree(final @NotNull String input, final @NotNull Pointered target, final @NotNull TagResolver tagResolver) { + return this.parser.parseToTree(this.newContext(input, requireNonNull(target, "target"), requireNonNull(tagResolver, "tagResolver"))); } @Override @@ -116,22 +137,22 @@ private SerializableResolver serialResolver(final @Nullable TagResolver extraRes @Override public @NotNull String escapeTags(final @NotNull String input) { - return this.parser.escapeTokens(this.newContext(input, null)); + return this.parser.escapeTokens(this.newContext(input, null, null)); } @Override public @NotNull String escapeTags(final @NotNull String input, final @NotNull TagResolver tagResolver) { - return this.parser.escapeTokens(this.newContext(input, tagResolver)); + return this.parser.escapeTokens(this.newContext(input, null, tagResolver)); } @Override public @NotNull String stripTags(final @NotNull String input) { - return this.parser.stripTokens(this.newContext(input, null)); + return this.parser.stripTokens(this.newContext(input, null, null)); } @Override public @NotNull String stripTags(final @NotNull String input, final @NotNull TagResolver tagResolver) { - return this.parser.stripTokens(this.newContext(input, tagResolver)); + return this.parser.stripTokens(this.newContext(input, null, tagResolver)); } @Override @@ -144,13 +165,9 @@ public boolean strict() { return this.parser.tagResolver; } - private @NotNull ContextImpl newContext(final @NotNull String input, final @Nullable TagResolver resolver) { + private @NotNull ContextImpl newContext(final @NotNull String input, final @Nullable Pointered target, final @Nullable TagResolver resolver) { requireNonNull(input, "input"); - if (resolver == null) { - return ContextImpl.of(this.strict, this.debugOutput, input, this, TagResolver.empty(), this.preProcessor, this.postProcessor); - } else { - return ContextImpl.of(this.strict, this.debugOutput, input, this, resolver, this.preProcessor, this.postProcessor); - } + return new ContextImpl(this.strict, this.debugOutput, input, this, target, resolver, this.preProcessor, this.postProcessor); } static final class BuilderImpl implements Builder { diff --git a/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/AbstractTest.java b/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/AbstractTest.java index c5fcc58fd..3e55f3f51 100644 --- a/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/AbstractTest.java +++ b/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/AbstractTest.java @@ -72,7 +72,7 @@ protected final String prettyPrint(final Component component) { } public static Context dummyContext(final String originalMessage) { - return ContextImpl.of(false, null, originalMessage, (MiniMessageImpl) PARSER, TagResolver.empty(), UnaryOperator.identity(), Component::compact); + return new ContextImpl(false, null, originalMessage, PARSER, null, TagResolver.empty(), UnaryOperator.identity(), Component::compact); } public static ArgumentQueue emptyArgumentQueue(final Context context) { diff --git a/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/MiniMessageTest.java b/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/MiniMessageTest.java index 0ef997d2c..10e94ff29 100644 --- a/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/MiniMessageTest.java +++ b/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/MiniMessageTest.java @@ -27,6 +27,7 @@ import java.util.Collection; import java.util.List; import java.util.function.Predicate; +import net.kyori.adventure.pointer.Pointered; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.tag.Tag; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; @@ -49,6 +50,7 @@ import static net.kyori.adventure.text.format.TextDecoration.UNDERLINED; import static net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -437,6 +439,35 @@ void debugModeMoreComplexNoError() { assertTrue(messages.contains("}")); } + static class TestTarget1 implements Pointered { + public String data; + } + + static class TestTarget2 implements Pointered { + } + + @Test + void contextTargetUtilMethods() { + final TagResolver tagResolver0 = TagResolver.resolver("tag", (argumentQueue, context) -> { + assertThrows(ParsingException.class, () -> context.targetAsType(TestTarget2.class)); + return Tag.inserting(Component.text(context.targetAsType(TestTarget1.class).data)); + }); + final TestTarget1 target = new TestTarget1(); + target.data = "hello"; + assertEquals(Component.text("hello"), MiniMessage.miniMessage().deserialize("