aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWyvest <45589059+Wyvest@users.noreply.github.com>2022-06-11 12:04:07 +0700
committerWyvest <45589059+Wyvest@users.noreply.github.com>2022-06-11 12:04:07 +0700
commitc703f099e2af36335dd9906d7e531a58da80fbd0 (patch)
treef9a2c5ad0006305d5646d73ec69e2a225ea100bd /src
parent78a8a15a48b25d2fe38c01a3ddb74bb6b24fa4f4 (diff)
downloadOneConfig-c703f099e2af36335dd9906d7e531a58da80fbd0.tar.gz
OneConfig-c703f099e2af36335dd9906d7e531a58da80fbd0.tar.bz2
OneConfig-c703f099e2af36335dd9906d7e531a58da80fbd0.zip
implement tab completions
Diffstat (limited to 'src')
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/utils/commands/CommandManager.java275
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/BooleanParser.java9
2 files changed, 188 insertions, 96 deletions
diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/CommandManager.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/CommandManager.java
index 338e9a3..e0f4779 100644
--- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/CommandManager.java
+++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/CommandManager.java
@@ -9,7 +9,12 @@ import cc.polyfrost.oneconfig.libs.universal.ChatColor;
import cc.polyfrost.oneconfig.libs.universal.UChat;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
+import net.minecraft.util.BlockPos;
import net.minecraftforge.client.ClientCommandHandler;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.ImmutableTriple;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.Triple;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -25,19 +30,20 @@ import java.util.*;
public class CommandManager {
public static final CommandManager INSTANCE = new CommandManager();
private static final String NOT_FOUND_TEXT = "Command not found! Type /@ROOT_COMMAND@ help for help.";
+ private static final String TOO_MANY_PARAMETERS = "There were too many / little parameters for this command! Type /@ROOT_COMMAND@ help for help.";
private static final String METHOD_RUN_ERROR = "Error while running @ROOT_COMMAND@ method! Please report this to the developer.";
private final HashMap<Class<?>, ArgumentParser<?>> parsers = new HashMap<>();
private CommandManager() {
addParser(new StringParser());
addParser(new IntegerParser());
- addParser(new IntegerParser(), int.class);
+ addParser(new IntegerParser(), Integer.TYPE);
addParser(new DoubleParser());
- addParser(new DoubleParser(), double.class);
+ addParser(new DoubleParser(), Double.TYPE);
addParser(new FloatParser());
- addParser(new FloatParser(), float.class);
+ addParser(new FloatParser(), Float.TYPE);
addParser(new BooleanParser());
- addParser(new BooleanParser(), boolean.class);
+ addParser(new BooleanParser(), Boolean.TYPE);
}
/**
@@ -89,62 +95,7 @@ public class CommandManager {
@Override
public void processCommand(ICommandSender sender, String[] args) {
- if (args.length == 0) {
- if (!root.invokers.isEmpty()) {
- try {
- root.invokers.get(0).method.invoke(null);
- } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException |
- ExceptionInInitializerError e) {
- e.printStackTrace();
- UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + METHOD_RUN_ERROR);
- }
- }
- } else {
- if (annotation.helpCommand() && args[0].equalsIgnoreCase("help")) {
- //UChat.chat(sendHelpCommand(root));
- } else {
- List<InternalCommand.InternalCommandInvoker> commands = new ArrayList<>();
- int depth = 0;
- for (InternalCommand command : root.children) {
- int newDepth = loopThroughCommands(commands, 0, command, args, true);
- if (newDepth != -1) {
- depth = newDepth;
- break;
- }
- }
- System.out.println(depth);
- System.out.println(commands);
- if (commands.isEmpty()) {
- UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + NOT_FOUND_TEXT.replace("@ROOT_COMMAND@", annotation.value()));
- } else {
- List<CustomError> errors = new ArrayList<>();
- for (InternalCommand.InternalCommandInvoker invoker : commands) {
- try {
- List<Object> params = getParametersForInvoker(invoker, depth, args);
- if (params.size() == 1) {
- Object first = params.get(0);
- if (first instanceof CustomError) {
- errors.add((CustomError) first);
- continue;
- }
- }
- invoker.method.invoke(null, params.toArray());
- return;
- } catch (Exception e) {
- e.printStackTrace();
- UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + METHOD_RUN_ERROR);
- return;
- }
- }
- if (!errors.isEmpty()) {
- UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + "Multiple errors occurred:");
- for (CustomError error : errors) {
- UChat.chat(" " + ChatColor.RED + ChatColor.BOLD + error.message);
- }
- }
- }
- }
- }
+ handleCommand(root, annotation, args);
}
@Override
@@ -152,36 +103,152 @@ public class CommandManager {
return -1;
}
- /*/
@Override
public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {
- List<InternalCommand.InternalCommandInvoker> commands = new ArrayList<>();
- int depth = 0;
- for (InternalCommand command : root.children) {
- int newDepth = loopThroughCommands(commands, 0, command, args, false);
- if (newDepth != -1) {
- depth = newDepth;
- break;
+ return handleTabCompletion(root, args);
+ }
+ });
+ }
+ }
+
+ private void handleCommand(InternalCommand root, Command annotation, String[] args) {
+ if (args.length == 0) {
+ if (!root.invokers.isEmpty()) {
+ try {
+ root.invokers.get(0).method.invoke(null);
+ } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException |
+ ExceptionInInitializerError e) {
+ e.printStackTrace();
+ UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + METHOD_RUN_ERROR);
+ }
+ }
+ } else {
+ if (annotation.helpCommand() && args[0].equalsIgnoreCase("help")) {
+ //UChat.chat(sendHelpCommand(root));
+ } else {
+ List<InternalCommand.InternalCommandInvoker> commands = new ArrayList<>();
+ int depth = 0;
+ for (InternalCommand command : root.children) {
+ int newDepth = loopThroughCommands(commands, 0, command, args);
+ if (newDepth != -1) {
+ depth = newDepth;
+ break;
+ }
+ }
+ if (commands.isEmpty()) {
+ if (depth == -2) {
+ UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + TOO_MANY_PARAMETERS.replace("@ROOT_COMMAND@", annotation.value()));
+ } else {
+ UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + NOT_FOUND_TEXT.replace("@ROOT_COMMAND@", annotation.value()));
+ }
+ } else {
+ List<CustomError> errors = new ArrayList<>();
+ for (InternalCommand.InternalCommandInvoker invoker : commands) {
+ try {
+ List<Object> params = getParametersForInvoker(invoker, depth, args);
+ if (params.size() == 1) {
+ Object first = params.get(0);
+ if (first instanceof CustomError) {
+ errors.add((CustomError) first);
+ continue;
+ }
+ }
+ invoker.method.invoke(null, params.toArray());
+ return;
+ } catch (Exception e) {
+ e.printStackTrace();
+ UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + METHOD_RUN_ERROR);
+ return;
}
}
- System.out.println(depth);
- System.out.println(commands);
- if (!commands.isEmpty()) {
- for (InternalCommand.InternalCommandInvoker invoker : commands) {
- try {
- List<Object> params = getParametersForInvoker(invoker, depth, args);
- invoker.method.invoke(null, params.toArray());
- return;
- } catch (Exception ignored) {
+ //noinspection ConstantConditions
+ if (!errors.isEmpty()) {
+ UChat.chat(ChatColor.RED.toString() + ChatColor.BOLD + "Multiple errors occurred:");
+ for (CustomError error : errors) {
+ UChat.chat(" " + ChatColor.RED + ChatColor.BOLD + error.message);
+ }
+ }
+ }
+ }
+ }
+ }
+ private List<String> handleTabCompletion(InternalCommand root, String[] args) {
+ try {
+ Set<Pair<InternalCommand.InternalCommandInvoker, Integer>> commands = new HashSet<>();
+ for (InternalCommand command : root.children) {
+ loopThroughCommandsTab(commands, 0, command, args);
+ }
+ if (!commands.isEmpty()) {
+ List<Triple<InternalCommand.InternalCommandInvoker, Integer, Integer>> validCommands = new ArrayList<>(); // command, depth, and all processed params
+ for (Pair<InternalCommand.InternalCommandInvoker, Integer> pair : commands) {
+ InternalCommand.InternalCommandInvoker invoker = pair.getLeft();
+ int depth = pair.getRight();
+ int currentParam = 0;
+ boolean failed = false;
+ while (args.length - depth > 1) {
+ Parameter param = invoker.method.getParameters()[currentParam];
+ if (param.isAnnotationPresent(Greedy.class) && currentParam + 1 != invoker.parameterTypes.length) {
+ failed = true;
+ break;
+ }
+ ArgumentParser<?> parser = parsers.get(param.getType());
+ if (parser == null) {
+ failed = true;
+ break;
+ }
+ try {
+ Arguments arguments = new Arguments(Arrays.copyOfRange(args, depth, args.length), param.isAnnotationPresent(Greedy.class));
+ if (parser.parse(arguments) != null) {
+ depth += arguments.getPosition();
+ currentParam++;
+ } else {
+ failed = true;
+ break;
}
+ } catch (Exception e) {
+ failed = true;
+ break;
}
}
+ if (!failed) {
+ validCommands.add(new ImmutableTriple<>(pair.getLeft(), depth, currentParam));
+ }
}
+ if (!validCommands.isEmpty()) {
+ Set<String> completions = new HashSet<>();
+ for (Triple<InternalCommand.InternalCommandInvoker, Integer, Integer> valid : validCommands) {
+ if (valid.getMiddle() == args.length) {
+ completions.add(valid.getLeft().name);
+ completions.addAll(Arrays.asList(valid.getLeft().aliases));
+ continue;
+ }
+ if (valid.getRight() + 1 > valid.getLeft().parameterTypes.length) continue;
+ Parameter param = valid.getLeft().method.getParameters()[valid.getRight()];
+ if (param.isAnnotationPresent(Greedy.class) && valid.getRight() + 1 != valid.getLeft().parameterTypes.length) {
+ continue;
+ }
+ ArgumentParser<?> parser = parsers.get(param.getType());
+ if (parser == null) {
+ continue;
+ }
+ try {
+ Arguments arguments = new Arguments(Arrays.copyOfRange(args, valid.getMiddle(), args.length), param.isAnnotationPresent(Greedy.class));
+ List<String> possibleCompletions = parser.complete(arguments, param);
+ if (possibleCompletions != null) {
+ completions.addAll(possibleCompletions);
+ }
+ } catch (Exception ignored) {
+
+ }
+ }
+ return new ArrayList<>(completions);
+ }
+ }
+ } catch (Exception ignored) {
- */
- });
}
+ return null;
}
private List<Object> getParametersForInvoker(InternalCommand.InternalCommandInvoker invoker, int depth, String[] args) {
@@ -190,7 +257,7 @@ public class CommandManager {
int currentParam = 0;
while (processed < args.length) {
Parameter param = invoker.method.getParameters()[currentParam];
- if (param.isAnnotationPresent(Greedy.class) && currentParam + 1 != invoker.method.getParameterCount()) {
+ if (param.isAnnotationPresent(Greedy.class) && currentParam + 1 != invoker.parameterTypes.length) {
return Collections.singletonList(new CustomError("Parsing failed: Greedy parameter must be the last one."));
}
ArgumentParser<?> parser = parsers.get(param.getType());
@@ -218,36 +285,50 @@ public class CommandManager {
return parameters;
}
- private int loopThroughCommands(List<InternalCommand.InternalCommandInvoker> commands, int depth, InternalCommand command, String[] args, boolean checkParams) {
+ private int loopThroughCommands(List<InternalCommand.InternalCommandInvoker> commands, int depth, InternalCommand command, String[] args) {
int nextDepth = depth + 1;
- if (command.isEqual(args[depth])) {
+ boolean thatOneSpecialError = false;
+ if (command.isValid(args[depth], false)) {
for (InternalCommand child : command.children) {
- if (args.length > nextDepth && child.isEqual(args[nextDepth])) {
- int result = loopThroughCommands(commands, nextDepth, child, args, checkParams);
- if (result != -1) {
+ if (args.length > nextDepth && child.isValid(args[nextDepth], false)) {
+ int result = loopThroughCommands(commands, nextDepth, child, args);
+ if (result > -1) {
return result;
+ } else if (result == -2) {
+ thatOneSpecialError = true;
}
}
}
boolean added = false;
for (InternalCommand.InternalCommandInvoker invoker : command.invokers) {
- if (!checkParams || args.length - nextDepth == invoker.method.getParameterCount()) {
+ if (args.length - nextDepth == invoker.parameterTypes.length) {
commands.add(invoker);
added = true;
+ } else {
+ thatOneSpecialError = true;
}
}
if (added) {
return nextDepth;
}
- } else {
- for (InternalCommand child : command.children) {
- int childDepth = loopThroughCommands(commands, nextDepth, child, args, checkParams);
- if (childDepth != -1) {
- return childDepth;
+ }
+ return thatOneSpecialError ? -2 : -1;
+ }
+
+ private void loopThroughCommandsTab(Set<Pair<InternalCommand.InternalCommandInvoker, Integer>> commands, int depth, InternalCommand command, String[] args) {
+ int nextDepth = depth + 1;
+ if (command.isValid(args[depth], args.length == nextDepth)) {
+ if (args.length != nextDepth) {
+ for (InternalCommand child : command.children) {
+ if (child.isValid(args[nextDepth], args.length == nextDepth + 1)) {
+ loopThroughCommandsTab(commands, nextDepth, child, args);
+ }
}
}
+ for (InternalCommand.InternalCommandInvoker invoker : command.invokers) {
+ commands.add(new ImmutablePair<>(invoker, nextDepth));
+ }
}
- return -1;
}
private void addToInvokers(Class<?>[] classes, InternalCommand parent) {
@@ -289,12 +370,15 @@ public class CommandManager {
this.parent = parent;
}
- public boolean isEqual(String name) {
- if (this.name.equals(name)) {
+ public boolean isValid(String name, boolean tabCompletion) {
+ String lowerCaseName = this.name.toLowerCase(Locale.ENGLISH);
+ String lowerCaseOtherName = name.toLowerCase(Locale.ENGLISH);
+ if (!tabCompletion ? lowerCaseName.equals(lowerCaseOtherName) : lowerCaseName.startsWith(lowerCaseOtherName)) {
return true;
} else {
for (String alias : aliases) {
- if (alias.equals(name)) {
+ String lowerCaseAlias = alias.toLowerCase(Locale.ENGLISH);
+ if (!tabCompletion ? lowerCaseAlias.equals(lowerCaseOtherName) : lowerCaseAlias.startsWith(lowerCaseOtherName)) {
return true;
}
}
@@ -345,3 +429,4 @@ public class CommandManager {
}
}
}
+
diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/BooleanParser.java b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/BooleanParser.java
index 7411cbe..ede83fb 100644
--- a/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/BooleanParser.java
+++ b/src/main/java/cc/polyfrost/oneconfig/utils/commands/arguments/BooleanParser.java
@@ -13,7 +13,14 @@ public class BooleanParser extends ArgumentParser<Boolean> {
@Override
public @Nullable Boolean parse(Arguments arguments) {
- return Boolean.parseBoolean(arguments.poll());
+ String next = arguments.poll();
+ if (next.equalsIgnoreCase("true")) {
+ return true;
+ } else if (next.equalsIgnoreCase("false")) {
+ return false;
+ } else {
+ return null;
+ }
}
@Override