diff --git a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/ContextImpl.java b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/ContextImpl.java index 8342546dc..724ad90ed 100644 --- a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/ContextImpl.java +++ b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/ContextImpl.java @@ -23,6 +23,7 @@ */ package net.kyori.adventure.text.minimessage; +import java.util.function.Consumer; import java.util.function.UnaryOperator; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.placeholder.PlaceholderResolver; @@ -38,7 +39,7 @@ */ class ContextImpl implements Context { private final boolean strict; - private final Appendable debugOutput; + private final Consumer debugOutput; private final String originalMessage; private final MiniMessage miniMessage; private final PlaceholderResolver placeholderResolver; @@ -46,7 +47,7 @@ class ContextImpl implements Context { ContextImpl( final boolean strict, - final Appendable debugOutput, + final Consumer debugOutput, final String originalMessage, final MiniMessage miniMessage, final @NotNull PlaceholderResolver placeholderResolver, @@ -62,7 +63,7 @@ class ContextImpl implements Context { static ContextImpl of( final boolean strict, - final Appendable debugOutput, + final Consumer debugOutput, final String input, final MiniMessageImpl miniMessage, final PlaceholderResolver placeholderResolver, @@ -75,7 +76,7 @@ public boolean strict() { return this.strict; } - public Appendable debugOutput() { + public Consumer debugOutput() { return this.debugOutput; } diff --git a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessage.java b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessage.java index 55b158d5e..36fd32a52 100644 --- a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessage.java +++ b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessage.java @@ -181,11 +181,14 @@ interface Builder extends Buildable.Builder { * *

Debug output includes detailed information about the parsing process to help debug parser behavior.

* + *

The consumer will receive line fragments terminated by {@code LF}, not complete lines. + * This avoids string concatenation within debug output generation. If the consumer is {@code null}, no debug information will be generated.

+ * * @param debugOutput if debug mode should be enabled * @return this builder * @since 4.10.0 */ - @NotNull Builder debug(final @Nullable Appendable debugOutput); + @NotNull Builder debug(final @Nullable Consumer debugOutput); /** * If in lenient mode, MiniMessage will output helpful messages. 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 b9de28622..a1b29b91d 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 @@ -47,12 +47,12 @@ final class MiniMessageImpl implements MiniMessage { static final MiniMessage INSTANCE = new MiniMessageImpl(TransformationRegistry.standard(), PlaceholderResolver.empty(), false, null, DEFAULT_ERROR_CONSUMER, DEFAULT_COMPACTING_METHOD); private final boolean strict; - private final Appendable debugOutput; + private final @Nullable Consumer debugOutput; private final Consumer> parsingErrorMessageConsumer; private final UnaryOperator postProcessor; final MiniMessageParser parser; - MiniMessageImpl(final @NotNull TransformationRegistry registry, final @NotNull PlaceholderResolver placeholderResolver, final boolean strict, final Appendable debugOutput, final @NotNull Consumer> parsingErrorMessageConsumer, final @NotNull UnaryOperator postProcessor) { + MiniMessageImpl(final @NotNull TransformationRegistry registry, final @NotNull PlaceholderResolver placeholderResolver, final boolean strict, final @Nullable Consumer debugOutput, final @NotNull Consumer> parsingErrorMessageConsumer, final @NotNull UnaryOperator postProcessor) { this.parser = new MiniMessageParser(registry, placeholderResolver); this.strict = strict; this.debugOutput = debugOutput; @@ -122,7 +122,7 @@ static final class BuilderImpl implements Builder { private TransformationRegistry registry = TransformationRegistry.standard(); private PlaceholderResolver placeholderResolver = null; private boolean strict = false; - private Appendable debug = null; + private Consumer debug = null; private Consumer> parsingErrorMessageConsumer = DEFAULT_ERROR_CONSUMER; private UnaryOperator postProcessor = DEFAULT_COMPACTING_METHOD; @@ -164,7 +164,7 @@ static final class BuilderImpl implements Builder { } @Override - public @NotNull Builder debug(final @Nullable Appendable debugOutput) { + public @NotNull Builder debug(final @Nullable Consumer debugOutput) { this.debug = debugOutput; return this; } diff --git a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessageParser.java b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessageParser.java index a3d0df669..4c3d6f8bf 100644 --- a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessageParser.java +++ b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessageParser.java @@ -23,13 +23,13 @@ */ package net.kyori.adventure.text.minimessage; -import java.io.IOException; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.BiPredicate; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; import net.kyori.adventure.text.Component; @@ -120,45 +120,47 @@ private void processTokens(final @NotNull StringBuilder sb, final @NotNull Strin @NotNull Component parseFormat(final @NotNull String richMessage, final @NotNull ContextImpl context) { final PlaceholderResolver combinedResolver = PlaceholderResolver.combining(context.placeholderResolver(), this.placeholderResolver); - final Appendable debug = context.debugOutput(); + final Consumer debug = context.debugOutput(); if (debug != null) { - try { - debug.append("Beginning parsing message ").append(richMessage).append('\n'); - } catch (final IOException ignored) { - } + debug.accept("Beginning parsing message "); + debug.accept(richMessage); + debug.accept("\n"); } final Function transformationFactory; if (debug != null) { transformationFactory = node -> { try { - try { - debug.append("Attempting to match node '").append(node.name()).append("' at column ") - .append(String.valueOf(node.token().startIndex())).append('\n'); - } catch (final IOException ignored) { - } + debug.accept("Attempting to match node '"); + debug.accept(node.name()); + debug.accept("' at column "); + debug.accept(String.valueOf(node.token().startIndex())); + debug.accept("\n"); final Transformation transformation = this.registry.get(this.sanitizePlaceholderName(node.name()), node.parts(), combinedResolver, context); - try { - if (transformation == null) { - debug.append("Could not match node '").append(node.name()).append("'\n"); - } else { - debug.append("Successfully matched node '").append(node.name()).append("' to transformation ") - .append(transformation.examinableName()).append('\n'); - } - } catch (final IOException ignored) { + if (transformation == null) { + debug.accept("Could not match node '"); + debug.accept(node.name()); + debug.accept("'\n"); + } else { + debug.accept("Successfully matched node '"); + debug.accept(node.name()); + debug.accept("' to transformation "); + debug.accept(transformation.examinableName()); + debug.accept("\n"); } return transformation; } catch (final ParsingException e) { - try { - if (e.tokens().length == 0) { - e.tokens(new Token[]{node.token()}); - } - debug.append("Could not match node '").append(node.name()).append("' - ").append(e.getMessage()).append('\n'); - } catch (final IOException ignored) { + if (e.tokens().length == 0) { + e.tokens(new Token[]{node.token()}); } + debug.accept("Could not match node '"); + debug.accept(node.name()); + debug.accept("' - "); + debug.accept(e.getMessage()); + debug.accept("\n"); return null; } }; @@ -179,11 +181,8 @@ private void processTokens(final @NotNull StringBuilder sb, final @NotNull Strin final ElementNode root = TokenParser.parse(transformationFactory, tagNameChecker, combinedResolver, richMessage, context.strict()); if (debug != null) { - try { - debug.append("Text parsed into element tree:\n"); - debug.append(root.toString()); - } catch (final IOException ignored) { - } + debug.accept("Text parsed into element tree:\n"); + debug.accept(root.toString()); } return Objects.requireNonNull(context.postProcessor().apply(this.treeToComponent(root, context)), "Post-processor must not return null"); @@ -225,12 +224,13 @@ private void processTokens(final @NotNull StringBuilder sb, final @NotNull Strin comp = this.handleModifying((Modifying) transformation, comp, 0); } - final Appendable debug = context.debugOutput(); + final Consumer debug = context.debugOutput(); if (debug != null) { - try { - debug.append("==========\ntreeToComponent \n").append(node.toString()).append("\n").append(comp.examine(MultiLineStringExaminer.simpleEscaping()).collect(Collectors.joining("\n"))).append("\n==========\n"); - } catch (final IOException ignored) { - } + debug.accept("==========\ntreeToComponent \n"); + debug.accept(node.toString()); + debug.accept("\n"); + debug.accept(comp.examine(MultiLineStringExaminer.simpleEscaping()).collect(Collectors.joining("\n"))); + debug.accept("\n==========\n"); } return comp; 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 5ea338b4b..17b6693f7 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 @@ -366,7 +366,7 @@ void debugModeSimple() { final String input = " RED "; final StringBuilder sb = new StringBuilder(); - MiniMessage.builder().debug(sb).build().deserialize(input); + MiniMessage.builder().debug(sb::append).build().deserialize(input); final List messages = Arrays.asList(sb.toString().split("\n")); assertTrue(messages.contains("Beginning parsing message RED ")); @@ -385,7 +385,7 @@ void debugModeMoreComplex() { final String input = " RED BLUE bad click "; final StringBuilder sb = new StringBuilder(); - MiniMessage.builder().debug(sb).build().deserialize(input); + MiniMessage.builder().debug(sb::append).build().deserialize(input); final List messages = Arrays.asList(sb.toString().split("\n")); assertTrue(messages.contains("Beginning parsing message RED BLUE bad click ")); @@ -413,7 +413,7 @@ void debugModeMoreComplexNoError() { final String input = " RED BLUE good click "; final StringBuilder sb = new StringBuilder(); - MiniMessage.builder().debug(sb).build().deserialize(input); + MiniMessage.builder().debug(sb::append).build().deserialize(input); final List messages = Arrays.asList(sb.toString().split("\n")); assertTrue(messages.contains("Beginning parsing message RED BLUE good click ")); diff --git a/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/TestBase.java b/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/TestBase.java index 3b0762538..22a0e4b08 100644 --- a/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/TestBase.java +++ b/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/TestBase.java @@ -34,7 +34,7 @@ public class TestBase { - final MiniMessage PARSER = MiniMessage.builder().debug(System.out).build(); + final MiniMessage PARSER = MiniMessage.builder().debug(System.out::print).build(); void assertParsedEquals(final @NotNull Component expected, final @NotNull String input) { this.assertParsedEquals(this.PARSER, expected, input);