diff --git a/bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/CommandCommand.java b/bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/CommandCommand.java index bdd9e9d..3a39882 100644 --- a/bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/CommandCommand.java +++ b/bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/CommandCommand.java @@ -59,7 +59,7 @@ public int run(CommandContext context) throws CommandSyntaxException { .max(Comparator.comparing(ParseMatch::getPriority)) .orElseThrow(IllegalStateException::new); - return executionHandler.handleExecution(executable.execute()); + return executionHandler.handleExecution(executable.getContext(), executable.execute()); } } diff --git a/bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/CommandExecutionHandler.java b/bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/CommandExecutionHandler.java index 94d4fa7..e260954 100644 --- a/bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/CommandExecutionHandler.java +++ b/bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/CommandExecutionHandler.java @@ -30,7 +30,7 @@ public interface CommandExecutionHandler { - int handleExecution(@Nullable T result) throws CommandSyntaxException; + int handleExecution(C context, @Nullable T result) throws CommandSyntaxException; int handleParseFailure(ParseResult parseResult) throws CommandSyntaxException; diff --git a/bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/DefaultExecutionHandler.java b/bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/DefaultExecutionHandler.java index 7399d97..1d2a4bc 100644 --- a/bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/DefaultExecutionHandler.java +++ b/bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/DefaultExecutionHandler.java @@ -34,7 +34,7 @@ public class DefaultExecutionHandler implements CommandExecutionHandler { @Override - public int handleExecution(T result) { + public int handleExecution(C context, T result) { if (result instanceof Number) return ((Number) result).intValue(); diff --git a/bluecommands-core/src/main/java/de/bluecolored/bluecommands/ArgumentCommand.java b/bluecommands-core/src/main/java/de/bluecolored/bluecommands/ArgumentCommand.java index 2a96728..11fdec7 100644 --- a/bluecommands-core/src/main/java/de/bluecolored/bluecommands/ArgumentCommand.java +++ b/bluecommands-core/src/main/java/de/bluecolored/bluecommands/ArgumentCommand.java @@ -26,7 +26,6 @@ import de.bluecolored.bluecommands.parsers.ArgumentParser; -import java.util.Collection; import java.util.List; public class ArgumentCommand extends Command { diff --git a/bluecommands-core/src/main/java/de/bluecolored/bluecommands/Command.java b/bluecommands-core/src/main/java/de/bluecolored/bluecommands/Command.java index 4134849..14d8122 100644 --- a/bluecommands-core/src/main/java/de/bluecolored/bluecommands/Command.java +++ b/bluecommands-core/src/main/java/de/bluecolored/bluecommands/Command.java @@ -58,6 +58,10 @@ public Collection> getSubCommands() { return subCommands; } + public ParseResult parse(C context, String input) { + return parse(context, new InputReader(input)); + } + public ParseResult parse(C context, InputReader input) { ParseData stack = new ParseData<>(context, input); parse(stack); @@ -114,6 +118,7 @@ private boolean isSubTreeOptional() { return true; } + @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean isTreeOptional() { long now = System.currentTimeMillis(); if (lastTreeOptionalTime < now - 1000) { diff --git a/bluecommands-core/src/main/java/de/bluecolored/bluecommands/annotations/ParserType.java b/bluecommands-core/src/main/java/de/bluecolored/bluecommands/annotations/ParserType.java index 35c1e87..cdd4640 100644 --- a/bluecommands-core/src/main/java/de/bluecolored/bluecommands/annotations/ParserType.java +++ b/bluecommands-core/src/main/java/de/bluecolored/bluecommands/annotations/ParserType.java @@ -35,6 +35,7 @@ @Retention(RetentionPolicy.RUNTIME) public @interface ParserType { - Class> value(); + @SuppressWarnings("rawtypes") + Class value(); } diff --git a/bluecommands-core/src/test/java/de/bluecolored/bluecommands/BlueCommandsTest.java b/bluecommands-core/src/test/java/de/bluecolored/bluecommands/BlueCommandsTest.java new file mode 100644 index 0000000..d064281 --- /dev/null +++ b/bluecommands-core/src/test/java/de/bluecolored/bluecommands/BlueCommandsTest.java @@ -0,0 +1,211 @@ +package de.bluecolored.bluecommands; + +import de.bluecolored.bluecommands.annotations.Argument; +import de.bluecolored.bluecommands.annotations.Command; +import de.bluecolored.bluecommands.annotations.ParserType; +import de.bluecolored.bluecommands.parsers.ArgumentParser; +import de.bluecolored.bluecommands.parsers.SimpleArgumentParser; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; + +public class BlueCommandsTest { + + private de.bluecolored.bluecommands.Command commands; + + @BeforeEach + public void init() { + BlueCommands blueCommands = new BlueCommands<>(); + commands = blueCommands.createCommand(this); + } + + @Test + public void testBasicCommand() { + var result = commands.parse(null, "test arg1 arg2"); + assertEquals(1, result.getMatches().size()); + + var match = result.getMatches().iterator().next(); + assertNull(match.getContext()); + var expected = new HashMap<>(); + expected.put("with", "arg1"); + expected.put("some", null); + expected.put("arguments", "arg2"); + assertEquals(expected, match.getArguments()); + assertEquals(4, match.getCommandStack().size()); + + var stack1 = match.getCommandStack().get(0); + assertEquals(0, stack1.getPosition()); + assertInstanceOf(LiteralCommand.class, stack1.getCommand()); + assertNull(stack1.getValue()); + + var stack2 = match.getCommandStack().get(1); + assertEquals(5, stack2.getPosition()); + assertInstanceOf(ArgumentCommand.class, stack2.getCommand()); + assertEquals("arg1", stack2.getValue()); + + var stack3 = match.getCommandStack().get(2); + assertEquals(10, stack3.getPosition()); + assertInstanceOf(ArgumentCommand.class, stack3.getCommand()); + assertNull(stack3.getValue()); + + var stack4 = match.getCommandStack().get(3); + assertEquals(10, stack4.getPosition()); + assertInstanceOf(ArgumentCommand.class, stack4.getCommand()); + assertEquals("arg2", stack4.getValue()); + } + + @Test + public void testSuggestionWithTrailingSpaceStart() { + var result = commands.parse(null, "test "); + assertEquals(Set.of( + "suggestion1_1", "suggestion1_2", + "suggestion4_1", "suggestion4_2" + ), allSuggestions(result)); + } + + @Test + public void testSuggestionWithoutTrailingSpaceBeforeOptional() { + var result = commands.parse(null, "test arg1"); + assertEquals(Set.of( + "suggestion1_1", "suggestion1_2", + "suggestion4_1", "suggestion4_2" + ), allSuggestions(result)); + } + + @Test + public void testSuggestionWithTrailingSpaceOptional() { + var result = commands.parse(null, "test arg1 "); + assertEquals(Set.of( + "suggestion2_1", "suggestion2_2", + "suggestion3_1", "suggestion3_2" + ), allSuggestions(result)); + } + + @Test + public void testSuggestionWithoutTrailingSpace() { + var result = commands.parse(null, "test arg1 arg2"); + assertEquals(Set.of( + "suggestion2_1", "suggestion2_2", + "suggestion3_1", "suggestion3_2" + ), allSuggestions(result)); + } + + @Test + public void testSuggestionWithTrailingSpace() { + var result = commands.parse(null, "test arg1 arg2 "); + assertEquals(Set.of( + "suggestion3_1", "suggestion3_2" + ), allSuggestions(result)); + } + + private static Set allSuggestions(ParseResult result) { + return result.getFailures().stream() + .map(ParseFailure::getSuggestions) + .flatMap(List::stream) + .map(Suggestion::getString) + .collect(Collectors.toSet()); + } + + @Command("test [some] ") + public void testWithArgs( + @ParserType(StringWithSuggestions.class) @Argument("with") String with, + @ParserType(StringWithSuggestions2.class) @Argument("some") String some, + @ParserType(StringWithSuggestions3.class) @Argument("arguments") String arguments + ) {} + + @Command("test ") + public void testWithArgs( + @ParserType(StringWithSuggestions4.class) @Argument("single-argument") String singleArgument + ) {} + + public static class StringWithSuggestions extends SimpleArgumentParser implements ArgumentParser { + + public StringWithSuggestions() { + super(true, false); + } + + @Override + public String parse(C context, String string) throws CommandParseException { + return string; + } + + @Override + public List suggest(C context, InputReader input) { + return List.of( + new SimpleSuggestion("suggestion1_1"), + new SimpleSuggestion("suggestion1_2") + ); + } + + } + + public static class StringWithSuggestions2 extends SimpleArgumentParser { + + public StringWithSuggestions2() { + super(true, false); + } + + @Override + public String parse(C context, String string) throws CommandParseException { + return string; + } + + @Override + public List suggest(C context, InputReader input) { + return List.of( + new SimpleSuggestion("suggestion2_1"), + new SimpleSuggestion("suggestion2_2") + ); + } + + } + + public static class StringWithSuggestions3 extends SimpleArgumentParser { + + public StringWithSuggestions3() { + super(true, false); + } + + @Override + public String parse(C context, String string) throws CommandParseException { + return string; + } + + @Override + public List suggest(C context, InputReader input) { + return List.of( + new SimpleSuggestion("suggestion3_1"), + new SimpleSuggestion("suggestion3_2") + ); + } + + } + + public static class StringWithSuggestions4 extends SimpleArgumentParser { + + public StringWithSuggestions4() { + super(true, false); + } + + @Override + public String parse(C context, String string) throws CommandParseException { + return string; + } + + @Override + public List suggest(C context, InputReader input) { + return List.of( + new SimpleSuggestion("suggestion4_1"), + new SimpleSuggestion("suggestion4_2") + ); + } + + } + +}