Skip to content

Commit

Permalink
Add semi-closing tags to QuickText, add DynamicTextNode
Browse files Browse the repository at this point in the history
  • Loading branch information
Patbox committed Jan 27, 2024
1 parent ec2a4fa commit cbefd98
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 45 deletions.
5 changes: 5 additions & 0 deletions src/main/java/eu/pb4/placeholders/api/TextParserUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
import eu.pb4.placeholders.api.parsers.TextParserV1;
import net.minecraft.text.Text;


/**
* You should use {@link eu.pb4.placeholders.api.parsers.ParserBuilder} for stacked parsing
* or {@link eu.pb4.placeholders.api.parsers.TagParser} for only tags to text.
*/
@Deprecated
public final class TextParserUtils {
private TextParserUtils() {}
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/eu/pb4/placeholders/api/node/DynamicTextNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package eu.pb4.placeholders.api.node;

import eu.pb4.placeholders.api.ParserContext;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import org.jetbrains.annotations.Nullable;

import java.util.function.Function;

public record DynamicTextNode(String id, ParserContext.Key<Function<String, Text>> key) implements TextNode {
public static DynamicTextNode of(String id, ParserContext.Key<Function<String, Text>> key) {
return new DynamicTextNode(id, key);
}

public static ParserContext.Key<Function<String, @Nullable Text>> key(String id) {
return new ParserContext.Key<>("dynamic:" + id, null);
}

@Override
public Text toText(ParserContext context, boolean removeBackslashes) {
var x = context.get(key);
if (x != null) {
return x.apply(id);
}
return Text.literal("[MISSING CONTEXT FOR " + this.key.key() + "]").formatted(Formatting.ITALIC).withColor(0xFF0000);
}

@Override
public boolean isDynamic() {
return true;
}
}
86 changes: 71 additions & 15 deletions src/main/java/eu/pb4/placeholders/api/parsers/ParserBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
import eu.pb4.placeholders.api.parsers.tag.TagRegistry;
import eu.pb4.placeholders.impl.textparser.MultiTagLikeParser;
import eu.pb4.placeholders.impl.textparser.SingleTagLikeParser;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;

import java.util.*;
import java.util.function.Function;

/**
* Allows you to create stacked parser in most "correct" and compatible way.
*/
public class ParserBuilder {
private final Map<TagLikeParser.Format, TagLikeParser.Provider> tagLike = new HashMap<>();
private final List<NodeParser> parserList = new ArrayList<>();
Expand All @@ -21,74 +25,126 @@ public class ParserBuilder {
private boolean safeOnly;
private TagRegistry customTagRegistry;

public static ParserBuilder of() {
return new ParserBuilder();
}

/**
* Enables parsing of Global Placeholders (aka {@link Placeholders})
*/
public ParserBuilder globalPlaceholders() {
return add(Placeholders.DEFAULT_PLACEHOLDER_PARSER);
}

/**
* Enables parsing of Global Placeholders, but with a custom format
*/
public ParserBuilder globalPlaceholders(TagLikeParser.Format format) {
return customTags(format, TagLikeParser.Provider.placeholder(PlaceholderContext.KEY, Placeholders.DEFAULT_PLACEHOLDER_GETTER));
}

/**
* Enables parsing of Global Placeholder, but with a custom format and context source
*/
public ParserBuilder globalPlaceholders(TagLikeParser.Format format, ParserContext.Key<PlaceholderContext> contextKey) {
return customTags(format, TagLikeParser.Provider.placeholder(contextKey, Placeholders.DEFAULT_PLACEHOLDER_GETTER));
}

/**
* Enables parsing of custom placeholder with a custom format and context source
*/
public ParserBuilder placeholders(TagLikeParser.Format format, ParserContext.Key<PlaceholderContext> contextKey, Placeholders.PlaceholderGetter getter) {
return customTags(format, TagLikeParser.Provider.placeholder(contextKey, getter));
}

/**
* Enables parsing of custom placeholder with a functional provider
*/
public ParserBuilder placeholders(TagLikeParser.Format format, Function<String, TextNode> function) {
return customTags(format, TagLikeParser.Provider.direct(function));
return customTags(format, TagLikeParser.Provider.placeholder(function));
}

/**
* Enables parsing of custom, context dependent placeholders
*/
public ParserBuilder placeholders(TagLikeParser.Format format, ParserContext.Key<Function<String, Text>> key) {
return customTags(format, TagLikeParser.Provider.placeholder(key));
}

/**
* Enables parsing of custom, context dependent placeholders
*/
public ParserBuilder placeholders(TagLikeParser.Format format, Set<String> tags, ParserContext.Key<Function<String, Text>> key) {
return customTags(format, TagLikeParser.Provider.placeholder(tags, key));
}

/**
* Enables QuickText format.
*/
public ParserBuilder quickText() {
this.quickText = true;
return this;
}

/**
* Enables Simplified Text Format.
*/
public ParserBuilder simplifiedTextFormat() {
this.simplifiedTextFormat = true;
return this;
}

/**
* Forces usage of safe tags for tag parsers.
*/
public ParserBuilder requireSafe() {
this.safeOnly = true;
return this;
}

/**
* Forces usage of custom registry for tag parsers.
*/
public ParserBuilder customTagRegistry(TagRegistry registry) {
this.customTagRegistry = registry;
return this;
}

/**
* Enables Markdown.
*/
public ParserBuilder markdown() {
return add(MarkdownLiteParserV1.ALL);
}

/**
* Enables Markdown with limited formatting.
*/
public ParserBuilder markdown(MarkdownLiteParserV1.MarkdownFormat... formats) {
return add(new MarkdownLiteParserV1(formats));
}

/**
* Enables legacy color tags (&X) with rgb extension.
*/
public ParserBuilder legacyColor() {
return add(LegacyFormattingParser.COLORS);
}

/**
* Enables legacy color tags (&X).
*/
public ParserBuilder legacyVanillaColor() {
return add(LegacyFormattingParser.BASE_COLORS);
}

/**
* Enables all legacy formatting (&X) with rgb extension.
*/
public ParserBuilder legacyAll() {
return add(LegacyFormattingParser.ALL);
}

/**
* Enables all legacy formatting.
*/
public ParserBuilder legacy(boolean allowRGB, Formatting... formatting) {
this.hasLegacy = true;
this.legacyRGB = allowRGB;
this.legacyFormatting.addAll(List.of(formatting));

return this;
}

/**
* Adds custom tag like parser
*/
public ParserBuilder customTags(TagLikeParser.Format format, TagLikeParser.Provider provider) {
this.tagLike.put(format, provider);
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
import java.util.regex.Pattern;


/**
* Replaced with {@link TagLikeParser}
*/
@Deprecated
public record PatternPlaceholderParser(Pattern pattern, Function<String, @Nullable TextNode> placeholderProvider) implements NodeParser {
public static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("(?<!((?<!(\\\\))\\\\))[%](?<id>[^%]+:[^%]+)[%]");
Expand Down
90 changes: 78 additions & 12 deletions src/main/java/eu/pb4/placeholders/api/parsers/TagLikeParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import eu.pb4.placeholders.api.ParserContext;
import eu.pb4.placeholders.api.PlaceholderContext;
import eu.pb4.placeholders.api.Placeholders;
import eu.pb4.placeholders.api.node.LiteralNode;
import eu.pb4.placeholders.api.node.TextNode;
import eu.pb4.placeholders.api.node.TranslatedNode;
import eu.pb4.placeholders.api.node.*;
import eu.pb4.placeholders.api.node.parent.ParentNode;
import eu.pb4.placeholders.api.node.parent.ParentTextNode;
import eu.pb4.placeholders.api.parsers.format.MultiCharacterFormat;
Expand All @@ -14,14 +12,12 @@
import eu.pb4.placeholders.impl.textparser.MultiTagLikeParser;
import eu.pb4.placeholders.impl.textparser.SingleTagLikeParser;
import eu.pb4.placeholders.impl.textparser.providers.LenientFormat;
import net.minecraft.text.Text;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
Expand All @@ -41,8 +37,20 @@ public static TagLikeParser placeholder(Format format, ParserContext.Key<Placeho
return new SingleTagLikeParser(format, Provider.placeholder(contextKey, placeholders));
}

public static TagLikeParser direct(Format format, Function<String, @Nullable TextNode> placeholders) {
return new SingleTagLikeParser(format, Provider.direct(placeholders));
public static TagLikeParser placeholder(Format format, Function<String, @Nullable TextNode> placeholders) {
return new SingleTagLikeParser(format, Provider.placeholder(placeholders));
}

public static TagLikeParser placeholderText(Format format, Function<String, @Nullable Text> placeholders) {
return new SingleTagLikeParser(format, Provider.placeholderText(placeholders));
}

public static TagLikeParser placeholderText(Format format, ParserContext.Key<Function<String, @Nullable Text>> key) {
return new SingleTagLikeParser(format, Provider.placeholder(key));
}

public static TagLikeParser placeholderText(Format format, Set<String> validIds, ParserContext.Key<Function<String, @Nullable Text>> key) {
return new SingleTagLikeParser(format, Provider.placeholder(validIds, key));
}

public static TagLikeParser of(Format format, Provider provider) {
Expand Down Expand Up @@ -126,7 +134,14 @@ public void handleTag(String id, String argument, Context context) {
};
}

static Provider direct(Function<String, @Nullable TextNode> function) {
static Provider placeholderText(Function<String, @Nullable Text> function) {
return placeholder(x -> {
var y = function.apply(x);
return y != null ? new DirectTextNode(y) : null;
});
}

static Provider placeholder(Function<String, @Nullable TextNode> function) {
return new Provider() {
@Override
public boolean isValidTag(String tag, Context context) {
Expand All @@ -143,6 +158,33 @@ public void handleTag(String id, String argument, Context context) {
};
}

static Provider placeholder(Set<String> validTags, ParserContext.Key<Function<String, Text>> key) {
return new Provider() {
@Override
public boolean isValidTag(String tag, Context context) {
return validTags.contains(tag);
}

@Override
public void handleTag(String id, String argument, Context context) {
context.addNode(new DynamicTextNode(id, key));
}
};
}
static Provider placeholder(ParserContext.Key<Function<String, Text>> key) {
return new Provider() {
@Override
public boolean isValidTag(String tag, Context context) {
return true;
}

@Override
public void handleTag(String id, String argument, Context context) {
context.addNode(new DynamicTextNode(id, key));
}
};
}

boolean isValidTag(String tag, Context context);

void handleTag(String id, String argument, Context context);
Expand Down Expand Up @@ -201,12 +243,33 @@ public void pop(String id) {
while (this.stack.size() > 1) {
var x = this.stack.pop();
this.stack.peek().nodes.add(x.collapse(this.parser));
if (x.id.equals(id)) {
if (id.equals(x.id)) {
return;
}
}
}

public void popOnly(String id) {
if (!contains(id)) {
return;
}

var list = new Stack<Scope>();

while (this.stack.size() > 1) {
var x = this.stack.pop();
this.stack.peek().nodes.add(x.collapse(this.parser));
if (id.equals(x.id)) {
while (!list.isEmpty()) {
this.stack.push(list.pop());
}
return;
} else {
list.add(new Scope(x.id, new ArrayList<>(), x.merger));
}
}
}

public void pop(Predicate<String> stopPredicate) {
while (this.stack.size() > 1) {
if (stopPredicate.test(this.stack.peek().id)) {
Expand All @@ -226,7 +289,6 @@ public void popInclusive(Predicate<String> stopPredicate) {
}
}
}

@Nullable
public String peekId() {
return this.stack.peek().id;
Expand Down Expand Up @@ -316,6 +378,10 @@ public interface Format {

@Nullable Tag findAt(String string, int start, Provider provider, Context context);

default int index() {
return 0;
}

record Tag(int start, int end, String id, String argument, @Nullable Object extra) {
public Tag(int start, int end, String id, String argument) {
this(start, end, id, argument, null);
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/eu/pb4/placeholders/api/parsers/TagParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@
import java.util.function.Function;

/**
* Parser implementing QuickText and Simplified Text Format.
* Parser implementing QuickText and Simplified Text Format (Legacy).
* Lenient parser can support both at the same time.
* <a href="https://placeholders.pb4.eu/user/text-format/">Format documentation</a>
*
* To create pure Quick Text parser, you use methods without Legacy or Lenient in the name.
* Lenient methods/parser allow for usage of both Quick Text and Simplified Text Format at the same
* time, allowing for better transition between the formats.
* Legacy parser refers to Simplified Text Format, which while discouraged, it's still supported.
*
*/
public final class TagParser implements NodeParser, TagLikeWrapper {
private final TagRegistry registry;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,5 @@ default TagLikeParser.Format.Tag findAt(String string, int start, TagLikeParser.

int endLength();

int minLength();

boolean hasArgument();
}
Loading

0 comments on commit cbefd98

Please sign in to comment.