Skip to content

Commit

Permalink
Merge pull request #749 from bluelhf/main/4
Browse files Browse the repository at this point in the history
Implement MiniMessage preprocessor and cleanup parsing
  • Loading branch information
zml2008 authored Jun 1, 2022
2 parents 0f40237 + a88f32b commit 96afa05
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class ContextImpl implements Context {
private String message;
private final MiniMessage miniMessage;
private final TagResolver tagResolver;
private final UnaryOperator<String> preProcessor;
private final UnaryOperator<Component> postProcessor;

ContextImpl(
Expand All @@ -60,13 +61,15 @@ class ContextImpl implements Context {
final String message,
final MiniMessage miniMessage,
final @NotNull TagResolver extraTags,
final UnaryOperator<String> preProcessor,
final UnaryOperator<Component> postProcessor
) {
this.strict = strict;
this.debugOutput = debugOutput;
this.message = message;
this.miniMessage = miniMessage;
this.tagResolver = extraTags;
this.preProcessor = preProcessor == null ? UnaryOperator.identity() : preProcessor;
this.postProcessor = postProcessor == null ? UnaryOperator.identity() : postProcessor;
}

Expand All @@ -76,9 +79,10 @@ static ContextImpl of(
final String input,
final MiniMessageImpl miniMessage,
final TagResolver extraTags,
final UnaryOperator<String> preProcessor,
final UnaryOperator<Component> postProcessor
) {
return new ContextImpl(strict, debugOutput, input, miniMessage, extraTags, postProcessor);
return new ContextImpl(strict, debugOutput, input, miniMessage, extraTags, preProcessor, postProcessor);
}

public boolean strict() {
Expand All @@ -105,6 +109,10 @@ public UnaryOperator<Component> postProcessor() {
return this.postProcessor;
}

public UnaryOperator<String> preProcessor() {
return this.preProcessor;
}

@Override
public @NotNull Component deserialize(final @NotNull String message) {
return this.miniMessage.deserialize(requireNonNull(message, "message"), this.tagResolver);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,16 @@ interface Builder extends AbstractBuilder<MiniMessage> {
*/
@NotNull Builder postProcessor(final @NotNull UnaryOperator<Component> postProcessor);

/**
* Specify a function that takes the string at the start of the parser process.
* <p>By default, this does absolutely nothing.</p>
*
* @param preProcessor method run at the start of parsing
* @return this builder
* @since 4.11.0
*/
@NotNull Builder preProcessor(final @NotNull UnaryOperator<String> preProcessor);

/**
* Builds the serializer.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,41 +54,44 @@ final class MiniMessageImpl implements MiniMessage {
static final class Instances {
static final MiniMessage INSTANCE = SERVICE
.map(Provider::miniMessage)
.orElseGet(() -> new MiniMessageImpl(TagResolver.standard(), false, null, DEFAULT_COMPACTING_METHOD));
.orElseGet(() -> new MiniMessageImpl(TagResolver.standard(), false, null, DEFAULT_NO_OP, DEFAULT_COMPACTING_METHOD));
}

static final UnaryOperator<String> DEFAULT_NO_OP = UnaryOperator.identity();
static final UnaryOperator<Component> DEFAULT_COMPACTING_METHOD = Component::compact;

private final boolean strict;
private final @Nullable Consumer<String> debugOutput;
private final UnaryOperator<Component> postProcessor;
private final UnaryOperator<String> preProcessor;
final MiniMessageParser parser;

MiniMessageImpl(final @NotNull TagResolver resolver, final boolean strict, final @Nullable Consumer<String> debugOutput, final @NotNull UnaryOperator<Component> postProcessor) {
MiniMessageImpl(final @NotNull TagResolver resolver, final boolean strict, final @Nullable Consumer<String> debugOutput, final @NotNull UnaryOperator<String> preProcessor, final @NotNull UnaryOperator<Component> postProcessor) {
this.parser = new MiniMessageParser(resolver);
this.strict = strict;
this.debugOutput = debugOutput;
this.preProcessor = preProcessor;
this.postProcessor = postProcessor;
}

@Override
public @NotNull Component deserialize(final @NotNull String input) {
return this.parser.parseFormat(input, this.newContext(input, null));
return this.parser.parseFormat(this.newContext(input, null));
}

@Override
public @NotNull Component deserialize(final @NotNull String input, final @NotNull TagResolver tagResolver) {
return this.parser.parseFormat(input, this.newContext(input, requireNonNull(tagResolver, "tagResolver")));
return this.parser.parseFormat(this.newContext(input, requireNonNull(tagResolver, "tagResolver")));
}

@Override
public Node.@NotNull Root deserializeToTree(final @NotNull String input) {
return this.parser.parseToTree(input, this.newContext(input, null));
return this.parser.parseToTree(this.newContext(input, null));
}

@Override
public Node.@NotNull Root deserializeToTree(final @NotNull String input, final @NotNull TagResolver tagResolver) {
return this.parser.parseToTree(input, this.newContext(input, requireNonNull(tagResolver, "tagResolver")));
return this.parser.parseToTree(this.newContext(input, requireNonNull(tagResolver, "tagResolver")));
}

@Override
Expand All @@ -113,30 +116,30 @@ private SerializableResolver serialResolver(final @Nullable TagResolver extraRes

@Override
public @NotNull String escapeTags(final @NotNull String input) {
return this.parser.escapeTokens(input, this.newContext(input, null));
return this.parser.escapeTokens(this.newContext(input, null));
}

@Override
public @NotNull String escapeTags(final @NotNull String input, final @NotNull TagResolver tagResolver) {
return this.parser.escapeTokens(input, this.newContext(input, tagResolver));
return this.parser.escapeTokens(this.newContext(input, tagResolver));
}

@Override
public @NotNull String stripTags(final @NotNull String input) {
return this.parser.stripTokens(input, this.newContext(input, null));
return this.parser.stripTokens(this.newContext(input, null));
}

@Override
public @NotNull String stripTags(final @NotNull String input, final @NotNull TagResolver tagResolver) {
return this.parser.stripTokens(input, this.newContext(input, tagResolver));
return this.parser.stripTokens(this.newContext(input, tagResolver));
}

private @NotNull ContextImpl newContext(final @NotNull String input, final @Nullable TagResolver resolver) {
requireNonNull(input, "input");
if (resolver == null) {
return ContextImpl.of(this.strict, this.debugOutput, input, this, TagResolver.empty(), this.postProcessor);
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.postProcessor);
return ContextImpl.of(this.strict, this.debugOutput, input, this, resolver, this.preProcessor, this.postProcessor);
}
}

Expand All @@ -145,6 +148,7 @@ static final class BuilderImpl implements Builder {
private boolean strict = false;
private Consumer<String> debug = null;
private UnaryOperator<Component> postProcessor = DEFAULT_COMPACTING_METHOD;
private UnaryOperator<String> preProcessor = DEFAULT_NO_OP;

BuilderImpl() {
BUILDER.accept(this);
Expand All @@ -156,6 +160,7 @@ static final class BuilderImpl implements Builder {
this.strict = serializer.strict;
this.debug = serializer.debugOutput;
this.postProcessor = serializer.postProcessor;
this.preProcessor = serializer.preProcessor;
}

@Override
Expand Down Expand Up @@ -191,9 +196,15 @@ static final class BuilderImpl implements Builder {
return this;
}

@Override
public @NotNull Builder preProcessor(final @NotNull UnaryOperator<String> preProcessor) {
this.preProcessor = Objects.requireNonNull(preProcessor, "preProcessor");
return this;
}

@Override
public @NotNull MiniMessage build() {
return new MiniMessageImpl(this.tagResolver, this.strict, this.debug, this.postProcessor);
return new MiniMessageImpl(this.tagResolver, this.strict, this.debug, this.preProcessor, this.postProcessor);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,17 @@ final class MiniMessageParser {
this.tagResolver = tagResolver;
}

@NotNull String escapeTokens(final @NotNull String richMessage, final @NotNull ContextImpl context) {
final StringBuilder sb = new StringBuilder(richMessage.length());
this.escapeTokens(sb, richMessage, context);
@NotNull String escapeTokens(final @NotNull ContextImpl context) {
final StringBuilder sb = new StringBuilder(context.message().length());
this.escapeTokens(sb, context);
return sb.toString();
}

void escapeTokens(final StringBuilder sb, final @NotNull String richMessage, final @NotNull ContextImpl context) {
void escapeTokens(final StringBuilder sb, final @NotNull ContextImpl context) {
this.escapeTokens(sb, context.message(), context);
}

private void escapeTokens(final StringBuilder sb, final String richMessage, final ContextImpl context) {
this.processTokens(sb, richMessage, context, (token, builder) -> {
builder.append('\\').append(TokenParser.TAG_START);
if (token.type() == TokenType.CLOSE_TAG) {
Expand All @@ -82,12 +86,16 @@ void escapeTokens(final StringBuilder sb, final @NotNull String richMessage, fin
});
}

@NotNull String stripTokens(final @NotNull String richMessage, final @NotNull ContextImpl context) {
final StringBuilder sb = new StringBuilder(richMessage.length());
this.processTokens(sb, richMessage, context, (token, builder) -> {});
@NotNull String stripTokens(final @NotNull ContextImpl context) {
final StringBuilder sb = new StringBuilder(context.message().length());
this.processTokens(sb, context, (token, builder) -> {});
return sb.toString();
}

private void processTokens(final @NotNull StringBuilder sb, final @NotNull ContextImpl context, final BiConsumer<Token, StringBuilder> tagHandler) {
this.processTokens(sb, context.message(), context, tagHandler);
}

private void processTokens(final @NotNull StringBuilder sb, final @NotNull String richMessage, final @NotNull ContextImpl context, final BiConsumer<Token, StringBuilder> tagHandler) {
final TagResolver combinedResolver = TagResolver.resolver(this.tagResolver, context.extraTags());
final List<Token> root = TokenParser.tokenize(richMessage);
Expand Down Expand Up @@ -117,12 +125,13 @@ private void processTokens(final @NotNull StringBuilder sb, final @NotNull Strin
}
}

@NotNull RootNode parseToTree(final @NotNull String richMessage, final @NotNull ContextImpl context) {
@NotNull RootNode parseToTree(final @NotNull ContextImpl context) {
final TagResolver combinedResolver = TagResolver.resolver(this.tagResolver, context.extraTags());
final String processedMessage = context.preProcessor().apply(context.message());
final Consumer<String> debug = context.debugOutput();
if (debug != null) {
debug.accept("Beginning parsing message ");
debug.accept(richMessage);
debug.accept(processedMessage);
debug.accept("\n");
}

Expand Down Expand Up @@ -183,10 +192,10 @@ private void processTokens(final @NotNull StringBuilder sb, final @NotNull Strin
return combinedResolver.has(sanitized);
};

final String preProcessed = TokenParser.resolvePreProcessTags(richMessage, transformationFactory);
final String preProcessed = TokenParser.resolvePreProcessTags(processedMessage, transformationFactory);
context.message(preProcessed);
// Then, once MiniMessage placeholders have been inserted, we can do the real parse
final RootNode root = TokenParser.parse(transformationFactory, tagNameChecker, preProcessed, richMessage, context.strict());
final RootNode root = TokenParser.parse(transformationFactory, tagNameChecker, preProcessed, processedMessage, context.strict());

if (debug != null) {
debug.accept("Text parsed into element tree:\n");
Expand All @@ -196,8 +205,8 @@ private void processTokens(final @NotNull StringBuilder sb, final @NotNull Strin
return root;
}

@NotNull Component parseFormat(final @NotNull String richMessage, final @NotNull ContextImpl context) {
final ElementNode root = this.parseToTree(richMessage, context);
@NotNull Component parseFormat(final @NotNull ContextImpl context) {
final ElementNode root = this.parseToTree(context);
return Objects.requireNonNull(context.postProcessor().apply(this.treeToComponent(root, context)), "Post-processor must not return null");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package net.kyori.adventure.text.minimessage;

import java.util.Collections;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
Expand Down Expand Up @@ -68,7 +69,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(), Component::compact);
return ContextImpl.of(false, null, originalMessage, (MiniMessageImpl) PARSER, TagResolver.empty(), UnaryOperator.identity(), Component::compact);
}

public static ArgumentQueue emptyArgumentQueue(final Context context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ void testPlaceholderComponentMixed() {
this.assertParsedEquals(miniMessage, expected, input, t1, t2);
}

@Test
void testPreprocessing() {
final Component expected = MiniMessage.miniMessage().deserialize("<red>Hello, world!</red>");

final String input = "Hello";
final MiniMessage miniMessage = MiniMessage.builder().preProcessor(str -> "<red>" + str + ", world!</red>").build();
this.assertParsedEquals(miniMessage, expected, input);
}

// GH-103
@Test
void testPlaceholderInHover() {
Expand Down

0 comments on commit 96afa05

Please sign in to comment.