New approach for chat processing
Created different providers for regex, range and string matching Handling one match at a time per provider TODO: Formatters should be executed one by one in declaration order Add enitre message by default Loop until all of the providers are finished Ignore any areas returned by the providers #71
This commit is contained in:
parent
b452170ff7
commit
0a4cdd01ce
9 changed files with 214 additions and 106 deletions
|
@ -49,7 +49,6 @@ public class ChatProcessing {
|
||||||
private static final Pattern CONSOLE_PING_PATTERN = Pattern.compile("(?i)" + Pattern.quote("@console"));
|
private static final Pattern CONSOLE_PING_PATTERN = Pattern.compile("(?i)" + Pattern.quote("@console"));
|
||||||
private static final Pattern HASHTAG_PATTERN = Pattern.compile("#(\\w+)");
|
private static final Pattern HASHTAG_PATTERN = Pattern.compile("#(\\w+)");
|
||||||
private static final Pattern URL_PATTERN = Pattern.compile("(http[\\w:/?=$\\-_.+!*'(),&]+(?:#[\\w]+)?)");
|
private static final Pattern URL_PATTERN = Pattern.compile("(http[\\w:/?=$\\-_.+!*'(),&]+(?:#[\\w]+)?)");
|
||||||
public static final Pattern ENTIRE_MESSAGE_PATTERN = Pattern.compile(".+");
|
|
||||||
private static final Pattern UNDERLINED_PATTERN = Pattern.compile("__");
|
private static final Pattern UNDERLINED_PATTERN = Pattern.compile("__");
|
||||||
private static final Pattern ITALIC_PATTERN = Pattern.compile("\\*");
|
private static final Pattern ITALIC_PATTERN = Pattern.compile("\\*");
|
||||||
private static final Pattern ITALIC_PATTERN_2 = Pattern.compile("_");
|
private static final Pattern ITALIC_PATTERN_2 = Pattern.compile("_");
|
||||||
|
@ -64,7 +63,10 @@ public class ChatProcessing {
|
||||||
private static final Pattern WORD_PATTERN = Pattern.compile("\\S+");
|
private static final Pattern WORD_PATTERN = Pattern.compile("\\S+");
|
||||||
private static boolean pingedconsole = false;
|
private static boolean pingedconsole = false;
|
||||||
|
|
||||||
public static final ChatFormatter ESCAPE_FORMATTER = ChatFormatter.builder("escape", ESCAPE_PATTERN).build();
|
/**
|
||||||
|
* A special range formatter that removes the effect of the next formatter
|
||||||
|
*/
|
||||||
|
public static final ChatFormatter ESCAPE_FORMATTER = ChatFormatter.builder("escape", ESCAPE_PATTERN).type(ChatFormatter.Type.Range).build();
|
||||||
|
|
||||||
private static ArrayList<ChatFormatter> commonFormatters = Lists.newArrayList(
|
private static ArrayList<ChatFormatter> commonFormatters = Lists.newArrayList(
|
||||||
ChatFormatter.builder("bold", BOLD_PATTERN).bold(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range)
|
ChatFormatter.builder("bold", BOLD_PATTERN).bold(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range)
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package buttondevteam.chat.components.formatter.formatting;
|
||||||
|
|
||||||
|
import buttondevteam.chat.commands.ucmds.admin.DebugCommand;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public final class ChatFormatUtils {
|
||||||
|
private ChatFormatUtils() {}
|
||||||
|
|
||||||
|
static void sendMessageWithPointer(String str, int... pointer) {
|
||||||
|
DebugCommand.SendDebugMessage(str);
|
||||||
|
StringBuilder sb = new StringBuilder(str.length());
|
||||||
|
Arrays.sort(pointer);
|
||||||
|
for (int i = 0; i < pointer.length; i++) {
|
||||||
|
for (int j = 0; j < pointer[i] - (i > 0 ? pointer[i - 1] + 1 : 0); j++)
|
||||||
|
sb.append(' ');
|
||||||
|
if (pointer[i] == (i > 0 ? pointer[i - 1] : -1))
|
||||||
|
continue;
|
||||||
|
sb.append('^');
|
||||||
|
}
|
||||||
|
DebugCommand.SendDebugMessage(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given start and end position is inside any of the ranges
|
||||||
|
*/
|
||||||
|
static boolean isInRange(int start, int end, ArrayList<int[]> ranges) {
|
||||||
|
return ranges.stream().anyMatch(range -> range[1] >= start && range[0] <= end - 1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,14 +5,12 @@ import buttondevteam.chat.components.formatter.ChatProcessing;
|
||||||
import buttondevteam.lib.architecture.ConfigData;
|
import buttondevteam.lib.architecture.ConfigData;
|
||||||
import buttondevteam.lib.architecture.IHaveConfig;
|
import buttondevteam.lib.architecture.IHaveConfig;
|
||||||
import buttondevteam.lib.chat.Color;
|
import buttondevteam.lib.chat.Color;
|
||||||
import buttondevteam.lib.chat.Priority;
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -28,16 +26,6 @@ import java.util.stream.Collectors;
|
||||||
@Builder
|
@Builder
|
||||||
public final class ChatFormatter {
|
public final class ChatFormatter {
|
||||||
Pattern regex;
|
Pattern regex;
|
||||||
boolean italic;
|
|
||||||
boolean bold;
|
|
||||||
boolean underlined;
|
|
||||||
boolean strikethrough;
|
|
||||||
boolean obfuscated;
|
|
||||||
Color color;
|
|
||||||
TriFunc<String, ChatFormatter, FormattedSection, String> onmatch;
|
|
||||||
String openlink;
|
|
||||||
@Builder.Default
|
|
||||||
Priority priority = Priority.Normal;
|
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
short removeCharCount = 0;
|
short removeCharCount = 0;
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
|
@ -64,18 +52,6 @@ public final class ChatFormatter {
|
||||||
return config.getData(name + ".enabled", true);
|
return config.getData(name + ".enabled", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Type {
|
|
||||||
Normal,
|
|
||||||
/**
|
|
||||||
* Matches a start and an end section which gets converted to one section (for example see italics)
|
|
||||||
*/
|
|
||||||
Range,
|
|
||||||
/**
|
|
||||||
* Exclude matching area from further processing (besides this formatter)
|
|
||||||
*/
|
|
||||||
Excluder
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface TriFunc<T1, T2, T3, R> {
|
public interface TriFunc<T1, T2, T3, R> {
|
||||||
R apply(T1 x1, T2 x2, T3 x3);
|
R apply(T1 x1, T2 x2, T3 x3);
|
||||||
|
@ -101,8 +77,8 @@ public final class ChatFormatter {
|
||||||
*/
|
*/
|
||||||
val remchars = new ArrayList<int[]>();
|
val remchars = new ArrayList<int[]>();
|
||||||
|
|
||||||
header("Range section conversion");
|
header("Range section creation");
|
||||||
sections = convertRangeSections(str, sections, remchars);
|
sections = createRangeSections(str, sections, formatters, remchars);
|
||||||
|
|
||||||
header("Adding remove chars (RC)"); // Important to add after the range section conversion
|
header("Adding remove chars (RC)"); // Important to add after the range section conversion
|
||||||
addRemChars(sections, remchars, str);
|
addRemChars(sections, remchars, str);
|
||||||
|
@ -117,28 +93,6 @@ public final class ChatFormatter {
|
||||||
|
|
||||||
private static void createSections(List<ChatFormatter> formatters, String str, ArrayList<FormattedSection> sections,
|
private static void createSections(List<ChatFormatter> formatters, String str, ArrayList<FormattedSection> sections,
|
||||||
boolean excluders) {
|
boolean excluders) {
|
||||||
for (ChatFormatter formatter : formatters) {
|
|
||||||
if (excluders == (formatter.type != Type.Excluder))
|
|
||||||
continue; //If we're looking at excluders and this isn't one, skip - or vica-versa
|
|
||||||
Matcher matcher = formatter.regex.matcher(str);
|
|
||||||
while (matcher.find()) {
|
|
||||||
DebugCommand.SendDebugMessage("Found match from " + matcher.start() + " to " + (matcher.end() - 1));
|
|
||||||
DebugCommand.SendDebugMessage("With " + (excluders ? "excluder " : "") + "formatter: " + formatter);
|
|
||||||
sendMessageWithPointer(str, matcher.start(), matcher.end() - 1);
|
|
||||||
if (formatter.regex != ChatProcessing.ENTIRE_MESSAGE_PATTERN && sections.stream().anyMatch(fs -> fs.type == Type.Excluder && (fs.End >= matcher.start() && fs.Start <= matcher.end() - 1))) {
|
|
||||||
DebugCommand.SendDebugMessage("Ignoring formatter because of an excluder");
|
|
||||||
continue; //Exclude areas matched by excluders - Range sections are correctly handled afterwards
|
|
||||||
}
|
|
||||||
ArrayList<String> groups = new ArrayList<>();
|
|
||||||
for (int i = 0; i < matcher.groupCount(); i++)
|
|
||||||
groups.add(matcher.group(i + 1));
|
|
||||||
if (groups.size() > 0)
|
|
||||||
DebugCommand.SendDebugMessage("First group: " + groups.get(0));
|
|
||||||
FormattedSection section = new FormattedSection(formatter, matcher.start(), matcher.end() - 1, groups,
|
|
||||||
formatter.type);
|
|
||||||
sections.add(section);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void newCombine(String str, ArrayList<FormattedSection> sections, ArrayList<int[]> remchars) {
|
private static void newCombine(String str, ArrayList<FormattedSection> sections, ArrayList<int[]> remchars) {
|
||||||
|
@ -154,7 +108,7 @@ public final class ChatFormatter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArrayList<FormattedSection> convertRangeSections(String str, ArrayList<FormattedSection> sections, ArrayList<int[]> remchars) {
|
private static ArrayList<FormattedSection> createRangeSections(String str, List<ChatFormatter> formatters, ArrayList<int[]> remchars) {
|
||||||
ArrayList<FormattedSection> combined = new ArrayList<>();
|
ArrayList<FormattedSection> combined = new ArrayList<>();
|
||||||
Map<ChatFormatter, FormattedSection> nextSection = new HashMap<>();
|
Map<ChatFormatter, FormattedSection> nextSection = new HashMap<>();
|
||||||
boolean escaped = false;
|
boolean escaped = false;
|
||||||
|
@ -172,7 +126,7 @@ public final class ChatFormatter {
|
||||||
combined.add(section); // The above will delete the \
|
combined.add(section); // The above will delete the \
|
||||||
DebugCommand.SendDebugMessage("Added section: " + section);
|
DebugCommand.SendDebugMessage("Added section: " + section);
|
||||||
}
|
}
|
||||||
sendMessageWithPointer(str, section.Start, section.End);
|
ChatFormatUtils.sendMessageWithPointer(str, section.Start, section.End);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!escaped) {
|
if (!escaped) {
|
||||||
|
@ -183,17 +137,17 @@ public final class ChatFormatter {
|
||||||
*/
|
*/
|
||||||
if (takenByBigGuy || formatter.removeCharCount < takenEnd - takenStart) {
|
if (takenByBigGuy || formatter.removeCharCount < takenEnd - takenStart) {
|
||||||
DebugCommand.SendDebugMessage("Lose: " + section);
|
DebugCommand.SendDebugMessage("Lose: " + section);
|
||||||
sendMessageWithPointer(str, section.Start, section.End);
|
ChatFormatUtils.sendMessageWithPointer(str, section.Start, section.End);
|
||||||
DebugCommand.SendDebugMessage("And win: " + takenFormatter);
|
DebugCommand.SendDebugMessage("And win: " + takenFormatter);
|
||||||
continue; // The current section loses
|
continue; // The current section loses
|
||||||
}
|
}
|
||||||
nextSection.remove(takenFormatter); // The current section wins
|
nextSection.remove(takenFormatter); // The current section wins
|
||||||
DebugCommand.SendDebugMessage("Win: " + section);
|
DebugCommand.SendDebugMessage("Win: " + section);
|
||||||
sendMessageWithPointer(str, section.Start, section.End);
|
ChatFormatUtils.sendMessageWithPointer(str, section.Start, section.End);
|
||||||
DebugCommand.SendDebugMessage("And lose: " + takenFormatter);
|
DebugCommand.SendDebugMessage("And lose: " + takenFormatter);
|
||||||
}
|
}
|
||||||
boolean hasFormatter = nextSection.containsKey(formatter);
|
boolean hasFormatter = nextSection.containsKey(formatter);
|
||||||
if (!hasFormatter) {
|
/*if (!hasFormatter) {
|
||||||
val ff = formatter;
|
val ff = formatter;
|
||||||
val cfo = nextSection.keySet().stream().filter(f -> f.removeCharCount > ff.removeCharCount).findAny();
|
val cfo = nextSection.keySet().stream().filter(f -> f.removeCharCount > ff.removeCharCount).findAny();
|
||||||
if (cfo.isPresent()) {
|
if (cfo.isPresent()) {
|
||||||
|
@ -205,7 +159,7 @@ public final class ChatFormatter {
|
||||||
continue; //Not the formatter we're looking for - TODO: It doesn't fix the problem of italics at the end
|
continue; //Not the formatter we're looking for - TODO: It doesn't fix the problem of italics at the end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
takenStart = section.Start;
|
takenStart = section.Start;
|
||||||
takenEnd = section.Start + formatter.removeCharCount;
|
takenEnd = section.Start + formatter.removeCharCount;
|
||||||
takenFormatter = formatter;
|
takenFormatter = formatter;
|
||||||
|
@ -218,19 +172,19 @@ public final class ChatFormatter {
|
||||||
combined.add(s);
|
combined.add(s);
|
||||||
takenByBigGuy = true;
|
takenByBigGuy = true;
|
||||||
DebugCommand.SendDebugMessage("Finished section: " + s);
|
DebugCommand.SendDebugMessage("Finished section: " + s);
|
||||||
sendMessageWithPointer(str, s.Start, s.End);
|
ChatFormatUtils.sendMessageWithPointer(str, s.Start, s.End);
|
||||||
} else {
|
} else {
|
||||||
DebugCommand.SendDebugMessage("Adding next section: " + section);
|
DebugCommand.SendDebugMessage("Adding next section: " + section);
|
||||||
sendMessageWithPointer(str, section.Start, section.End);
|
ChatFormatUtils.sendMessageWithPointer(str, section.Start, section.End);
|
||||||
nextSection.put(formatter, section);
|
nextSection.put(formatter, section);
|
||||||
takenByBigGuy = false;
|
takenByBigGuy = false;
|
||||||
}
|
}
|
||||||
DebugCommand
|
DebugCommand
|
||||||
.SendDebugMessage("New area taken: (" + takenStart + "-" + takenEnd + ") " + takenFormatter);
|
.SendDebugMessage("New area taken: (" + takenStart + "-" + takenEnd + ") " + takenFormatter);
|
||||||
sendMessageWithPointer(str, takenStart, takenEnd);
|
ChatFormatUtils.sendMessageWithPointer(str, takenStart, takenEnd);
|
||||||
} else {
|
} else {
|
||||||
DebugCommand.SendDebugMessage("Skipping section: " + section); // This will keep the text (character)
|
DebugCommand.SendDebugMessage("Skipping section: " + section); // This will keep the text (character)
|
||||||
sendMessageWithPointer(str, section.Start, section.End);
|
ChatFormatUtils.sendMessageWithPointer(str, section.Start, section.End);
|
||||||
escaped = false; // Reset escaping if applied, like if we're at the '*' in '\*'
|
escaped = false; // Reset escaping if applied, like if we're at the '*' in '\*'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,7 +204,7 @@ public final class ChatFormatter {
|
||||||
.forEach(remchars::add);
|
.forEach(remchars::add);
|
||||||
DebugCommand.SendDebugMessage("Added remchars:");
|
DebugCommand.SendDebugMessage("Added remchars:");
|
||||||
DebugCommand.SendDebugMessage(remchars.stream().map(Arrays::toString).collect(Collectors.joining("; ")));
|
DebugCommand.SendDebugMessage(remchars.stream().map(Arrays::toString).collect(Collectors.joining("; ")));
|
||||||
sendMessageWithPointer(str,
|
ChatFormatUtils.sendMessageWithPointer(str,
|
||||||
remchars.stream().flatMapToInt(Arrays::stream).toArray());
|
remchars.stream().flatMapToInt(Arrays::stream).toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,15 +225,15 @@ public final class ChatFormatter {
|
||||||
lastSection = lastSect;
|
lastSection = lastSect;
|
||||||
}
|
}
|
||||||
DebugCommand.SendDebugMessage("Combining sections " + firstSection);
|
DebugCommand.SendDebugMessage("Combining sections " + firstSection);
|
||||||
sendMessageWithPointer(str, firstSection.Start, firstSection.End);
|
ChatFormatUtils.sendMessageWithPointer(str, firstSection.Start, firstSection.End);
|
||||||
DebugCommand.SendDebugMessage(" and " + lastSection);
|
DebugCommand.SendDebugMessage(" and " + lastSection);
|
||||||
sendMessageWithPointer(str, lastSection.Start, lastSection.End);
|
ChatFormatUtils.sendMessageWithPointer(str, lastSection.Start, lastSection.End);
|
||||||
if (firstSection.Start == lastSection.Start && firstSection.End == lastSection.End) {
|
if (firstSection.Start == lastSection.Start && firstSection.End == lastSection.End) {
|
||||||
firstSection.Formatters.addAll(lastSection.Formatters);
|
firstSection.Formatters.addAll(lastSection.Formatters);
|
||||||
firstSection.Matches.addAll(lastSection.Matches);
|
firstSection.Matches.addAll(lastSection.Matches);
|
||||||
firstSection.type = lastSection.type;
|
firstSection.type = lastSection.type;
|
||||||
DebugCommand.SendDebugMessage("To section " + firstSection);
|
DebugCommand.SendDebugMessage("To section " + firstSection);
|
||||||
sendMessageWithPointer(str, firstSection.Start, firstSection.End);
|
ChatFormatUtils.sendMessageWithPointer(str, firstSection.Start, firstSection.End);
|
||||||
sections.remove(i);
|
sections.remove(i);
|
||||||
i = 0;
|
i = 0;
|
||||||
sortSections(sections);
|
sortSections(sections);
|
||||||
|
@ -305,7 +259,7 @@ public final class ChatFormatter {
|
||||||
Predicate<FormattedSection> removeIfNeeded = s -> {
|
Predicate<FormattedSection> removeIfNeeded = s -> {
|
||||||
if (s.Start < 0 || s.End < 0 || s.Start > s.End) {
|
if (s.Start < 0 || s.End < 0 || s.Start > s.End) {
|
||||||
DebugCommand.SendDebugMessage(" Removed: " + s);
|
DebugCommand.SendDebugMessage(" Removed: " + s);
|
||||||
sendMessageWithPointer(str, s.Start, s.End);
|
ChatFormatUtils.sendMessageWithPointer(str, s.Start, s.End);
|
||||||
sections.remove(s);
|
sections.remove(s);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -315,15 +269,15 @@ public final class ChatFormatter {
|
||||||
DebugCommand.SendDebugMessage("To sections");
|
DebugCommand.SendDebugMessage("To sections");
|
||||||
if (!removeIfNeeded.test(firstSection)) {
|
if (!removeIfNeeded.test(firstSection)) {
|
||||||
DebugCommand.SendDebugMessage(" 1:" + firstSection + "");
|
DebugCommand.SendDebugMessage(" 1:" + firstSection + "");
|
||||||
sendMessageWithPointer(str, firstSection.Start, firstSection.End);
|
ChatFormatUtils.sendMessageWithPointer(str, firstSection.Start, firstSection.End);
|
||||||
}
|
}
|
||||||
if (!removeIfNeeded.test(section)) {
|
if (!removeIfNeeded.test(section)) {
|
||||||
DebugCommand.SendDebugMessage(" 2:" + section + "");
|
DebugCommand.SendDebugMessage(" 2:" + section + "");
|
||||||
sendMessageWithPointer(str, section.Start, section.End);
|
ChatFormatUtils.sendMessageWithPointer(str, section.Start, section.End);
|
||||||
}
|
}
|
||||||
if (!removeIfNeeded.test(lastSection)) {
|
if (!removeIfNeeded.test(lastSection)) {
|
||||||
DebugCommand.SendDebugMessage(" 3:" + lastSection);
|
DebugCommand.SendDebugMessage(" 3:" + lastSection);
|
||||||
sendMessageWithPointer(str, lastSection.Start, lastSection.End);
|
ChatFormatUtils.sendMessageWithPointer(str, lastSection.Start, lastSection.End);
|
||||||
}
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
|
@ -332,7 +286,7 @@ public final class ChatFormatter {
|
||||||
for (int j = i - 1; j <= i + 1; j++) {
|
for (int j = i - 1; j <= i + 1; j++) {
|
||||||
if (j < sections.size() && sections.get(j).End < sections.get(j).Start) {
|
if (j < sections.size() && sections.get(j).End < sections.get(j).Start) {
|
||||||
DebugCommand.SendDebugMessage("Removing section: " + sections.get(j));
|
DebugCommand.SendDebugMessage("Removing section: " + sections.get(j));
|
||||||
sendMessageWithPointer(str, sections.get(j).Start, sections.get(j).End);
|
ChatFormatUtils.sendMessageWithPointer(str, sections.get(j).Start, sections.get(j).End);
|
||||||
sections.remove(j);
|
sections.remove(j);
|
||||||
j--;
|
j--;
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -349,7 +303,7 @@ public final class ChatFormatter {
|
||||||
String originaltext;
|
String originaltext;
|
||||||
int start = section.Start, end = section.End;
|
int start = section.Start, end = section.End;
|
||||||
DebugCommand.SendDebugMessage("Start: " + start + " - End: " + end);
|
DebugCommand.SendDebugMessage("Start: " + start + " - End: " + end);
|
||||||
sendMessageWithPointer(str, start, end);
|
ChatFormatUtils.sendMessageWithPointer(str, start, end);
|
||||||
/*DebugCommand.SendDebugMessage("RCS: "+remchars.stream().filter(rc -> rc[0] <= start && start <= rc[1]).count());
|
/*DebugCommand.SendDebugMessage("RCS: "+remchars.stream().filter(rc -> rc[0] <= start && start <= rc[1]).count());
|
||||||
DebugCommand.SendDebugMessage("RCE: "+remchars.stream().filter(rc -> rc[0] <= end && end <= rc[1]).count());
|
DebugCommand.SendDebugMessage("RCE: "+remchars.stream().filter(rc -> rc[0] <= end && end <= rc[1]).count());
|
||||||
DebugCommand.SendDebugMessage("RCI: "+remchars.stream().filter(rc -> start < rc[0] || rc[1] < end).count());*/
|
DebugCommand.SendDebugMessage("RCI: "+remchars.stream().filter(rc -> start < rc[0] || rc[1] < end).count());*/
|
||||||
|
@ -432,20 +386,6 @@ public final class ChatFormatter {
|
||||||
: Integer.compare(s1.Start, s2.Start));
|
: Integer.compare(s1.Start, s2.Start));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sendMessageWithPointer(String str, int... pointer) {
|
|
||||||
DebugCommand.SendDebugMessage(str);
|
|
||||||
StringBuilder sb = new StringBuilder(str.length());
|
|
||||||
Arrays.sort(pointer);
|
|
||||||
for (int i = 0; i < pointer.length; i++) {
|
|
||||||
for (int j = 0; j < pointer[i] - (i > 0 ? pointer[i - 1] + 1 : 0); j++)
|
|
||||||
sb.append(' ');
|
|
||||||
if (pointer[i] == (i > 0 ? pointer[i - 1] : -1))
|
|
||||||
continue;
|
|
||||||
sb.append('^');
|
|
||||||
}
|
|
||||||
DebugCommand.SendDebugMessage(sb.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void header(String message) {
|
private static void header(String message) {
|
||||||
DebugCommand.SendDebugMessage("\n--------\n" + message + "\n--------\n");
|
DebugCommand.SendDebugMessage("\n--------\n" + message + "\n--------\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package buttondevteam.chat.components.formatter.formatting;
|
||||||
|
|
||||||
|
import buttondevteam.lib.chat.Color;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class FormatSettings {
|
||||||
|
boolean italic;
|
||||||
|
boolean bold;
|
||||||
|
boolean underlined;
|
||||||
|
boolean strikethrough;
|
||||||
|
boolean obfuscated;
|
||||||
|
Color color;
|
||||||
|
ChatFormatter.TriFunc<String, ChatFormatter, FormattedSection, String> onmatch;
|
||||||
|
String openlink;
|
||||||
|
}
|
|
@ -1,36 +1,17 @@
|
||||||
package buttondevteam.chat.components.formatter.formatting;
|
package buttondevteam.chat.components.formatter.formatting;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
public class FormattedSection {
|
public class FormattedSection {
|
||||||
public int Start;
|
public int Start;
|
||||||
public int End;
|
public int End;
|
||||||
public ArrayList<ChatFormatter> Formatters = new ArrayList<ChatFormatter>();
|
public FormatSettings Settings;
|
||||||
public ArrayList<String> Matches = new ArrayList<String>();
|
public ArrayList<String> Matches = new ArrayList<String>();
|
||||||
public ChatFormatter.Type type;
|
|
||||||
|
|
||||||
FormattedSection(ChatFormatter formatter, int start, int end, ArrayList<String> matches, ChatFormatter.Type type) {
|
FormattedSection(FormatSettings settings, int start, int end, ArrayList<String> matches) {
|
||||||
Start = start;
|
Start = start;
|
||||||
End = end;
|
End = end;
|
||||||
Formatters.add(formatter);
|
Settings = settings;
|
||||||
Matches.addAll(matches);
|
Matches.addAll(matches);
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
FormattedSection(Collection<ChatFormatter> formatters, int start, int end, ArrayList<String> matches,
|
|
||||||
ChatFormatter.Type type) {
|
|
||||||
Start = start;
|
|
||||||
End = end;
|
|
||||||
Formatters.addAll(formatters);
|
|
||||||
Matches.addAll(matches);
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Section(" + Start + ", " + End + ", formatters: " +
|
|
||||||
Formatters.toString() + ", matches: " + Matches.toString() + ", " +
|
|
||||||
type + ")";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package buttondevteam.chat.components.formatter.formatting;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public interface MatchProvider {
|
||||||
|
@Nullable
|
||||||
|
FormattedSection getNextSection(String message, ArrayList<int[]> ignoredAreas, ArrayList<int[]> removedCharacters);
|
||||||
|
|
||||||
|
boolean isFinished();
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package buttondevteam.chat.components.formatter.formatting;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RangeMatchProvider implements MatchProvider {
|
||||||
|
private final String pattern;
|
||||||
|
private final FormatSettings settings;
|
||||||
|
@Getter
|
||||||
|
private boolean finished;
|
||||||
|
private int nextIndex = 0;
|
||||||
|
private FormattedSection startedSection;
|
||||||
|
|
||||||
|
@SuppressWarnings("DuplicatedCode")
|
||||||
|
@Override
|
||||||
|
public FormattedSection getNextSection(String message, ArrayList<int[]> ignoredAreas, ArrayList<int[]> removedCharacters) {
|
||||||
|
int i, len;
|
||||||
|
do {
|
||||||
|
i = message.indexOf(pattern, nextIndex);
|
||||||
|
len = pattern.length();
|
||||||
|
nextIndex = i + len; //Set for the next loop if it's escaped or for the next method call
|
||||||
|
} while (i > 0 && message.charAt(i - 1) == '\\');
|
||||||
|
if (i == -1) {
|
||||||
|
finished = true; //Won't find any more - unfinished sections will be garbage collected
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
removedCharacters.add(new int[]{i, i + len - 1});
|
||||||
|
if (startedSection == null) {
|
||||||
|
startedSection = new FormattedSection(settings, i, i + len - 1, new ArrayList<>(0));
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
startedSection.End = i + len - 1;
|
||||||
|
return startedSection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package buttondevteam.chat.components.formatter.formatting;
|
||||||
|
|
||||||
|
import buttondevteam.chat.commands.ucmds.admin.DebugCommand;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RegexMatchProvider implements MatchProvider {
|
||||||
|
private final Pattern pattern;
|
||||||
|
private final FormatSettings settings;
|
||||||
|
private Matcher matcher;
|
||||||
|
@Getter
|
||||||
|
private boolean finished;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public FormattedSection getNextSection(String message, ArrayList<int[]> ignoredAreas, ArrayList<int[]> removedCharacters) {
|
||||||
|
if (matcher == null)
|
||||||
|
matcher = pattern.matcher(message);
|
||||||
|
if (!matcher.find()) {
|
||||||
|
finished = true;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int start = matcher.start(), end = matcher.end() - 1;
|
||||||
|
DebugCommand.SendDebugMessage("Found regex match from " + start + " to " + end);
|
||||||
|
DebugCommand.SendDebugMessage("With settings: " + settings);
|
||||||
|
ChatFormatUtils.sendMessageWithPointer(message, start, end);
|
||||||
|
if (ChatFormatUtils.isInRange(start, end, ignoredAreas)) {
|
||||||
|
DebugCommand.SendDebugMessage("Formatter is in ignored area, skipping");
|
||||||
|
return null; //Not setting finished to true, so it will go to the next match
|
||||||
|
}
|
||||||
|
ArrayList<String> groups = new ArrayList<>();
|
||||||
|
for (int i = 0; i < matcher.groupCount(); i++)
|
||||||
|
groups.add(matcher.group(i + 1));
|
||||||
|
if (groups.size() > 0)
|
||||||
|
DebugCommand.SendDebugMessage("First group: " + groups.get(0));
|
||||||
|
return new FormattedSection(settings, matcher.start(), matcher.end() - 1, groups);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package buttondevteam.chat.components.formatter.formatting;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class StringMatchProvider implements MatchProvider {
|
||||||
|
private final String[] strings;
|
||||||
|
private final FormatSettings settings;
|
||||||
|
@Getter
|
||||||
|
private boolean finished;
|
||||||
|
private int nextIndex = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches the given strings in the order given
|
||||||
|
*
|
||||||
|
* @param settings The format settings
|
||||||
|
* @param strings The strings to match in the correct order
|
||||||
|
*/
|
||||||
|
public StringMatchProvider(FormatSettings settings, String... strings) {
|
||||||
|
this.settings = settings;
|
||||||
|
this.strings = strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public FormattedSection getNextSection(String message, ArrayList<int[]> ignoredAreas, ArrayList<int[]> removedCharacters) {
|
||||||
|
int i = -1, len = 0;
|
||||||
|
for (String string : strings) {
|
||||||
|
i = message.indexOf(string, nextIndex);
|
||||||
|
len = string.length();
|
||||||
|
if (i != -1) break;
|
||||||
|
}
|
||||||
|
if (i == -1) {
|
||||||
|
finished = true; //Won't find any more
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
nextIndex = i + len;
|
||||||
|
return new FormattedSection(settings, i, i + len - 1, new ArrayList<>(0));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue