Skip to content

Commit 9e2f59c

Browse files
committed
wip: feat: continue translate methods of legacy parser
1 parent c13963c commit 9e2f59c

File tree

6 files changed

+192
-73
lines changed

6 files changed

+192
-73
lines changed

core/src/main/java/com/rexcantor64/triton/language/parser/AdventureParser.java

Lines changed: 6 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.rexcantor64.triton.api.language.Localized;
66
import com.rexcantor64.triton.api.language.MessageParser;
77
import com.rexcantor64.triton.utils.ComponentUtils;
8+
import com.rexcantor64.triton.utils.ParserUtils;
89
import com.rexcantor64.triton.utils.StringUtils;
910
import lombok.AccessLevel;
1011
import lombok.Getter;
@@ -110,7 +111,7 @@ TranslationResult<Component> translateComponent(@NotNull Component component, @N
110111
plainText = componentToString(component);
111112
}
112113

113-
val indexes = this.getPatternIndexArray(plainText, configuration.getFeatureSyntax().getLang());
114+
val indexes = ParserUtils.getPatternIndexArray(plainText, configuration.getFeatureSyntax().getLang());
114115

115116
if (indexes.isEmpty()) {
116117
return handleNonContentText(component, configuration);
@@ -170,7 +171,7 @@ private Optional<Component> handlePlaceholder(Component placeholder, Translation
170171
placeholder = stripStyleOfFirstCharacter(placeholder);
171172

172173
String placeholderStr = componentToString(placeholder);
173-
val indexes = this.getPatternIndexArray(placeholderStr, configuration.getFeatureSyntax().getArg());
174+
val indexes = ParserUtils.getPatternIndexArray(placeholderStr, configuration.getFeatureSyntax().getArg());
174175
Queue<Integer> indexesToSplitAt = indexes.stream()
175176
.flatMap(Arrays::stream)
176177
.sorted()
@@ -186,10 +187,7 @@ private Optional<Component> handlePlaceholder(Component placeholder, Translation
186187
Component part = splitComponents.get(i);
187188
if (i == 0) {
188189
key = PlainTextComponentSerializer.plainText().serialize(part);
189-
// The [args] tag is optional since v4.0.0, so strip it if it's present
190-
if (key.endsWith("[" + configuration.getFeatureSyntax().getArgs() + "]")) {
191-
key = key.substring(0, key.length() - configuration.getFeatureSyntax().getArgs().length() - 2);
192-
}
190+
key = ParserUtils.normalizeTranslationKey(key, configuration);
193191
if (!StringUtils.isEmptyOrNull(configuration.getDisabledLine()) && configuration.getDisabledLine()
194192
.equals(key)) {
195193
return Optional.empty();
@@ -352,7 +350,8 @@ private Style getStyleOfFirstCharacterOrEmpty(Component component) {
352350
*/
353351
@VisibleForTesting
354352
@Contract("_ -> new")
355-
@NotNull Component stripStyleOfFirstCharacter(@NotNull Component component) {
353+
@NotNull
354+
Component stripStyleOfFirstCharacter(@NotNull Component component) {
356355
if (component instanceof TextComponent) {
357356
TextComponent textComponent = (TextComponent) component;
358357
if (!textComponent.content().isEmpty()) {
@@ -584,51 +583,6 @@ private List<Component> handleChildren(Component parent, List<Component> childre
584583
return accumulator;
585584
}
586585

587-
/**
588-
* Find the indexes of all root "[pattern][/pattern]" tags in the given string.
589-
* <p>
590-
* Only the root tags are included, that is, nested tags are ignored.
591-
* For example, <code>[pattern][pattern][/pattern][/pattern]</code> would only
592-
* return the indexes for the outer tags.
593-
* <p>
594-
* Each array in the returned list corresponds to a different set of opening and closing tags,
595-
* and has size 4.
596-
* Indexes have the following meaning:
597-
* <ul>
598-
* <li>0: the first character of the opening tag</li>
599-
* <li>1: the character after the last character of the closing tag</li>
600-
* <li>2: the character after the last character of the opening tag</li>
601-
* <li>3: the first character of the closing tag</li>
602-
* </ul>
603-
*
604-
* @param input The string to search for opening and closing tags.
605-
* @param pattern The tags to search for (i.e. "lang" will search for "[lang]" and "[/lang]").
606-
* @return A list of indexes of all the found tags, as specified by the method description.
607-
*/
608-
public List<Integer[]> getPatternIndexArray(String input, String pattern) {
609-
List<Integer[]> result = new ArrayList<>();
610-
int start = -1;
611-
int openedAmount = 0;
612-
613-
for (int i = 0; i < input.length(); i++) {
614-
char currentChar = input.charAt(i);
615-
if (currentChar == '[' && input.length() > i + pattern.length() + 1 && input.substring(i + 1,
616-
i + 2 + pattern.length()).equals(pattern + "]")) {
617-
if (start == -1) start = i;
618-
openedAmount++;
619-
i += 1 + pattern.length();
620-
} else if (currentChar == '[' && input.length() > i + pattern.length() + 2 && input.substring(i + 1,
621-
i + 3 + pattern.length()).equals("/" + pattern + "]")) {
622-
openedAmount--;
623-
if (openedAmount == 0) {
624-
result.add(new Integer[]{start, i + 3 + pattern.length(), start + pattern.length() + 2, i});
625-
start = -1;
626-
}
627-
}
628-
}
629-
return result;
630-
}
631-
632586
/**
633587
* Adventure has an issue where some components might not become empty
634588
* components, even though they should be. This is a fix for that, while

core/src/main/java/com/rexcantor64/triton/language/parser/LegacyParser.java

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import com.rexcantor64.triton.api.config.FeatureSyntax;
55
import com.rexcantor64.triton.api.language.Localized;
66
import com.rexcantor64.triton.api.language.MessageParser;
7-
import com.rexcantor64.triton.api.language.TranslationResult;
87
import com.rexcantor64.triton.utils.ComponentUtils;
8+
import com.rexcantor64.triton.utils.ParserUtils;
99
import lombok.AccessLevel;
1010
import lombok.Getter;
1111
import lombok.Setter;
@@ -37,6 +37,7 @@
3737
import java.util.Arrays;
3838
import java.util.HashMap;
3939
import java.util.List;
40+
import java.util.Optional;
4041
import java.util.UUID;
4142
import java.util.stream.Collectors;
4243

@@ -130,8 +131,78 @@ TranslationResult<SerializedComponent> translateComponent(
130131
@NotNull SerializedComponent component,
131132
@NotNull TranslationConfiguration<SerializedComponent> configuration
132133
) {
133-
// TODO!
134-
return null;
134+
String text = component.getText();
135+
val indexes = ParserUtils.getPatternIndexArray(text, configuration.getFeatureSyntax().getLang());
136+
137+
if (indexes.isEmpty()) {
138+
// TODO handle non text components
139+
return TranslationResult.unchanged();
140+
}
141+
142+
val builder = new StringBuilder();
143+
// keep track of last index added to the string builder
144+
int lastCharacter = 0;
145+
146+
for (val index : indexes) {
147+
builder.append(text, lastCharacter, index[0]);
148+
lastCharacter = index[1];
149+
150+
val placeholder = text.substring(index[2], index[3]);
151+
152+
val resultComponent = handlePlaceholder(placeholder, configuration);
153+
if (!resultComponent.isPresent()) {
154+
return TranslationResult.remove();
155+
}
156+
157+
builder.append(resultComponent.get().getText());
158+
component.importFromComponent(resultComponent.get());
159+
}
160+
161+
builder.append(text, lastCharacter, text.length());
162+
component.setText(builder.toString());
163+
164+
// TODO handle non text components
165+
166+
return TranslationResult.changed(component);
167+
}
168+
169+
/**
170+
* An auxiliary method to {@link LegacyParser#translateComponent(SerializedComponent, TranslationConfiguration)}
171+
* that handles translating the component inside the <code>[lang][/lang]</code> tags.
172+
* The <code>[args][/args]</code> tags are optional since Triton v4.0.0.
173+
* <p>
174+
* This method gets the translation for the key and replaces its arguments, if any.
175+
*
176+
* @param placeholder The text inside the <code>[lang][/lang]</code> tags.
177+
* @param configuration The settings to apply to this translation.
178+
* @return The translation of this placeholder. Empty optional if the translation is "disabled line".
179+
* @since 4.0.0
180+
*/
181+
private @NotNull Optional<SerializedComponent> handlePlaceholder(
182+
@NotNull String placeholder,
183+
@NotNull TranslationConfiguration<SerializedComponent> configuration
184+
) {
185+
val indexes = ParserUtils.getPatternIndexArray(placeholder, configuration.getFeatureSyntax().getArg());
186+
187+
SerializedComponent[] arguments = indexes.stream()
188+
.map(index -> placeholder.substring(index[2], index[3]))
189+
.map(SerializedComponent::new)
190+
.toArray(SerializedComponent[]::new);
191+
192+
String key = placeholder;
193+
if (!indexes.isEmpty()) {
194+
key = key.substring(0, indexes.get(0)[0]);
195+
}
196+
key = ParserUtils.normalizeTranslationKey(key, configuration);
197+
198+
val result = configuration.translationSupplier.apply(key, arguments);
199+
200+
TranslationResult<SerializedComponent> translationResult = translateComponent(result, configuration);
201+
if (translationResult.getState() == TranslationResult.ResultState.TO_REMOVE) {
202+
return Optional.empty();
203+
}
204+
205+
return Optional.of(translationResult.getResult().orElse(result));
135206
}
136207

137208
public @NotNull String replaceArguments(@NotNull String text, @Nullable String @NotNull [] arguments) {
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.rexcantor64.triton.utils;
2+
3+
import com.rexcantor64.triton.language.parser.TranslationConfiguration;
4+
import lombok.val;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
9+
/**
10+
* Methods used in implementations of {@link com.rexcantor64.triton.api.language.MessageParser}.
11+
*
12+
* @since 4.0.0
13+
*/
14+
public class ParserUtils {
15+
16+
/**
17+
* Find the indexes of all root "[pattern][/pattern]" tags in the given string.
18+
* <p>
19+
* Only the root tags are included, that is, nested tags are ignored.
20+
* For example, <code>[pattern][pattern][/pattern][/pattern]</code> would only
21+
* return the indexes for the outer tags.
22+
* <p>
23+
* Each array in the returned list corresponds to a different set of opening and closing tags,
24+
* and has size 4.
25+
* Indexes have the following meaning:
26+
* <ul>
27+
* <li>0: the first character of the opening tag</li>
28+
* <li>1: the character after the last character of the closing tag</li>
29+
* <li>2: the character after the last character of the opening tag</li>
30+
* <li>3: the first character of the closing tag</li>
31+
* </ul>
32+
*
33+
* @param input The string to search for opening and closing tags.
34+
* @param pattern The tags to search for (i.e. "lang" will search for "[lang]" and "[/lang]").
35+
* @return A list of indexes of all the found tags, as specified by the method description.
36+
*/
37+
public static List<Integer[]> getPatternIndexArray(String input, String pattern) {
38+
List<Integer[]> result = new ArrayList<>();
39+
int start = -1;
40+
int openedAmount = 0;
41+
42+
for (int i = 0; i < input.length(); i++) {
43+
char currentChar = input.charAt(i);
44+
if (currentChar == '[' && input.length() > i + pattern.length() + 1 && input.substring(i + 1,
45+
i + 2 + pattern.length()).equals(pattern + "]")) {
46+
if (start == -1) start = i;
47+
openedAmount++;
48+
i += 1 + pattern.length();
49+
} else if (currentChar == '[' && input.length() > i + pattern.length() + 2 && input.substring(i + 1,
50+
i + 3 + pattern.length()).equals("/" + pattern + "]")) {
51+
openedAmount--;
52+
if (openedAmount == 0) {
53+
result.add(new Integer[]{start, i + 3 + pattern.length(), start + pattern.length() + 2, i});
54+
start = -1;
55+
}
56+
}
57+
}
58+
return result;
59+
}
60+
61+
/**
62+
* Removes legacy <code>[args][/args]</code> tags from (the end of) translation keys.
63+
* Since v4.0.0, these tags are no longer needed and are therefore deprecated.
64+
* For backwards compatibility, ignore them.
65+
*
66+
* @param key The key, potentially ending in <code>[args]</code>, <code>[/args]</code>, or both.
67+
* @param configuration The settings being applied while translating the placeholder with this key.
68+
* @return The key with the <code>[args][/args]</code> removed.
69+
*/
70+
public static String normalizeTranslationKey(String key, TranslationConfiguration<?> configuration) {
71+
val syntax = configuration.getFeatureSyntax().getArgs();
72+
// The [args] tag is optional since v4.0.0, so strip it if it's present
73+
if (key.endsWith("[/" + syntax + "]")) {
74+
key = key.substring(0, key.length() - syntax.length() - 3);
75+
}
76+
if (key.endsWith("[" + configuration.getFeatureSyntax().getArgs() + "]")) {
77+
key = key.substring(0, key.length() - syntax.length() - 2);
78+
}
79+
return key;
80+
}
81+
}

core/src/test/java/com/rexcantor64/triton/language/parser/AdventureParserTest.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,23 +1182,6 @@ public void testSplitComponentWithSingleNonTextComponentWithRepeatedIndexes() {
11821182
}
11831183
}
11841184

1185-
@Test
1186-
public void testGetPatternIndexArray() {
1187-
String input = "Lorem ipsum [tag]dolor [tag]sit[/tag] amet[/tag], [tag2]consectetur[/tag2] [tag]adipiscing elit[/tag]. Nullam posuere.";
1188-
1189-
List<Integer[]> result = parser.getPatternIndexArray(input, "tag");
1190-
1191-
List<Integer[]> expected = Arrays.asList(
1192-
new Integer[]{12, 48, 17, 42},
1193-
new Integer[]{75, 101, 80, 95}
1194-
);
1195-
1196-
assertEquals(expected.size(), result.size());
1197-
for (int i = 0; i < expected.size(); i++) {
1198-
assertArrayEquals(expected.get(i), result.get(i));
1199-
}
1200-
}
1201-
12021185
@Test
12031186
public void testGetStyleOfFirstStyle() {
12041187
Component comp = Component.text()
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.rexcantor64.triton.utils;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import java.util.Arrays;
6+
import java.util.List;
7+
8+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
9+
import static org.junit.jupiter.api.Assertions.assertEquals;
10+
11+
public class ParserUtilsTest {
12+
13+
@Test
14+
public void testGetPatternIndexArray() {
15+
String input = "Lorem ipsum [tag]dolor [tag]sit[/tag] amet[/tag], [tag2]consectetur[/tag2] [tag]adipiscing elit[/tag]. Nullam posuere.";
16+
17+
List<Integer[]> result = ParserUtils.getPatternIndexArray(input, "tag");
18+
19+
List<Integer[]> expected = Arrays.asList(
20+
new Integer[]{12, 48, 17, 42},
21+
new Integer[]{75, 101, 80, 95}
22+
);
23+
24+
assertEquals(expected.size(), result.size());
25+
for (int i = 0; i < expected.size(); i++) {
26+
assertArrayEquals(expected.get(i), result.get(i));
27+
}
28+
}
29+
}

triton-spigot/src/main/java/com/rexcantor64/triton/spigot/listeners/BukkitListener.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.rexcantor64.triton.Triton;
44
import com.rexcantor64.triton.language.parser.AdventureParser;
55
import com.rexcantor64.triton.spigot.SpigotTriton;
6+
import com.rexcantor64.triton.utils.ParserUtils;
67
import lombok.val;
78
import org.bukkit.event.EventHandler;
89
import org.bukkit.event.EventPriority;
@@ -57,7 +58,7 @@ public void onChat(AsyncPlayerChatEvent e) {
5758
}
5859

5960
String msg = e.getMessage();
60-
val indexes = parser().getPatternIndexArray(msg, Triton.get().getConfig().getChatSyntax().getLang());
61+
val indexes = ParserUtils.getPatternIndexArray(msg, Triton.get().getConfig().getChatSyntax().getLang());
6162
for (int i = 0; i < indexes.size(); ++i) {
6263
val index = indexes.get(i);
6364
// add a zero width space to prevent the parser from finding this placeholder

0 commit comments

Comments
 (0)