diff --git a/commands-core/src/main/java/com/intellectualsites/commands/CommandTree.java b/commands-core/src/main/java/com/intellectualsites/commands/CommandTree.java index 53cf4858..c70aac0b 100644 --- a/commands-core/src/main/java/com/intellectualsites/commands/CommandTree.java +++ b/commands-core/src/main/java/com/intellectualsites/commands/CommandTree.java @@ -29,7 +29,7 @@ import com.intellectualsites.commands.context.CommandContext; import com.intellectualsites.commands.exceptions.InvalidSyntaxException; import com.intellectualsites.commands.exceptions.NoSuchCommandException; import com.intellectualsites.commands.internal.CommandRegistrationHandler; -import com.intellectualsites.commands.parser.ComponentParseResult; +import com.intellectualsites.commands.components.parser.ComponentParseResult; import com.intellectualsites.commands.sender.CommandSender; import javax.annotation.Nonnull; @@ -85,7 +85,7 @@ public class CommandTree { private Optional> parseCommand(@Nonnull final CommandContext commandContext, @Nonnull final Queue commandQueue, - @Nonnull final Node> root) throws NoSuchCommandException { + @Nonnull final Node> root) { if (!this.isPermitted(commandContext.getCommandSender(), root)) { /* TODO: Send not allowed */ throw new RuntimeException("Nope!"); diff --git a/commands-core/src/main/java/com/intellectualsites/commands/components/CommandComponent.java b/commands-core/src/main/java/com/intellectualsites/commands/components/CommandComponent.java index a4463198..68dac4ce 100644 --- a/commands-core/src/main/java/com/intellectualsites/commands/components/CommandComponent.java +++ b/commands-core/src/main/java/com/intellectualsites/commands/components/CommandComponent.java @@ -24,7 +24,7 @@ package com.intellectualsites.commands.components; import com.intellectualsites.commands.Command; -import com.intellectualsites.commands.parser.ComponentParser; +import com.intellectualsites.commands.components.parser.ComponentParser; import com.intellectualsites.commands.sender.CommandSender; import javax.annotation.Nonnull; @@ -38,6 +38,7 @@ import java.util.regex.Pattern; * @param Command sender type * @param The type that the component parses into */ +@SuppressWarnings("unused") public class CommandComponent implements Comparable> { private static final Pattern NAME_PATTERN = Pattern.compile("[A-Za-z0-9]+"); @@ -63,7 +64,7 @@ public class CommandComponent implements Comparable< private Command owningCommand; - CommandComponent(final boolean required, @Nonnull final String name, + public CommandComponent(final boolean required, @Nonnull final String name, @Nonnull final ComponentParser parser) { this.required = required; this.name = Objects.requireNonNull(name, "Name may not be null"); @@ -78,7 +79,7 @@ public class CommandComponent implements Comparable< * * @param clazz Argument class * @param Command sender type - * @param Argument Type + * @param Argument Type. Used to make the compiler happy. * @return Component builder */ @Nonnull @@ -185,13 +186,13 @@ public class CommandComponent implements Comparable< * @param Command sender type * @param Component value type */ - public static final class Builder { + public static class Builder { - private String name; - private boolean required = true; - private ComponentParser parser; + protected String name; + protected boolean required = true; + protected ComponentParser parser; - private Builder() { + protected Builder() { } /** diff --git a/commands-core/src/main/java/com/intellectualsites/commands/components/StaticComponent.java b/commands-core/src/main/java/com/intellectualsites/commands/components/StaticComponent.java index 1d835986..19547b57 100644 --- a/commands-core/src/main/java/com/intellectualsites/commands/components/StaticComponent.java +++ b/commands-core/src/main/java/com/intellectualsites/commands/components/StaticComponent.java @@ -24,8 +24,8 @@ package com.intellectualsites.commands.components; import com.intellectualsites.commands.context.CommandContext; -import com.intellectualsites.commands.parser.ComponentParseResult; -import com.intellectualsites.commands.parser.ComponentParser; +import com.intellectualsites.commands.components.parser.ComponentParseResult; +import com.intellectualsites.commands.components.parser.ComponentParser; import com.intellectualsites.commands.sender.CommandSender; import javax.annotation.Nonnull; diff --git a/commands-core/src/main/java/com/intellectualsites/commands/parser/ComponentParseResult.java b/commands-core/src/main/java/com/intellectualsites/commands/components/parser/ComponentParseResult.java similarity index 98% rename from commands-core/src/main/java/com/intellectualsites/commands/parser/ComponentParseResult.java rename to commands-core/src/main/java/com/intellectualsites/commands/components/parser/ComponentParseResult.java index bb203dc0..0fd57837 100644 --- a/commands-core/src/main/java/com/intellectualsites/commands/parser/ComponentParseResult.java +++ b/commands-core/src/main/java/com/intellectualsites/commands/components/parser/ComponentParseResult.java @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // -package com.intellectualsites.commands.parser; +package com.intellectualsites.commands.components.parser; import javax.annotation.Nonnull; import java.util.Optional; diff --git a/commands-core/src/main/java/com/intellectualsites/commands/parser/ComponentParser.java b/commands-core/src/main/java/com/intellectualsites/commands/components/parser/ComponentParser.java similarity index 97% rename from commands-core/src/main/java/com/intellectualsites/commands/parser/ComponentParser.java rename to commands-core/src/main/java/com/intellectualsites/commands/components/parser/ComponentParser.java index 9523ad1a..36f2da61 100644 --- a/commands-core/src/main/java/com/intellectualsites/commands/parser/ComponentParser.java +++ b/commands-core/src/main/java/com/intellectualsites/commands/components/parser/ComponentParser.java @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // -package com.intellectualsites.commands.parser; +package com.intellectualsites.commands.components.parser; import com.intellectualsites.commands.context.CommandContext; import com.intellectualsites.commands.sender.CommandSender; diff --git a/commands-core/src/main/java/com/intellectualsites/commands/components/standard/ByteComponent.java b/commands-core/src/main/java/com/intellectualsites/commands/components/standard/ByteComponent.java new file mode 100644 index 00000000..cd8cc7fd --- /dev/null +++ b/commands-core/src/main/java/com/intellectualsites/commands/components/standard/ByteComponent.java @@ -0,0 +1,170 @@ +// +// MIT License +// +// Copyright (c) 2020 IntellectualSites +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package com.intellectualsites.commands.components.standard; + +import com.intellectualsites.commands.components.CommandComponent; +import com.intellectualsites.commands.components.parser.ComponentParseResult; +import com.intellectualsites.commands.components.parser.ComponentParser; +import com.intellectualsites.commands.context.CommandContext; +import com.intellectualsites.commands.exceptions.parsing.NumberParseException; +import com.intellectualsites.commands.sender.CommandSender; + +import javax.annotation.Nonnull; +import java.util.Queue; + +@SuppressWarnings("unused") +public class ByteComponent extends CommandComponent { + + private final byte min; + private final byte max; + + private ByteComponent(final boolean required, @Nonnull final String name, final byte min, final byte max) { + super(required, name, new ByteParser<>(min, max)); + this.min = min; + this.max = max; + } + + @Nonnull + public static Builder newBuilder() { + return new Builder<>(); + } + + @Nonnull + public static CommandComponent required(@Nonnull final String name) { + return ByteComponent.newBuilder().named(name).asRequired().build(); + } + + @Nonnull + public static CommandComponent optional(@Nonnull final String name) { + return ByteComponent.newBuilder().named(name).asOptional().build(); + } + + + public static final class Builder extends CommandComponent.Builder { + + private byte min = Byte.MIN_VALUE; + private byte max = Byte.MAX_VALUE; + + @Nonnull + public Builder withMin(final byte min) { + this.min = min; + return this; + } + + @Nonnull + public Builder withMax(final byte max) { + this.max = max; + return this; + } + + @Nonnull + @Override + public ByteComponent build() { + return new ByteComponent<>(this.required, this.name, this.min, this.max); + } + + } + + + /** + * Get the minimum accepted byteeger that could have been parsed + * + * @return Minimum byteeger + */ + public byte getMin() { + return this.min; + } + + /** + * Get the maximum accepted byteeger that could have been parsed + * + * @return Maximum byteeger + */ + public byte getMax() { + return this.max; + } + + + private static final class ByteParser implements ComponentParser { + + private final byte min; + private final byte max; + + public ByteParser(final byte min, final byte max) { + this.min = min; + this.max = max; + } + + @Nonnull + @Override + public ComponentParseResult parse( + @Nonnull final CommandContext commandContext, + @Nonnull final Queue inputQueue) { + final String input = inputQueue.peek(); + if (input == null) { + return ComponentParseResult.failure(new NullPointerException("No input was provided")); + } + try { + final byte value = Byte.parseByte(input); + if (value < this.min || value > this.max) { + return ComponentParseResult.failure( + new ByteParseException(input, + this.min, + this.max)); + } + return ComponentParseResult.success(value); + } catch (final Exception e) { + return ComponentParseResult.failure( + new ByteParseException(input, this.min, + this.max)); + } + } + + } + + + public static final class ByteParseException extends NumberParseException { + + public ByteParseException(@Nonnull final String input, final byte min, final byte max) { + super(input, min, max); + } + + @Override + public boolean hasMin() { + return this.getMin().byteValue() == Byte.MIN_VALUE; + } + + @Override + public boolean hasMax() { + return this.getMax().byteValue() == Byte.MAX_VALUE; + } + + @Override + public String getNumberType() { + return "byte"; + } + + } + +} diff --git a/commands-core/src/main/java/com/intellectualsites/commands/components/standard/IntegerComponent.java b/commands-core/src/main/java/com/intellectualsites/commands/components/standard/IntegerComponent.java new file mode 100644 index 00000000..5149689b --- /dev/null +++ b/commands-core/src/main/java/com/intellectualsites/commands/components/standard/IntegerComponent.java @@ -0,0 +1,160 @@ +// +// MIT License +// +// Copyright (c) 2020 IntellectualSites +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package com.intellectualsites.commands.components.standard; + +import com.intellectualsites.commands.components.CommandComponent; +import com.intellectualsites.commands.components.parser.ComponentParseResult; +import com.intellectualsites.commands.components.parser.ComponentParser; +import com.intellectualsites.commands.context.CommandContext; +import com.intellectualsites.commands.exceptions.parsing.NumberParseException; +import com.intellectualsites.commands.sender.CommandSender; + +import javax.annotation.Nonnull; +import java.util.Queue; + +@SuppressWarnings("unused") +public class IntegerComponent extends CommandComponent { + + private final int min; + private final int max; + + private IntegerComponent(final boolean required, @Nonnull final String name, final int min, final int max) { + super(required, name, new IntegerParser<>(min, max)); + this.min = min; + this.max = max; + } + + @Nonnull public static Builder newBuilder() { + return new Builder<>(); + } + + @Nonnull public static CommandComponent required(@Nonnull final String name) { + return IntegerComponent.newBuilder().named(name).asRequired().build(); + } + + @Nonnull public static CommandComponent optional(@Nonnull final String name) { + return IntegerComponent.newBuilder().named(name).asOptional().build(); + } + + + public static final class Builder extends CommandComponent.Builder { + + private int min = Integer.MIN_VALUE; + private int max = Integer.MAX_VALUE; + + @Nonnull public Builder withMin(final int min) { + this.min = min; + return this; + } + + @Nonnull public Builder withMax(final int max) { + this.max = max; + return this; + } + + @Nonnull + @Override + public IntegerComponent build() { + return new IntegerComponent<>(this.required, this.name, this.min, this.max); + } + + } + + + /** + * Get the minimum accepted integer that could have been parsed + * + * @return Minimum integer + */ + public int getMin() { + return this.min; + } + + /** + * Get the maximum accepted integer that could have been parsed + * + * @return Maximum integer + */ + public int getMax() { + return this.max; + } + + + private static final class IntegerParser implements ComponentParser { + + private final int min; + private final int max; + + public IntegerParser(final int min, final int max) { + this.min = min; + this.max = max; + } + + @Nonnull + @Override + public ComponentParseResult parse( + @Nonnull final CommandContext commandContext, + @Nonnull final Queue inputQueue) { + final String input = inputQueue.peek(); + if (input == null) { + return ComponentParseResult.failure(new NullPointerException("No input was provided")); + } + try { + final int value = Integer.parseInt(input); + if (value < this.min || value > this.max) { + return ComponentParseResult.failure(new IntegerParseException(input, this.min, this.max)); + } + return ComponentParseResult.success(value); + } catch (final Exception e) { + return ComponentParseResult.failure(new IntegerParseException(input, this.min, this.max)); + } + } + + } + + + public static final class IntegerParseException extends NumberParseException { + + public IntegerParseException(@Nonnull final String input, final int min, final int max) { + super(input, min, max); + } + + @Override + public boolean hasMin() { + return this.getMin().intValue() == Integer.MIN_VALUE; + } + + @Override + public boolean hasMax() { + return this.getMax().intValue() == Integer.MAX_VALUE; + } + + @Override + public String getNumberType() { + return "integer"; + } + + } + +} diff --git a/commands-core/src/main/java/com/intellectualsites/commands/exceptions/parsing/NumberParseException.java b/commands-core/src/main/java/com/intellectualsites/commands/exceptions/parsing/NumberParseException.java new file mode 100644 index 00000000..31233a1a --- /dev/null +++ b/commands-core/src/main/java/com/intellectualsites/commands/exceptions/parsing/NumberParseException.java @@ -0,0 +1,86 @@ +// +// MIT License +// +// Copyright (c) 2020 IntellectualSites +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package com.intellectualsites.commands.exceptions.parsing; + +import javax.annotation.Nonnull; + +public abstract class NumberParseException extends IllegalArgumentException { + + private final String input; + private final Number min; + private final Number max; + + public NumberParseException(@Nonnull final String input, final int min, final int max) { + this.input = input; + this.min = min; + this.max = max; + } + + @Override + public String getMessage() { + if (this.hasMin() && this.hasMax()) { + return "'" + this.input + "' is not a valid " + this.getNumberType() + " in the range [" + this.min + ", " + this.max + "]"; + } else if (this.hasMin()) { + return "'" + this.input + "' is not a valid " + this.getNumberType() + " above " + this.min; + } else if (this.hasMax()) { + return "'" + this.input + "' is not a valid " + this.getNumberType() + " below " + this.max; + } else { + return String.format("'%s' is not a valid %s", this.input, this.getNumberType()); + } + } + + public abstract String getNumberType(); + + public abstract boolean hasMax(); + + public abstract boolean hasMin(); + + /** + * Get the input that failed to parse + * + * @return Input + */ + @Nonnull public String getInput() { + return this.input; + } + + /** + * Get the minimum accepted integer that could have been parsed + * + * @return Minimum integer + */ + public Number getMin() { + return this.min; + } + + /** + * Get the maximum accepted integer that could have been parsed + * + * @return Maximum integer + */ + public Number getMax() { + return this.max; + } + +} diff --git a/commands-jline/src/main/java/com/intellectualsites/commands/jline/JLineCommandManager.java b/commands-jline/src/main/java/com/intellectualsites/commands/jline/JLineCommandManager.java index b266faef..a0c8cae9 100644 --- a/commands-jline/src/main/java/com/intellectualsites/commands/jline/JLineCommandManager.java +++ b/commands-jline/src/main/java/com/intellectualsites/commands/jline/JLineCommandManager.java @@ -32,7 +32,7 @@ import com.intellectualsites.commands.exceptions.InvalidSyntaxException; import com.intellectualsites.commands.exceptions.NoSuchCommandException; import com.intellectualsites.commands.execution.CommandExecutionCoordinator; import com.intellectualsites.commands.internal.CommandRegistrationHandler; -import com.intellectualsites.commands.parser.ComponentParseResult; +import com.intellectualsites.commands.components.parser.ComponentParseResult; import org.jline.reader.Candidate; import org.jline.reader.Completer; import org.jline.reader.LineReader;