fix child command issues

This commit is contained in:
dfsek 2021-03-08 00:36:01 -07:00
parent c1b04d1772
commit a5d101ff61
2 changed files with 102 additions and 22 deletions

View File

@ -19,11 +19,14 @@ public class TerraCommandManager implements CommandManager {
@Override @Override
public void execute(String commandName, List<String> argsIn) throws CommandException { public void execute(String commandName, List<String> argsIn) throws CommandException {
execute(commands.get(commandName), new ArrayList<>(argsIn));
}
private void execute(CommandHolder commandHolder, List<String> args) throws CommandException {
List<String> ogArgs = new ArrayList<>(args);
List<String> args = new ArrayList<>(argsIn);
ExecutionState state = new ExecutionState(); ExecutionState state = new ExecutionState();
CommandHolder commandHolder = commands.get(commandName);
Class<? extends CommandTemplate> commandClass = commandHolder.clazz; Class<? extends CommandTemplate> commandClass = commandHolder.clazz;
if(!commandClass.isAnnotationPresent(Command.class)) { if(!commandClass.isAnnotationPresent(Command.class)) {
@ -38,7 +41,10 @@ public class TerraCommandManager implements CommandManager {
} }
if(commandHolder.subcommands.containsKey(args.get(0))) { if(commandHolder.subcommands.containsKey(args.get(0))) {
invoke(commandHolder.subcommands.get(args.get(0)).clazz(), state); String c = args.get(0);
args.remove(0);
execute(commandHolder.subcommands.get(c), args);
return;
} }
@ -49,7 +55,7 @@ public class TerraCommandManager implements CommandManager {
req = argument.required(); req = argument.required();
if(args.isEmpty()) { if(args.isEmpty()) {
if(req) throw new InvalidArgumentsException("Invalid arguments: " + command.usage()); if(req) throw new InvalidArgumentsException("Invalid arguments: " + ogArgs + ", usage: " + command.usage());
break; break;
} }
@ -83,16 +89,17 @@ public class TerraCommandManager implements CommandManager {
private static final class CommandHolder { private static final class CommandHolder {
private final Class<? extends CommandTemplate> clazz; private final Class<? extends CommandTemplate> clazz;
private final Map<String, Subcommand> subcommands = new HashMap<>(); private final Map<String, CommandHolder> subcommands = new HashMap<>();
private CommandHolder(Class<? extends CommandTemplate> clazz) { private CommandHolder(Class<? extends CommandTemplate> clazz) {
this.clazz = clazz; this.clazz = clazz;
if(clazz.isAnnotationPresent(Command.class)) { if(clazz.isAnnotationPresent(Command.class)) {
Command command = clazz.getAnnotation(Command.class); Command command = clazz.getAnnotation(Command.class);
for(Subcommand subcommand : command.subcommands()) { for(Subcommand subcommand : command.subcommands()) {
subcommands.put(subcommand.value(), subcommand); CommandHolder holder = new CommandHolder(subcommand.clazz());
subcommands.put(subcommand.value(), holder);
for(String alias : subcommand.aliases()) { for(String alias : subcommand.aliases()) {
subcommands.put(alias, subcommand); subcommands.put(alias, holder);
} }
} }
} }

View File

@ -6,9 +6,10 @@ import com.dfsek.terra.api.command.ExecutionState;
import com.dfsek.terra.api.command.TerraCommandManager; import com.dfsek.terra.api.command.TerraCommandManager;
import com.dfsek.terra.api.command.annotation.Argument; import com.dfsek.terra.api.command.annotation.Argument;
import com.dfsek.terra.api.command.annotation.Command; import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.Subcommand;
import com.dfsek.terra.api.command.exception.CommandException; import com.dfsek.terra.api.command.exception.CommandException;
import com.dfsek.terra.api.command.exception.InvalidArgumentsException;
import com.dfsek.terra.api.command.exception.MalformedCommandException; import com.dfsek.terra.api.command.exception.MalformedCommandException;
import com.dfsek.terra.commands.StructureCommand;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.Arrays; import java.util.Arrays;
@ -19,9 +20,14 @@ public class CommandTest {
@Test @Test
public void subcommand() throws CommandException { public void subcommand() throws CommandException {
CommandManager manager = new TerraCommandManager(); CommandManager manager = new TerraCommandManager();
manager.register("structure", StructureCommand.class); manager.register("test", DemoParentCommand.class);
manager.execute("structure", Arrays.asList("export")); manager.execute("test", Arrays.asList("subcommand1", "first", "2"));
manager.execute("test", Arrays.asList("subcommand2", "first", "2"));
manager.execute("test", Arrays.asList("s1", "first", "2", "3.4"));
manager.execute("test", Arrays.asList("s2", "first", "2"));
manager.execute("test", Arrays.asList("sub1", "first", "2", "3.4"));
manager.execute("test", Arrays.asList("sub2", "first", "2"));
} }
@Test @Test
@ -33,6 +39,18 @@ public class CommandTest {
manager.execute("test", Arrays.asList("first", "2", "3.4")); manager.execute("test", Arrays.asList("first", "2", "3.4"));
} }
@Test
public void argsBeforeFlags() throws CommandException {
CommandManager manager = new TerraCommandManager();
manager.register("test", DemoCommand.class);
try {
manager.execute("test", Arrays.asList("first", "-flag", "2"));
fail();
} catch(InvalidArgumentsException ignore) {
}
}
@Test @Test
public void requiredArgsFirst() throws CommandException { public void requiredArgsFirst() throws CommandException {
CommandManager manager = new TerraCommandManager(); CommandManager manager = new TerraCommandManager();
@ -45,30 +63,32 @@ public class CommandTest {
} }
} }
@Command(arguments = { @Command(
@Argument(value = "arg0"), arguments = {
@Argument(value = "arg1", type = int.class), @Argument(value = "arg0"),
@Argument(value = "arg2", type = double.class, required = false) @Argument(value = "arg1", type = int.class),
}) @Argument(value = "arg2", type = double.class, required = false)
})
public static final class DemoCommand implements CommandTemplate { public static final class DemoCommand implements CommandTemplate {
@Override @Override
public void execute(ExecutionState state) { public void execute(ExecutionState state) {
System.out.println(state.getArgument("arg0", String.class)); System.out.println(state.getArgument("arg0", String.class));
System.out.println(state.getArgument("arg1", String.class)); System.out.println(state.getArgument("arg1", int.class));
try { try {
System.out.println(state.getArgument("arg2", String.class)); System.out.println(state.getArgument("arg2", double.class));
} catch(IllegalArgumentException e) { } catch(IllegalArgumentException e) {
System.out.println("arg2 undefined."); System.out.println("arg2 undefined.");
} }
} }
} }
@Command(arguments = { @Command(
@Argument(value = "arg0"), arguments = {
@Argument(value = "arg2", type = double.class, required = false), // optional arguments must be last. this command is invalid. @Argument(value = "arg0"),
@Argument(value = "arg1", type = int.class) @Argument(value = "arg2", type = double.class, required = false), // optional arguments must be last. this command is invalid.
}) @Argument(value = "arg1", type = int.class)
})
public static final class DemoInvalidCommand implements CommandTemplate { public static final class DemoInvalidCommand implements CommandTemplate {
@Override @Override
@ -76,4 +96,57 @@ public class CommandTest {
throw new Error("this should never be reached"); throw new Error("this should never be reached");
} }
} }
@Command(
arguments = {
@Argument(value = "arg0"),
@Argument(value = "arg1", type = int.class),
@Argument(value = "arg2", type = double.class, required = false),
},
subcommands = {
@Subcommand(
value = "subcommand1",
aliases = {"s1", "sub1"},
clazz = DemoChildCommand.class
),
@Subcommand(
value = "subcommand2",
aliases = {"s2", "sub2"},
clazz = DemoChildCommand.class // Duplicate command intentional.
)
})
public static final class DemoParentCommand implements CommandTemplate {
@Override
public void execute(ExecutionState state) {
System.out.println("Parent command");
System.out.println(state.getArgument("arg0", String.class));
System.out.println(state.getArgument("arg1", int.class));
try {
System.out.println(state.getArgument("arg2", double.class));
} catch(IllegalArgumentException e) {
System.out.println("arg2 undefined.");
}
}
}
@Command(
arguments = {
@Argument(value = "arg0"),
@Argument(value = "arg1", type = int.class),
@Argument(value = "arg2", type = double.class, required = false),
})
public static final class DemoChildCommand implements CommandTemplate {
@Override
public void execute(ExecutionState state) {
System.out.println("Child command");
System.out.println(state.getArgument("arg0", String.class));
System.out.println(state.getArgument("arg1", int.class));
try {
System.out.println(state.getArgument("arg2", double.class));
} catch(IllegalArgumentException e) {
System.out.println("arg2 undefined.");
}
}
}
} }