-
Notifications
You must be signed in to change notification settings - Fork 0
06) Command Parameters
You can put anything as a Command Parameter.
Note that you can pass flags to the parser as a hint. For Members and Channels, passing a flag of 1
indicates that it should only map mentions, otherwise will map mentions, ids, and names. You can either set this value programmatically with CommandParameterBuilder#setFlags
or with the @Flags
annotation.
When passing primitives to a Command, their boxed forms should be used or their Optional forms such as
Integer
, or OptionalInt
.
The parameters in a method are mapped from the first parameter to the last parameter. If one parameter is mapped from a substring in the input, that substring is considered consumed and unavailable for the next parameters.
Take the following method declaration
@Command("c")
public void myCommand(String quote, String author, Integer age) {...}
Here is some example input.
!c "The path is short" Randy 13 -> quote="The path is short", author="Randy", age=13.
!c The path is short Randy 13 -> quote="The", author="path", age=13.
!c Randy 13 "The path is short" -> quote="Randy", author="13", age=null.
Each parameter has a default width of 1 meaning that they will consume exactly 1 token. If the width is set to a positive number, it will consume exactly that many number of tokens otherwise it is set to null. If the width is set to 0, It will try all combination of contiguous tokens until it matches. If the width is set to a negative number, It will only try the largest combination of contiguous tokens.
The index of a parameter is by default 0
. This is the default behavior where it will attempt to map the argument at each index. If the index is set, It will attempt to parse that token where the index of the first token is 0. If the index is out of bounds (larger than the number of arguments passed in the event), the parameter will be passed null
. If the index is negative, it will count backwards from the last argument where the last argument is -1
.
If a command requires a parameter in order to execute, you can do CommandParameterBuilder#setRequired
or @Required
. If the parameter could not be mapped from the arguments passed, the command will not be executed. If you would like to set some action to be run when an argument is missing you can use CommandParameterBuilder#setOnAbsentArgument
which takes in a AbsentArgumentHandler
which is a consumer that takes in the CommandEvent
and the CommandParameter
which was not found. There also exists an annotation @HandleAbsentArgument
which takes in a class that extends AbsentArgumentHandler
.
@Command("ex")
@Name("example")
public String exampleCommand(@Required @Index(-1) Integer lint,
@Index(3) String third,
@Width(0) String start) {
return "lint=" + lint +
", third=" + third +
", start=" + start;
}
@ConfigureCommand("example")
public static void configureCommand(CommandHandleBuilder command) {
command.getParameter(0)
.setOnAbsentArgument( (event, param) -> {
event.replyFormat("Error: required [%s] but not found", param.getName())});
}
"!ex hello 1" -> "lint=1, third=null, start=hello"
"!ex hhel lo 3i wo 6" -> "lint=6, third=3i, start=hhel lo"
"!ex is i2noi 2i4 sz" -> "Error: required [arg0] but not found"
//using 'javac -parameters'
"!ex is i2noi 2i4 sz" -> "Error: required [lint] but not found"
When using Gradle, you can use -parameters with the following
tasks.withType(JavaCompile) {
options.compilerArgs << '-parameters'
}
Supported Collection Types
- Stream
- List
- Queue
- Deque
How a collection works is that it's generic parameter is used to map as many arguments as possible. Specifying the contiguous property specifies whether the arguments must be adjacent to one another.
public void test(List<Integer> ints, List<String> strings) {...}
"a b 3 d e 5" -> ints={3, 5}, strings={"a", "b", "d", "e"}
//where ints is contiguous
-> ints={3}, strings={"a", "b", "d", "e", "5"}
//where strings is contiguous
-> ints={3, 5}, strings={"a", "b"}
Here is an example.
BreadBotClient bread = new BreadBotClientBuilder()
.registerParameterTypeFlagless(
MathCommand.Operator.class, //type
null, //optional predicate to test for type
arg -> { //mapper
switch (arg.getArgument()) {
case "+":
return new MathCommand.AddOperator();
case "-":
return new MathCommand.SubtractOperator();
case "/":
return new MathCommand.DivideOperator();
case "*":
return new MathCommand.MultiplyOperator();
default:
throw new RuntimeException();
}
})
.addCommand(MathCommand.class)
.build();
...
public class MathCommand {
@MainCommand
@Description("This command can only use the 4 basic operators" +
"and evaluates expressions left to right" +
"disregarding any order of operations")
public String math(CommandEvent event,
Deque<Double> operands,
Deque<Operator> operators) {
if (operands.size() != operators.size() + 1) {
return "invalid";
} else {
while (!operators.isEmpty()) {
Double op1 = operands.pop();
Double op2 = operands.pop();
Operator o = operators.pop();
operands.push(o.calculate(op1, op2));
}
}
return String.valueOf(operands.pop());
}
public static abstract class Operator {
public abstract double calculate(double op1, double op2);
}
public static class AddOperator extends Operator {
@Override
public double calculate(double op1, double op2) {
return op1 + op2;
}
}
public static class SubtractOperator extends Operator {
@Override
public double calculate(double op1, double op2) {
return op1 - op2;
}
}
public static class MultiplyOperator extends Operator {
@Override
public double calculate(double op1, double op2) {
return op1 * op2;
}
}
public static class DivideOperator extends Operator {
@Override
public double calculate(double op1, double op2) {
return op1 / op2;
}
}
}