Skip to content

Commit

Permalink
Fix issues with nested parsing (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
Phoenix616 committed Sep 10, 2022
1 parent 0208f75 commit 5f40f57
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 30 deletions.
42 changes: 12 additions & 30 deletions src/main/java/de/themoep/minedown/MineDownParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,30 +148,14 @@ public ComponentBuilder parse(String message) throws IllegalArgumentException {
boolean isEscape = c == '\\' && i + 1 < message.length();
boolean isColorCode = isEnabled(Option.LEGACY_COLORS)
&& i + 1 < message.length() && (c == ChatColor.COLOR_CHAR || c == colorChar());
boolean isEvent = false;
if (isEnabled(Option.ADVANCED_FORMATTING) && c == '[') {
int nextEventClose = Util.indexOfNotEscaped(message, "](", i + 1);
if (nextEventClose != -1 && nextEventClose + 2 < message.length()) {
int nextDefClose = Util.indexOfNotEscaped(message, ")", i + 2);
if (nextDefClose != -1) {
int depth = 1;
isEvent = true;
boolean innerEscaped = false;
for (int j = i + 1; j < nextEventClose; j++) {
if (innerEscaped) {
innerEscaped = false;
} else if (message.charAt(j) == '\\') {
innerEscaped = true;
} else if (message.charAt(j) == '[') {
depth++;
} else if (message.charAt(j) == ']') {
depth--;
}
if (depth == 0) {
isEvent = false;
break;
}
}
int eventEndIndex = -1;
String eventDefinition = "";
if (!escaped && isEnabled(Option.ADVANCED_FORMATTING) && c == '[') {
eventEndIndex = Util.getUnescapedEndIndex(message, '[', ']', i);
if (eventEndIndex != -1 && message.length() > eventEndIndex + 1 && message.charAt(eventEndIndex + 1) == '(') {
int definitionClose = Util.getUnescapedEndIndex(message, '(', ')', eventEndIndex + 1);
if (definitionClose != -1) {
eventDefinition = message.substring(eventEndIndex + 2, definitionClose);
}
}
}
Expand Down Expand Up @@ -297,16 +281,14 @@ public ComponentBuilder parse(String message) throws IllegalArgumentException {
continue;

// Events
} else if (isEvent) {
int index = Util.indexOfNotEscaped(message, "](", i + 1);
int endIndex = Util.indexOfNotEscaped(message, ")", index + 2);
} else if (eventEndIndex != -1 && !eventDefinition.isEmpty()) {
appendValue();
if (!isFiltered(Option.ADVANCED_FORMATTING)) {
append(parseEvent(message.substring(i + 1, index), message.substring(index + 2, endIndex)));
append(parseEvent(message.substring(i + 1, eventEndIndex), eventDefinition));
} else {
append(copy(true).parse(message.substring(i + 1, index)));
append(copy(true).parse(message.substring(i + 1, eventEndIndex)));
}
i = endIndex;
i = eventEndIndex + 2 + eventDefinition.length();
continue;

// Simple formatting
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/de/themoep/minedown/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,34 @@ public static boolean isEscaped(String string, int index) {
return e % 2 != 0;
}

/**
* Gets the proper end index of a certain definition on the same depth while ignoring escaped chars.
* @param string The string to search
* @param startChar The start cahracter of the definition
* @param endChar The end character of the definition
* @param fromIndex The index to start searching from (should be at the start char)
* @return The first end index of that group or {@code -1} if not found
*/
public static int getUnescapedEndIndex(String string, char startChar, char endChar, int fromIndex) {
int depth = 0;
boolean innerEscaped = false;
for (int i = fromIndex; i < string.length(); i++) {
if (innerEscaped) {
innerEscaped = false;
} else if (string.charAt(i) == '\\') {
innerEscaped = true;
} else if (string.charAt(i) == startChar) {
depth++;
} else if (string.charAt(i) == endChar) {
depth--;
if (depth == 0) {
return i;
}
}
}
return -1;
}

/**
* Wrap a string if it is longer than the line length and contains no new line.
* Will try to wrap at spaces between words.
Expand Down
12 changes: 12 additions & 0 deletions src/test/java/de/themoep/minedown/tests/ParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -226,4 +226,16 @@ public void testNegated() {
() -> parse("&lBold [not bold](!bold) bold", "{\"extra\":[{\"bold\":true,\"text\":\"Bold \"},{\"bold\":false,\"text\":\"not bold\"},{\"bold\":true,\"text\":\" bold\"}],\"text\":\"\"}")
);
}

@Test
public void testParseNested() {
Assertions.assertAll(
() -> parse("[outer start [inner](green) outer end](aqua)",
"{\"extra\":[{\"color\":\"aqua\",\"text\":\"outer start \"},{\"color\":\"green\",\"text\":\"inner\"},{\"color\":\"aqua\",\"text\":\" outer end\"}],\"text\":\"\"}"),
() -> parse("[outer start \\[[inner](green)\\] outer end](aqua)",
"{\"extra\":[{\"color\":\"aqua\",\"text\":\"outer start [\"},{\"color\":\"green\",\"text\":\"inner\"},{\"color\":\"aqua\",\"text\":\"] outer end\"}],\"text\":\"\"}"),
() -> parse("[outer start [inner](green) outer end](aqua hover={[red hover](red)})",
"{\"extra\":[{\"color\":\"aqua\",\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[{\"color\":\"red\",\"text\":\"red hover\"}]},\"text\":\"outer start \"},{\"color\":\"green\",\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[{\"color\":\"red\",\"text\":\"red hover\"}]},\"text\":\"inner\"},{\"color\":\"aqua\",\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[{\"color\":\"red\",\"text\":\"red hover\"}]},\"text\":\" outer end\"}],\"text\":\"\"}")
);
}
}

0 comments on commit 5f40f57

Please sign in to comment.