✨ Finalize command flags
They're currently quite ugly in the help menu. this should probably be fixed, but it's not a priority issue.
This commit is contained in:
parent
549fbd1d1d
commit
782f3023fc
14 changed files with 453 additions and 76 deletions
|
|
@ -27,6 +27,8 @@ import cloud.commandframework.arguments.CommandArgument;
|
||||||
import cloud.commandframework.arguments.StaticArgument;
|
import cloud.commandframework.arguments.StaticArgument;
|
||||||
import cloud.commandframework.arguments.compound.ArgumentPair;
|
import cloud.commandframework.arguments.compound.ArgumentPair;
|
||||||
import cloud.commandframework.arguments.compound.ArgumentTriplet;
|
import cloud.commandframework.arguments.compound.ArgumentTriplet;
|
||||||
|
import cloud.commandframework.arguments.compound.FlagArgument;
|
||||||
|
import cloud.commandframework.arguments.flags.CommandFlag;
|
||||||
import cloud.commandframework.execution.CommandExecutionHandler;
|
import cloud.commandframework.execution.CommandExecutionHandler;
|
||||||
import cloud.commandframework.meta.CommandMeta;
|
import cloud.commandframework.meta.CommandMeta;
|
||||||
import cloud.commandframework.meta.SimpleCommandMeta;
|
import cloud.commandframework.meta.SimpleCommandMeta;
|
||||||
|
|
@ -39,6 +41,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -146,8 +149,13 @@ public class Command<C> {
|
||||||
@NonNull final String... aliases) {
|
@NonNull final String... aliases) {
|
||||||
final Map<@NonNull CommandArgument<C, ?>, @NonNull Description> map = new LinkedHashMap<>();
|
final Map<@NonNull CommandArgument<C, ?>, @NonNull Description> map = new LinkedHashMap<>();
|
||||||
map.put(StaticArgument.of(commandName, aliases), description);
|
map.put(StaticArgument.of(commandName, aliases), description);
|
||||||
return new Builder<>(null, commandMeta, null, map,
|
return new Builder<>(null,
|
||||||
new CommandExecutionHandler.NullCommandExecutionHandler<>(), Permission.empty());
|
commandMeta,
|
||||||
|
null,
|
||||||
|
map,
|
||||||
|
new CommandExecutionHandler.NullCommandExecutionHandler<>(),
|
||||||
|
Permission.empty(),
|
||||||
|
Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -165,8 +173,13 @@ public class Command<C> {
|
||||||
@NonNull final String... aliases) {
|
@NonNull final String... aliases) {
|
||||||
final Map<CommandArgument<C, ?>, Description> map = new LinkedHashMap<>();
|
final Map<CommandArgument<C, ?>, Description> map = new LinkedHashMap<>();
|
||||||
map.put(StaticArgument.of(commandName, aliases), Description.empty());
|
map.put(StaticArgument.of(commandName, aliases), Description.empty());
|
||||||
return new Builder<>(null, commandMeta, null, map,
|
return new Builder<>(null,
|
||||||
new CommandExecutionHandler.NullCommandExecutionHandler<>(), Permission.empty());
|
commandMeta,
|
||||||
|
null,
|
||||||
|
map,
|
||||||
|
new CommandExecutionHandler.NullCommandExecutionHandler<>(),
|
||||||
|
Permission.empty(),
|
||||||
|
Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -258,19 +271,22 @@ public class Command<C> {
|
||||||
private final Class<? extends C> senderType;
|
private final Class<? extends C> senderType;
|
||||||
private final CommandPermission commandPermission;
|
private final CommandPermission commandPermission;
|
||||||
private final CommandManager<C> commandManager;
|
private final CommandManager<C> commandManager;
|
||||||
|
private final Collection<CommandFlag<?>> flags;
|
||||||
|
|
||||||
private Builder(@Nullable final CommandManager<C> commandManager,
|
private Builder(@Nullable final CommandManager<C> commandManager,
|
||||||
@NonNull final CommandMeta commandMeta,
|
@NonNull final CommandMeta commandMeta,
|
||||||
@Nullable final Class<? extends C> senderType,
|
@Nullable final Class<? extends C> senderType,
|
||||||
@NonNull final Map<@NonNull CommandArgument<C, ?>, @NonNull Description> commandArguments,
|
@NonNull final Map<@NonNull CommandArgument<C, ?>, @NonNull Description> commandArguments,
|
||||||
@NonNull final CommandExecutionHandler<@NonNull C> commandExecutionHandler,
|
@NonNull final CommandExecutionHandler<@NonNull C> commandExecutionHandler,
|
||||||
@NonNull final CommandPermission commandPermission) {
|
@NonNull final CommandPermission commandPermission,
|
||||||
|
@NonNull final Collection<CommandFlag<?>> flags) {
|
||||||
this.commandManager = commandManager;
|
this.commandManager = commandManager;
|
||||||
this.senderType = senderType;
|
this.senderType = senderType;
|
||||||
this.commandArguments = Objects.requireNonNull(commandArguments, "Arguments may not be null");
|
this.commandArguments = Objects.requireNonNull(commandArguments, "Arguments may not be null");
|
||||||
this.commandExecutionHandler = Objects.requireNonNull(commandExecutionHandler, "Execution handler may not be null");
|
this.commandExecutionHandler = Objects.requireNonNull(commandExecutionHandler, "Execution handler may not be null");
|
||||||
this.commandPermission = Objects.requireNonNull(commandPermission, "Permission may not be null");
|
this.commandPermission = Objects.requireNonNull(commandPermission, "Permission may not be null");
|
||||||
this.commandMeta = Objects.requireNonNull(commandMeta, "Meta may not be null");
|
this.commandMeta = Objects.requireNonNull(commandMeta, "Meta may not be null");
|
||||||
|
this.flags = Objects.requireNonNull(flags, "Flags may not be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -282,8 +298,13 @@ public class Command<C> {
|
||||||
*/
|
*/
|
||||||
public @NonNull Builder<C> meta(@NonNull final String key, @NonNull final String value) {
|
public @NonNull Builder<C> meta(@NonNull final String key, @NonNull final String value) {
|
||||||
final CommandMeta commandMeta = SimpleCommandMeta.builder().with(this.commandMeta).with(key, value).build();
|
final CommandMeta commandMeta = SimpleCommandMeta.builder().with(this.commandMeta).with(key, value).build();
|
||||||
return new Builder<>(this.commandManager, commandMeta, this.senderType, this.commandArguments,
|
return new Builder<>(this.commandManager,
|
||||||
this.commandExecutionHandler, this.commandPermission);
|
commandMeta,
|
||||||
|
this.senderType,
|
||||||
|
this.commandArguments,
|
||||||
|
this.commandExecutionHandler,
|
||||||
|
this.commandPermission,
|
||||||
|
this.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -295,8 +316,13 @@ public class Command<C> {
|
||||||
* @return New builder instance using the provided command manager
|
* @return New builder instance using the provided command manager
|
||||||
*/
|
*/
|
||||||
public @NonNull Builder<C> manager(@Nullable final CommandManager<C> commandManager) {
|
public @NonNull Builder<C> manager(@Nullable final CommandManager<C> commandManager) {
|
||||||
return new Builder<>(commandManager, this.commandMeta, this.senderType, this.commandArguments,
|
return new Builder<>(commandManager,
|
||||||
this.commandExecutionHandler, this.commandPermission);
|
this.commandMeta,
|
||||||
|
this.senderType,
|
||||||
|
this.commandArguments,
|
||||||
|
this.commandExecutionHandler,
|
||||||
|
this.commandPermission,
|
||||||
|
this.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -360,8 +386,13 @@ public class Command<C> {
|
||||||
@NonNull final Description description) {
|
@NonNull final Description description) {
|
||||||
final Map<CommandArgument<C, ?>, Description> commandArgumentMap = new LinkedHashMap<>(this.commandArguments);
|
final Map<CommandArgument<C, ?>, Description> commandArgumentMap = new LinkedHashMap<>(this.commandArguments);
|
||||||
commandArgumentMap.put(argument, description);
|
commandArgumentMap.put(argument, description);
|
||||||
return new Builder<>(this.commandManager, this.commandMeta, this.senderType, commandArgumentMap,
|
return new Builder<>(this.commandManager,
|
||||||
this.commandExecutionHandler, this.commandPermission);
|
this.commandMeta,
|
||||||
|
this.senderType,
|
||||||
|
commandArgumentMap,
|
||||||
|
this.commandExecutionHandler,
|
||||||
|
this.commandPermission,
|
||||||
|
this.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -537,8 +568,13 @@ public class Command<C> {
|
||||||
* @return New builder instance using the command execution handler
|
* @return New builder instance using the command execution handler
|
||||||
*/
|
*/
|
||||||
public @NonNull Builder<C> handler(@NonNull final CommandExecutionHandler<C> commandExecutionHandler) {
|
public @NonNull Builder<C> handler(@NonNull final CommandExecutionHandler<C> commandExecutionHandler) {
|
||||||
return new Builder<>(this.commandManager, this.commandMeta, this.senderType, this.commandArguments,
|
return new Builder<>(this.commandManager,
|
||||||
commandExecutionHandler, this.commandPermission);
|
this.commandMeta,
|
||||||
|
this.senderType,
|
||||||
|
this.commandArguments,
|
||||||
|
commandExecutionHandler,
|
||||||
|
this.commandPermission,
|
||||||
|
this.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -548,8 +584,13 @@ public class Command<C> {
|
||||||
* @return New builder instance using the command execution handler
|
* @return New builder instance using the command execution handler
|
||||||
*/
|
*/
|
||||||
public @NonNull Builder<C> withSenderType(@NonNull final Class<? extends C> senderType) {
|
public @NonNull Builder<C> withSenderType(@NonNull final Class<? extends C> senderType) {
|
||||||
return new Builder<>(this.commandManager, this.commandMeta, senderType, this.commandArguments,
|
return new Builder<>(this.commandManager,
|
||||||
this.commandExecutionHandler, this.commandPermission);
|
this.commandMeta,
|
||||||
|
senderType,
|
||||||
|
this.commandArguments,
|
||||||
|
this.commandExecutionHandler,
|
||||||
|
this.commandPermission,
|
||||||
|
this.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -559,8 +600,13 @@ public class Command<C> {
|
||||||
* @return New builder instance using the command permission
|
* @return New builder instance using the command permission
|
||||||
*/
|
*/
|
||||||
public @NonNull Builder<C> withPermission(@NonNull final CommandPermission permission) {
|
public @NonNull Builder<C> withPermission(@NonNull final CommandPermission permission) {
|
||||||
return new Builder<>(this.commandManager, this.commandMeta, this.senderType, this.commandArguments,
|
return new Builder<>(this.commandManager,
|
||||||
this.commandExecutionHandler, permission);
|
this.commandMeta,
|
||||||
|
this.senderType,
|
||||||
|
this.commandArguments,
|
||||||
|
this.commandExecutionHandler,
|
||||||
|
permission,
|
||||||
|
this.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -570,8 +616,13 @@ public class Command<C> {
|
||||||
* @return New builder instance using the command permission
|
* @return New builder instance using the command permission
|
||||||
*/
|
*/
|
||||||
public @NonNull Builder<C> withPermission(@NonNull final String permission) {
|
public @NonNull Builder<C> withPermission(@NonNull final String permission) {
|
||||||
return new Builder<>(this.commandManager, this.commandMeta, this.senderType, this.commandArguments,
|
return new Builder<>(this.commandManager,
|
||||||
this.commandExecutionHandler, Permission.of(permission));
|
this.commandMeta,
|
||||||
|
this.senderType,
|
||||||
|
this.commandArguments,
|
||||||
|
this.commandExecutionHandler,
|
||||||
|
Permission.of(permission),
|
||||||
|
this.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -610,13 +661,38 @@ public class Command<C> {
|
||||||
return this.meta("hidden", "true");
|
return this.meta("hidden", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new command flag
|
||||||
|
*
|
||||||
|
* @param flag Flag
|
||||||
|
* @param <T> Flag value type
|
||||||
|
* @return New builder instance that uses the provided flag
|
||||||
|
*/
|
||||||
|
public @NonNull <T> Builder<C> flag(@NonNull final CommandFlag<T> flag) {
|
||||||
|
final List<CommandFlag<?>> flags = new ArrayList<>(this.flags);
|
||||||
|
flags.add(flag);
|
||||||
|
return new Builder<>(this.commandManager,
|
||||||
|
this.commandMeta,
|
||||||
|
this.senderType,
|
||||||
|
this.commandArguments,
|
||||||
|
this.commandExecutionHandler,
|
||||||
|
this.commandPermission,
|
||||||
|
Collections.unmodifiableList(flags));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a command using the builder instance
|
* Build a command using the builder instance
|
||||||
*
|
*
|
||||||
* @return Built command
|
* @return Built command
|
||||||
*/
|
*/
|
||||||
public @NonNull Command<C> build() {
|
public @NonNull Command<C> build() {
|
||||||
return new Command<>(Collections.unmodifiableMap(this.commandArguments),
|
final LinkedHashMap<CommandArgument<C, ?>, Description> commandArguments = new LinkedHashMap<>(this.commandArguments);
|
||||||
|
/* Construct flag node */
|
||||||
|
if (!flags.isEmpty()) {
|
||||||
|
final FlagArgument<C> flagArgument = new FlagArgument<>(this.flags);
|
||||||
|
commandArguments.put(flagArgument, Description.of("Command flags"));
|
||||||
|
}
|
||||||
|
return new Command<>(Collections.unmodifiableMap(commandArguments),
|
||||||
this.commandExecutionHandler,
|
this.commandExecutionHandler,
|
||||||
this.senderType,
|
this.senderType,
|
||||||
this.commandPermission,
|
this.commandPermission,
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ package cloud.commandframework;
|
||||||
import cloud.commandframework.arguments.CommandArgument;
|
import cloud.commandframework.arguments.CommandArgument;
|
||||||
import cloud.commandframework.arguments.CommandSyntaxFormatter;
|
import cloud.commandframework.arguments.CommandSyntaxFormatter;
|
||||||
import cloud.commandframework.arguments.StandardCommandSyntaxFormatter;
|
import cloud.commandframework.arguments.StandardCommandSyntaxFormatter;
|
||||||
|
import cloud.commandframework.arguments.flags.CommandFlag;
|
||||||
import cloud.commandframework.arguments.parser.ArgumentParser;
|
import cloud.commandframework.arguments.parser.ArgumentParser;
|
||||||
import cloud.commandframework.arguments.parser.ParserParameter;
|
import cloud.commandframework.arguments.parser.ParserParameter;
|
||||||
import cloud.commandframework.arguments.parser.ParserRegistry;
|
import cloud.commandframework.arguments.parser.ParserRegistry;
|
||||||
|
|
@ -363,6 +364,16 @@ public abstract class CommandManager<C> {
|
||||||
return CommandArgument.<C, T>ofType(type, name).manager(this);
|
return CommandArgument.<C, T>ofType(type, name).manager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command flag builder
|
||||||
|
*
|
||||||
|
* @param name Flag name
|
||||||
|
* @return Flag builder
|
||||||
|
*/
|
||||||
|
public CommandFlag.@NonNull Builder<Void> flagBuilder(@NonNull final String name) {
|
||||||
|
return CommandFlag.<C>newBuilder(name);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the internal command tree. This should not be accessed unless you know what you
|
* Get the internal command tree. This should not be accessed unless you know what you
|
||||||
* are doing
|
* are doing
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ package cloud.commandframework;
|
||||||
import cloud.commandframework.arguments.CommandArgument;
|
import cloud.commandframework.arguments.CommandArgument;
|
||||||
import cloud.commandframework.arguments.StaticArgument;
|
import cloud.commandframework.arguments.StaticArgument;
|
||||||
import cloud.commandframework.arguments.compound.CompoundArgument;
|
import cloud.commandframework.arguments.compound.CompoundArgument;
|
||||||
|
import cloud.commandframework.arguments.compound.FlagArgument;
|
||||||
import cloud.commandframework.arguments.parser.ArgumentParseResult;
|
import cloud.commandframework.arguments.parser.ArgumentParseResult;
|
||||||
import cloud.commandframework.context.CommandContext;
|
import cloud.commandframework.context.CommandContext;
|
||||||
import cloud.commandframework.exceptions.AmbiguousNodeException;
|
import cloud.commandframework.exceptions.AmbiguousNodeException;
|
||||||
|
|
@ -378,6 +379,15 @@ public final class CommandTree<C> {
|
||||||
}
|
}
|
||||||
// END: Compound arguments
|
// END: Compound arguments
|
||||||
|
|
||||||
|
// START: Flags
|
||||||
|
if (child.getValue() instanceof FlagArgument) {
|
||||||
|
/* Remove all but last */
|
||||||
|
while (commandQueue.size() > 1) {
|
||||||
|
commandContext.store(FlagArgument.FLAG_META, commandQueue.remove());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// END: Flags
|
||||||
|
|
||||||
if (child.getValue() != null) {
|
if (child.getValue() != null) {
|
||||||
if (commandQueue.isEmpty()) {
|
if (commandQueue.isEmpty()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,21 @@
|
||||||
//
|
//
|
||||||
package cloud.commandframework.arguments.compound;
|
package cloud.commandframework.arguments.compound;
|
||||||
|
|
||||||
import cloud.commandframework.types.tuples.DynamicTuple;
|
import cloud.commandframework.arguments.CommandArgument;
|
||||||
import cloud.commandframework.types.tuples.Tuple;
|
import cloud.commandframework.arguments.flags.CommandFlag;
|
||||||
import io.leangen.geantyref.TypeToken;
|
import cloud.commandframework.arguments.parser.ArgumentParseResult;
|
||||||
|
import cloud.commandframework.arguments.parser.ArgumentParser;
|
||||||
|
import cloud.commandframework.context.CommandContext;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container for flag parsing logic. This should not be be used directly.
|
* Container for flag parsing logic. This should not be be used directly.
|
||||||
|
|
@ -36,21 +45,160 @@ import java.util.function.Function;
|
||||||
*
|
*
|
||||||
* @param <C> Command sender type
|
* @param <C> Command sender type
|
||||||
*/
|
*/
|
||||||
public class FlagArgument<C> extends CompoundArgument<DynamicTuple, C, DynamicTuple> {
|
public class FlagArgument<C> extends CommandArgument<C, Object> {
|
||||||
|
|
||||||
FlagArgument(final @NonNull Tuple names,
|
/**
|
||||||
final @NonNull Tuple parserTuple,
|
* Dummy object that indicates that flags were parsed successfully
|
||||||
final @NonNull Tuple types,
|
*/
|
||||||
final @NonNull Function<@NonNull DynamicTuple, @NonNull DynamicTuple> mapper,
|
public static final Object FLAG_PARSE_RESULT_OBJECT = new Object();
|
||||||
final @NonNull TypeToken<DynamicTuple> valueType) {
|
/**
|
||||||
|
* Meta data for the last argument that was suggested
|
||||||
|
*/
|
||||||
|
public static final String FLAG_META = "__last_flag__";
|
||||||
|
|
||||||
|
private static final String FLAG_ARGUMENT_NAME = "flags";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new flag argument
|
||||||
|
*
|
||||||
|
* @param flags Flags
|
||||||
|
*/
|
||||||
|
public FlagArgument(final Collection<CommandFlag<?>> flags) {
|
||||||
super(false,
|
super(false,
|
||||||
"flags",
|
FLAG_ARGUMENT_NAME,
|
||||||
names,
|
new FlagArgumentParser<>(flags.toArray(new CommandFlag<?>[0])),
|
||||||
parserTuple,
|
Object.class);
|
||||||
types,
|
}
|
||||||
mapper,
|
|
||||||
DynamicTuple::of,
|
public static final class FlagArgumentParser<C> implements ArgumentParser<C, Object> {
|
||||||
valueType);
|
|
||||||
|
private final CommandFlag<?>[] flags;
|
||||||
|
|
||||||
|
private FlagArgumentParser(@NonNull final CommandFlag<?>[] flags) {
|
||||||
|
this.flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull ArgumentParseResult<@NonNull Object> parse(@NonNull final CommandContext<@NonNull C> commandContext,
|
||||||
|
@NonNull final Queue<@NonNull String> inputQueue) {
|
||||||
|
/*
|
||||||
|
This argument must necessarily be the last so we can just consume all remaining input. This argument type
|
||||||
|
is similar to a greedy string in that sense. But, we need to keep all flag logic contained to the parser
|
||||||
|
*/
|
||||||
|
final Set<CommandFlag<?>> parsedFlags = new HashSet<>();
|
||||||
|
CommandFlag<?> currentFlag = null;
|
||||||
|
|
||||||
|
for (@NonNull final String string : inputQueue) {
|
||||||
|
if (string.startsWith("-")) {
|
||||||
|
if (currentFlag != null && currentFlag.getCommandArgument() != null) {
|
||||||
|
return ArgumentParseResult.failure(
|
||||||
|
new IllegalArgumentException(String.format("Missing argument for '%s'", currentFlag.getName())));
|
||||||
|
}
|
||||||
|
if (string.startsWith("--")) {
|
||||||
|
final String flagName = string.substring(2);
|
||||||
|
for (final CommandFlag<?> flag : this.flags) {
|
||||||
|
if (flagName.equalsIgnoreCase(flag.getName())) {
|
||||||
|
currentFlag = flag;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final String flagName = string.substring(1);
|
||||||
|
for (final CommandFlag<?> flag : this.flags) {
|
||||||
|
for (final String alias : flag.getAliases()) {
|
||||||
|
if (alias.equalsIgnoreCase(flagName)) {
|
||||||
|
currentFlag = flag;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentFlag == null) {
|
||||||
|
return ArgumentParseResult.failure(
|
||||||
|
new IllegalArgumentException(String.format("Unknown flag '%s'", string)));
|
||||||
|
} else if (parsedFlags.contains(currentFlag)) {
|
||||||
|
return ArgumentParseResult.failure(
|
||||||
|
new IllegalArgumentException(String.format("Duplicate flag '%s'", string)));
|
||||||
|
}
|
||||||
|
parsedFlags.add(currentFlag);
|
||||||
|
if (currentFlag.getCommandArgument() == null) {
|
||||||
|
/* It's a presence flag */
|
||||||
|
commandContext.flags().addPresenceFlag(currentFlag);
|
||||||
|
/* We don't want to parse a value for this flag */
|
||||||
|
currentFlag = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (currentFlag == null) {
|
||||||
|
return ArgumentParseResult.failure(
|
||||||
|
new IllegalArgumentException(String.format("No flag started. Don't"
|
||||||
|
+ " know what to do with '%s'", string)));
|
||||||
|
} else {
|
||||||
|
final ArgumentParseResult<?> result =
|
||||||
|
((CommandArgument) currentFlag.getCommandArgument())
|
||||||
|
.getParser()
|
||||||
|
.parse(commandContext,
|
||||||
|
new LinkedList<>(Collections.singletonList(string)));
|
||||||
|
if (result.getFailure().isPresent()) {
|
||||||
|
return ArgumentParseResult.failure(result.getFailure().get());
|
||||||
|
} else {
|
||||||
|
final CommandFlag erasedFlag = currentFlag;
|
||||||
|
final Object value = result.getParsedValue().get();
|
||||||
|
commandContext.flags().addValueFlag(erasedFlag, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* We've consumed everything */
|
||||||
|
inputQueue.clear();
|
||||||
|
return ArgumentParseResult.success(FLAG_PARSE_RESULT_OBJECT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull List<@NonNull String> suggestions(final @NonNull CommandContext<C> commandContext,
|
||||||
|
final @NonNull String input) {
|
||||||
|
/* Check if we have a last flag stored */
|
||||||
|
final String lastArg = commandContext.getOrDefault(FLAG_META, "");
|
||||||
|
if (lastArg.isEmpty() || !lastArg.startsWith("-")) {
|
||||||
|
/* We don't care about the last value and so we expect a flag */
|
||||||
|
final List<String> strings = new LinkedList<>();
|
||||||
|
for (final CommandFlag<?> flag : this.flags) {
|
||||||
|
strings.add(String.format("--%s", flag.getName()));
|
||||||
|
for (final String alias : flag.getAliases()) {
|
||||||
|
strings.add(String.format("-%s", alias));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings;
|
||||||
|
} else {
|
||||||
|
CommandFlag<?> currentFlag = null;
|
||||||
|
if (lastArg.startsWith("--")) {
|
||||||
|
final String flagName = lastArg.substring(2);
|
||||||
|
for (final CommandFlag<?> flag : this.flags) {
|
||||||
|
if (flagName.equalsIgnoreCase(flag.getName())) {
|
||||||
|
currentFlag = flag;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (lastArg.startsWith("-")) {
|
||||||
|
final String flagName = lastArg.substring(1);
|
||||||
|
for (final CommandFlag<?> flag : this.flags) {
|
||||||
|
for (final String alias : flag.getAliases()) {
|
||||||
|
if (alias.equalsIgnoreCase(flagName)) {
|
||||||
|
currentFlag = flag;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentFlag != null && currentFlag.getCommandArgument() != null) {
|
||||||
|
// noinspection all
|
||||||
|
return (List<String>) ((BiFunction) currentFlag.getCommandArgument().getSuggestionsProvider())
|
||||||
|
.apply(commandContext, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commandContext.store(FLAG_META, "");
|
||||||
|
return suggestions(commandContext, input);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A flag is an optional command argument that may have an associated parser,
|
* A flag is an optional command argument that may have an associated parser,
|
||||||
|
|
@ -88,7 +89,7 @@ public final class CommandFlag<T> {
|
||||||
/**
|
/**
|
||||||
* Get the flag description
|
* Get the flag description
|
||||||
* <p>
|
* <p>
|
||||||
* Flag description
|
* @return Flag description
|
||||||
*/
|
*/
|
||||||
public @NonNull Description getDescription() {
|
public @NonNull Description getDescription() {
|
||||||
return this.description;
|
return this.description;
|
||||||
|
|
@ -108,6 +109,23 @@ public final class CommandFlag<T> {
|
||||||
return String.format("--%s", this.name);
|
return String.format("--%s", this.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final CommandFlag<?> that = (CommandFlag<?>) o;
|
||||||
|
return getName().equals(that.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static final class Builder<T> {
|
public static final class Builder<T> {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import java.util.Map;
|
||||||
/**
|
/**
|
||||||
* Flag value mappings
|
* Flag value mappings
|
||||||
*/
|
*/
|
||||||
public class FlagContext {
|
public final class FlagContext {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dummy object stored as a flag value when the flag has no associated parser
|
* Dummy object stored as a flag value when the flag has no associated parser
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 Alexander Söderberg & Contributors
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cloud flag system
|
||||||
|
*/
|
||||||
|
package cloud.commandframework.arguments.flags;
|
||||||
|
|
@ -26,6 +26,7 @@ package cloud.commandframework.context;
|
||||||
import cloud.commandframework.arguments.CommandArgument;
|
import cloud.commandframework.arguments.CommandArgument;
|
||||||
import cloud.commandframework.arguments.flags.FlagContext;
|
import cloud.commandframework.arguments.flags.FlagContext;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
@ -114,6 +115,15 @@ public final class CommandContext<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a stored value from the context
|
||||||
|
*
|
||||||
|
* @param key Key to remove
|
||||||
|
*/
|
||||||
|
public void remove(@NonNull final String key) {
|
||||||
|
this.internalStorage.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a required argument from the context. This will thrown an exception
|
* Get a required argument from the context. This will thrown an exception
|
||||||
* if there's no value associated with the given key
|
* if there's no value associated with the given key
|
||||||
|
|
@ -140,8 +150,8 @@ public final class CommandContext<C> {
|
||||||
* @param <T> Argument type
|
* @param <T> Argument type
|
||||||
* @return Argument, or supplied default value
|
* @return Argument, or supplied default value
|
||||||
*/
|
*/
|
||||||
public <T> @NonNull T getOrDefault(@NonNull final String key,
|
public <T> @Nullable T getOrDefault(@NonNull final String key,
|
||||||
@NonNull final T defaultValue) {
|
@Nullable final T defaultValue) {
|
||||||
return this.<T>getOptional(key).orElse(defaultValue);
|
return this.<T>getOptional(key).orElse(defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public final class DynamicTuple implements Tuple {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int getSize() {
|
public int getSize() {
|
||||||
return this.internalArray.length;
|
return this.internalArray.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,15 @@ public class CommandSuggestionsTest {
|
||||||
manager.command(manager.commandBuilder("com2")
|
manager.command(manager.commandBuilder("com2")
|
||||||
.argumentPair("com", Pair.of("x", "enum"),
|
.argumentPair("com", Pair.of("x", "enum"),
|
||||||
Pair.of(Integer.class, TestEnum.class), Description.empty()));
|
Pair.of(Integer.class, TestEnum.class), Description.empty()));
|
||||||
|
|
||||||
|
manager.command(manager.commandBuilder("flags")
|
||||||
|
.argument(IntegerArgument.of("num"))
|
||||||
|
.flag(manager.flagBuilder("enum")
|
||||||
|
.withArgument(EnumArgument.of(TestEnum.class, "enum"))
|
||||||
|
.build())
|
||||||
|
.flag(manager.flagBuilder("static")
|
||||||
|
.build())
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -142,6 +151,20 @@ public class CommandSuggestionsTest {
|
||||||
Assertions.assertEquals(Arrays.asList("foo", "bar"), suggestions4);
|
Assertions.assertEquals(Arrays.asList("foo", "bar"), suggestions4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFlags() {
|
||||||
|
final String input = "flags 10 ";
|
||||||
|
final List<String> suggestions = manager.suggest(new TestCommandSender(), input);
|
||||||
|
Assertions.assertEquals(Arrays.asList("--enum", "--static"), suggestions);
|
||||||
|
final String input2 = "flags 10 --enum ";
|
||||||
|
final List<String> suggestions2 = manager.suggest(new TestCommandSender(), input2);
|
||||||
|
Assertions.assertEquals(Arrays.asList("foo", "bar"), suggestions2);
|
||||||
|
final String input3 = "flags 10 --enum foo ";
|
||||||
|
final List<String> suggestions3 = manager.suggest(new TestCommandSender(), input3);
|
||||||
|
Assertions.assertEquals(Arrays.asList("--enum", "--static"), suggestions3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public enum TestEnum {
|
public enum TestEnum {
|
||||||
FOO,
|
FOO,
|
||||||
BAR
|
BAR
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,21 @@ class CommandTreeTest {
|
||||||
final Vector2 vector2 = c.get("vec");
|
final Vector2 vector2 = c.get("vec");
|
||||||
System.out.printf("X: %f | Y: %f\n", vector2.getX(), vector2.getY());
|
System.out.printf("X: %f | Y: %f\n", vector2.getX(), vector2.getY());
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
/* Build command for testing flags */
|
||||||
|
manager.command(manager.commandBuilder("flags")
|
||||||
|
.flag(manager.flagBuilder("test")
|
||||||
|
.withAliases("t")
|
||||||
|
.build())
|
||||||
|
.flag(manager.flagBuilder("test2")
|
||||||
|
.build())
|
||||||
|
.flag(manager.flagBuilder("num")
|
||||||
|
.withArgument(IntegerArgument.of("num")).build())
|
||||||
|
.handler(c -> {
|
||||||
|
System.out.println("Flag present? " + c.flags().isPresent("test"));
|
||||||
|
System.out.println("Numerical flag: " + c.flags().getValue("num", -10));
|
||||||
|
})
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -182,6 +197,20 @@ class CommandTreeTest {
|
||||||
manager.executeCommand(new TestCommandSender(), "vec 1 1").join();
|
manager.executeCommand(new TestCommandSender(), "vec 1 1").join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFlags() {
|
||||||
|
manager.executeCommand(new TestCommandSender(), "flags").join();
|
||||||
|
manager.executeCommand(new TestCommandSender(), "flags --test").join();
|
||||||
|
manager.executeCommand(new TestCommandSender(), "flags -t").join();
|
||||||
|
Assertions.assertThrows(CompletionException.class, () ->
|
||||||
|
manager.executeCommand(new TestCommandSender(), "flags --test --nonexistant").join());
|
||||||
|
Assertions.assertThrows(CompletionException.class, () ->
|
||||||
|
manager.executeCommand(new TestCommandSender(), "flags --test --duplicate").join());
|
||||||
|
manager.executeCommand(new TestCommandSender(), "flags --test --test2").join();
|
||||||
|
Assertions.assertThrows(CompletionException.class, () ->
|
||||||
|
manager.executeCommand(new TestCommandSender(), "flags --test test2").join());
|
||||||
|
manager.executeCommand(new TestCommandSender(), "flags --num 500");
|
||||||
|
}
|
||||||
|
|
||||||
public static final class SpecificCommandSender extends TestCommandSender {
|
public static final class SpecificCommandSender extends TestCommandSender {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,13 @@
|
||||||
//
|
//
|
||||||
package cloud.commandframework.brigadier;
|
package cloud.commandframework.brigadier;
|
||||||
|
|
||||||
import io.leangen.geantyref.GenericTypeReflector;
|
|
||||||
import io.leangen.geantyref.TypeToken;
|
|
||||||
import cloud.commandframework.Command;
|
import cloud.commandframework.Command;
|
||||||
import cloud.commandframework.CommandManager;
|
import cloud.commandframework.CommandManager;
|
||||||
import cloud.commandframework.CommandTree;
|
import cloud.commandframework.CommandTree;
|
||||||
import cloud.commandframework.arguments.CommandArgument;
|
import cloud.commandframework.arguments.CommandArgument;
|
||||||
import cloud.commandframework.arguments.StaticArgument;
|
import cloud.commandframework.arguments.StaticArgument;
|
||||||
import cloud.commandframework.arguments.compound.CompoundArgument;
|
import cloud.commandframework.arguments.compound.CompoundArgument;
|
||||||
|
import cloud.commandframework.arguments.compound.FlagArgument;
|
||||||
import cloud.commandframework.arguments.parser.ArgumentParser;
|
import cloud.commandframework.arguments.parser.ArgumentParser;
|
||||||
import cloud.commandframework.arguments.standard.BooleanArgument;
|
import cloud.commandframework.arguments.standard.BooleanArgument;
|
||||||
import cloud.commandframework.arguments.standard.ByteArgument;
|
import cloud.commandframework.arguments.standard.ByteArgument;
|
||||||
|
|
@ -57,6 +56,8 @@ import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||||
import com.mojang.brigadier.suggestion.Suggestions;
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||||
|
import io.leangen.geantyref.GenericTypeReflector;
|
||||||
|
import io.leangen.geantyref.TypeToken;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
|
|
@ -82,8 +83,8 @@ import java.util.function.Supplier;
|
||||||
*/
|
*/
|
||||||
public final class CloudBrigadierManager<C, S> {
|
public final class CloudBrigadierManager<C, S> {
|
||||||
|
|
||||||
private final Map<Class<?>, Function<? extends ArgumentParser<C, ?>,
|
private final Map<Class<?>, cloud.commandframework.types.tuples.Pair<Function<? extends ArgumentParser<C, ?>,
|
||||||
? extends ArgumentType<?>>> mappers;
|
? extends ArgumentType<?>>, Boolean>> mappers;
|
||||||
private final Map<Class<?>, Supplier<ArgumentType<?>>> defaultArgumentTypeSuppliers;
|
private final Map<Class<?>, Supplier<ArgumentType<?>>> defaultArgumentTypeSuppliers;
|
||||||
private final Supplier<CommandContext<C>> dummyContextProvider;
|
private final Supplier<CommandContext<C>> dummyContextProvider;
|
||||||
private final CommandManager<C> commandManager;
|
private final CommandManager<C> commandManager;
|
||||||
|
|
@ -107,7 +108,7 @@ public final class CloudBrigadierManager<C, S> {
|
||||||
private void registerInternalMappings() {
|
private void registerInternalMappings() {
|
||||||
/* Map byte, short and int to IntegerArgumentType */
|
/* Map byte, short and int to IntegerArgumentType */
|
||||||
this.registerMapping(new TypeToken<ByteArgument.ByteParser<C>>() {
|
this.registerMapping(new TypeToken<ByteArgument.ByteParser<C>>() {
|
||||||
}, argument -> {
|
}, true, argument -> {
|
||||||
final boolean hasMin = argument.getMin() != Byte.MIN_VALUE;
|
final boolean hasMin = argument.getMin() != Byte.MIN_VALUE;
|
||||||
final boolean hasMax = argument.getMax() != Byte.MAX_VALUE;
|
final boolean hasMax = argument.getMax() != Byte.MAX_VALUE;
|
||||||
if (hasMin) {
|
if (hasMin) {
|
||||||
|
|
@ -119,7 +120,7 @@ public final class CloudBrigadierManager<C, S> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.registerMapping(new TypeToken<ShortArgument.ShortParser<C>>() {
|
this.registerMapping(new TypeToken<ShortArgument.ShortParser<C>>() {
|
||||||
}, argument -> {
|
}, true, argument -> {
|
||||||
final boolean hasMin = argument.getMin() != Short.MIN_VALUE;
|
final boolean hasMin = argument.getMin() != Short.MIN_VALUE;
|
||||||
final boolean hasMax = argument.getMax() != Short.MAX_VALUE;
|
final boolean hasMax = argument.getMax() != Short.MAX_VALUE;
|
||||||
if (hasMin) {
|
if (hasMin) {
|
||||||
|
|
@ -131,7 +132,7 @@ public final class CloudBrigadierManager<C, S> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.registerMapping(new TypeToken<IntegerArgument.IntegerParser<C>>() {
|
this.registerMapping(new TypeToken<IntegerArgument.IntegerParser<C>>() {
|
||||||
}, argument -> {
|
}, true, argument -> {
|
||||||
final boolean hasMin = argument.getMin() != Integer.MIN_VALUE;
|
final boolean hasMin = argument.getMin() != Integer.MIN_VALUE;
|
||||||
final boolean hasMax = argument.getMax() != Integer.MAX_VALUE;
|
final boolean hasMax = argument.getMax() != Integer.MAX_VALUE;
|
||||||
if (hasMin) {
|
if (hasMin) {
|
||||||
|
|
@ -144,7 +145,7 @@ public final class CloudBrigadierManager<C, S> {
|
||||||
});
|
});
|
||||||
/* Map float to FloatArgumentType */
|
/* Map float to FloatArgumentType */
|
||||||
this.registerMapping(new TypeToken<FloatArgument.FloatParser<C>>() {
|
this.registerMapping(new TypeToken<FloatArgument.FloatParser<C>>() {
|
||||||
}, argument -> {
|
}, true, argument -> {
|
||||||
final boolean hasMin = argument.getMin() != Float.MIN_VALUE;
|
final boolean hasMin = argument.getMin() != Float.MIN_VALUE;
|
||||||
final boolean hasMax = argument.getMax() != Float.MAX_VALUE;
|
final boolean hasMax = argument.getMax() != Float.MAX_VALUE;
|
||||||
if (hasMin) {
|
if (hasMin) {
|
||||||
|
|
@ -157,7 +158,7 @@ public final class CloudBrigadierManager<C, S> {
|
||||||
});
|
});
|
||||||
/* Map double to DoubleArgumentType */
|
/* Map double to DoubleArgumentType */
|
||||||
this.registerMapping(new TypeToken<DoubleArgument.DoubleParser<C>>() {
|
this.registerMapping(new TypeToken<DoubleArgument.DoubleParser<C>>() {
|
||||||
}, argument -> {
|
}, true, argument -> {
|
||||||
final boolean hasMin = argument.getMin() != Double.MIN_VALUE;
|
final boolean hasMin = argument.getMin() != Double.MIN_VALUE;
|
||||||
final boolean hasMax = argument.getMax() != Double.MAX_VALUE;
|
final boolean hasMax = argument.getMax() != Double.MAX_VALUE;
|
||||||
if (hasMin) {
|
if (hasMin) {
|
||||||
|
|
@ -170,10 +171,10 @@ public final class CloudBrigadierManager<C, S> {
|
||||||
});
|
});
|
||||||
/* Map boolean to BoolArgumentType */
|
/* Map boolean to BoolArgumentType */
|
||||||
this.registerMapping(new TypeToken<BooleanArgument.BooleanParser<C>>() {
|
this.registerMapping(new TypeToken<BooleanArgument.BooleanParser<C>>() {
|
||||||
}, argument -> BoolArgumentType.bool());
|
}, true, argument -> BoolArgumentType.bool());
|
||||||
/* Map String properly to StringArgumentType */
|
/* Map String properly to StringArgumentType */
|
||||||
this.registerMapping(new TypeToken<StringArgument.StringParser<C>>() {
|
this.registerMapping(new TypeToken<StringArgument.StringParser<C>>() {
|
||||||
}, argument -> {
|
}, false, argument -> {
|
||||||
switch (argument.getStringMode()) {
|
switch (argument.getStringMode()) {
|
||||||
case QUOTED:
|
case QUOTED:
|
||||||
return StringArgumentType.string();
|
return StringArgumentType.string();
|
||||||
|
|
@ -183,21 +184,27 @@ public final class CloudBrigadierManager<C, S> {
|
||||||
return StringArgumentType.word();
|
return StringArgumentType.word();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
/* Map flags to a greedy string */
|
||||||
|
this.registerMapping(new TypeToken<FlagArgument.FlagArgumentParser<C>>() {
|
||||||
|
}, false, argument -> StringArgumentType.greedyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a cloud-Brigadier mapping
|
* Register a cloud-Brigadier mapping
|
||||||
*
|
*
|
||||||
* @param argumentType cloud argument type
|
* @param argumentType cloud argument type
|
||||||
* @param mapper mapper function
|
* @param nativeSuggestions Whether or not Brigadier suggestions should be used
|
||||||
* @param <T> cloud argument value type
|
* @param mapper mapper function
|
||||||
* @param <K> cloud argument type
|
* @param <T> cloud argument value type
|
||||||
* @param <O> Brigadier argument type value
|
* @param <K> cloud argument type
|
||||||
|
* @param <O> Brigadier argument type value
|
||||||
*/
|
*/
|
||||||
public <T, K extends ArgumentParser<C, T>, O> void registerMapping(@NonNull final TypeToken<K> argumentType,
|
public <T, K extends ArgumentParser<C, T>, O> void registerMapping(@NonNull final TypeToken<K> argumentType,
|
||||||
|
final boolean nativeSuggestions,
|
||||||
@NonNull final Function<@NonNull ? extends K,
|
@NonNull final Function<@NonNull ? extends K,
|
||||||
@NonNull ? extends ArgumentType<O>> mapper) {
|
@NonNull ? extends ArgumentType<O>> mapper) {
|
||||||
this.mappers.put(GenericTypeReflector.erase(argumentType.getType()), mapper);
|
this.mappers.put(GenericTypeReflector.erase(argumentType.getType()),
|
||||||
|
cloud.commandframework.types.tuples.Pair.of(mapper, nativeSuggestions));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -217,11 +224,13 @@ public final class CloudBrigadierManager<C, S> {
|
||||||
@NonNull final TypeToken<T> argumentType,
|
@NonNull final TypeToken<T> argumentType,
|
||||||
@NonNull final K argument) {
|
@NonNull final K argument) {
|
||||||
final ArgumentParser<C, ?> commandArgument = (ArgumentParser<C, ?>) argument;
|
final ArgumentParser<C, ?> commandArgument = (ArgumentParser<C, ?>) argument;
|
||||||
Function function = this.mappers.get(GenericTypeReflector.erase(argumentType.getType()));
|
final cloud.commandframework.types.tuples.Pair pair
|
||||||
if (function == null) {
|
= this.mappers.get(GenericTypeReflector.erase(argumentType.getType()));
|
||||||
|
if (pair == null || pair.getFirst() == null) {
|
||||||
return this.createDefaultMapper(valueType, commandArgument);
|
return this.createDefaultMapper(valueType, commandArgument);
|
||||||
}
|
}
|
||||||
return new Pair<>((ArgumentType<?>) function.apply(commandArgument), !(argument instanceof StringArgument.StringParser));
|
return new Pair<>((ArgumentType<?>) ((Function) pair.getFirst()).apply(commandArgument),
|
||||||
|
(boolean) pair.getSecond());
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T, K extends ArgumentParser<C, T>> @NonNull Pair<@NonNull ArgumentType<?>, @NonNull Boolean> createDefaultMapper(
|
private <T, K extends ArgumentParser<C, T>> @NonNull Pair<@NonNull ArgumentType<?>, @NonNull Boolean> createDefaultMapper(
|
||||||
|
|
@ -255,7 +264,8 @@ public final class CloudBrigadierManager<C, S> {
|
||||||
final LiteralArgumentBuilder<S> literalArgumentBuilder = LiteralArgumentBuilder
|
final LiteralArgumentBuilder<S> literalArgumentBuilder = LiteralArgumentBuilder
|
||||||
.<S>literal(label)
|
.<S>literal(label)
|
||||||
.requires(sender -> permissionChecker.test(sender, (CommandPermission) node.getNodeMeta()
|
.requires(sender -> permissionChecker.test(sender, (CommandPermission) node.getNodeMeta()
|
||||||
.getOrDefault("permission", Permission.empty())));
|
.getOrDefault("permission",
|
||||||
|
Permission.empty())));
|
||||||
literalArgumentBuilder.executes(executor);
|
literalArgumentBuilder.executes(executor);
|
||||||
final LiteralCommandNode<S> constructedRoot = literalArgumentBuilder.build();
|
final LiteralCommandNode<S> constructedRoot = literalArgumentBuilder.build();
|
||||||
for (final CommandTree.Node<CommandArgument<C, ?>> child : node.getChildren()) {
|
for (final CommandTree.Node<CommandArgument<C, ?>> child : node.getChildren()) {
|
||||||
|
|
@ -282,8 +292,10 @@ public final class CloudBrigadierManager<C, S> {
|
||||||
final com.mojang.brigadier.@NonNull Command<S> executor,
|
final com.mojang.brigadier.@NonNull Command<S> executor,
|
||||||
@NonNull final BiPredicate<@NonNull S, @NonNull CommandPermission> permissionChecker) {
|
@NonNull final BiPredicate<@NonNull S, @NonNull CommandPermission> permissionChecker) {
|
||||||
final LiteralArgumentBuilder<S> literalArgumentBuilder = LiteralArgumentBuilder.<S>literal(root.getLiteral())
|
final LiteralArgumentBuilder<S> literalArgumentBuilder = LiteralArgumentBuilder.<S>literal(root.getLiteral())
|
||||||
.requires(sender -> permissionChecker.test(sender, (CommandPermission) cloudCommand.getNodeMeta()
|
.requires(sender -> permissionChecker.test(sender,
|
||||||
.getOrDefault("permission", Permission.empty())));
|
(CommandPermission) cloudCommand.getNodeMeta()
|
||||||
|
.getOrDefault("permission",
|
||||||
|
Permission.empty())));
|
||||||
if (cloudCommand.getValue() != null && cloudCommand.getValue().getOwningCommand() != null) {
|
if (cloudCommand.getValue() != null && cloudCommand.getValue().getOwningCommand() != null) {
|
||||||
literalArgumentBuilder.executes(executor);
|
literalArgumentBuilder.executes(executor);
|
||||||
}
|
}
|
||||||
|
|
@ -312,18 +324,19 @@ public final class CloudBrigadierManager<C, S> {
|
||||||
final ArgumentBuilder<S, ?>[] argumentBuilders = new ArgumentBuilder[parsers.length];
|
final ArgumentBuilder<S, ?>[] argumentBuilders = new ArgumentBuilder[parsers.length];
|
||||||
|
|
||||||
for (int i = parsers.length - 1; i >= 0; i--) {
|
for (int i = parsers.length - 1; i >= 0; i--) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked") final ArgumentParser<C, ?> parser = (ArgumentParser<C, ?>) parsers[i];
|
||||||
final ArgumentParser<C, ?> parser = (ArgumentParser<C, ?>) parsers[i];
|
|
||||||
final Pair<ArgumentType<?>, Boolean> pair = this.getArgument(TypeToken.get((Class<?>) types[i]),
|
final Pair<ArgumentType<?>, Boolean> pair = this.getArgument(TypeToken.get((Class<?>) types[i]),
|
||||||
TypeToken.get(parser.getClass()),
|
TypeToken.get(parser.getClass()),
|
||||||
parser);
|
parser);
|
||||||
final SuggestionProvider<S> provider = pair.getRight() ? null : suggestionProvider;
|
final SuggestionProvider<S> provider = pair.getRight() ? null : suggestionProvider;
|
||||||
|
|
||||||
final ArgumentBuilder<S, ?> fragmentBuilder = RequiredArgumentBuilder
|
final ArgumentBuilder<S, ?> fragmentBuilder = RequiredArgumentBuilder
|
||||||
.<S, Object>argument((String) names[i], (ArgumentType<Object>) pair.getLeft())
|
.<S, Object>argument((String) names[i], (ArgumentType<Object>) pair.getLeft())
|
||||||
.suggests(provider)
|
.suggests(provider)
|
||||||
.requires(sender -> permissionChecker.test(sender,
|
.requires(sender -> permissionChecker.test(sender,
|
||||||
(CommandPermission) root.getNodeMeta()
|
(CommandPermission) root.getNodeMeta()
|
||||||
.getOrDefault("permission", Permission.empty())));
|
.getOrDefault("permission",
|
||||||
|
Permission.empty())));
|
||||||
argumentBuilders[i] = fragmentBuilder;
|
argumentBuilders[i] = fragmentBuilder;
|
||||||
|
|
||||||
if (forceExecutor || (i == parsers.length - 1) && (root.isLeaf() || !root.getValue().isRequired())) {
|
if (forceExecutor || (i == parsers.length - 1) && (root.isLeaf() || !root.getValue().isRequired())) {
|
||||||
|
|
@ -354,12 +367,17 @@ public final class CloudBrigadierManager<C, S> {
|
||||||
final Pair<ArgumentType<?>, Boolean> pair = this.getArgument(root.getValue().getValueType(),
|
final Pair<ArgumentType<?>, Boolean> pair = this.getArgument(root.getValue().getValueType(),
|
||||||
TypeToken.get(root.getValue().getParser().getClass()),
|
TypeToken.get(root.getValue().getParser().getClass()),
|
||||||
root.getValue().getParser());
|
root.getValue().getParser());
|
||||||
final SuggestionProvider<S> provider = pair.getRight() ? null : suggestionProvider;
|
final SuggestionProvider<S> provider = pair.getRight()
|
||||||
|
? null
|
||||||
|
: (context, builder) -> this.buildSuggestions(root.getValue(),
|
||||||
|
context, builder);
|
||||||
argumentBuilder = RequiredArgumentBuilder
|
argumentBuilder = RequiredArgumentBuilder
|
||||||
.<S, Object>argument(root.getValue().getName(), (ArgumentType<Object>) pair.getLeft())
|
.<S, Object>argument(root.getValue().getName(), (ArgumentType<Object>) pair.getLeft())
|
||||||
.suggests(provider)
|
.suggests(provider)
|
||||||
.requires(sender -> permissionChecker.test(sender, (CommandPermission) root.getNodeMeta()
|
.requires(sender -> permissionChecker.test(sender,
|
||||||
.getOrDefault("permission", Permission.empty())));
|
(CommandPermission) root.getNodeMeta()
|
||||||
|
.getOrDefault("permission",
|
||||||
|
Permission.empty())));
|
||||||
}
|
}
|
||||||
if (forceExecutor || root.isLeaf() || !root.getValue().isRequired()) {
|
if (forceExecutor || root.isLeaf() || !root.getValue().isRequired()) {
|
||||||
argumentBuilder.executes(executor);
|
argumentBuilder.executes(executor);
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ import org.bukkit.World;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
@ -168,12 +169,21 @@ public final class BukkitTest extends JavaPlugin {
|
||||||
.sendMessage(String.format("UUID: %s\n", c.<UUID>getOptional("uuid").orElse(null)))))
|
.sendMessage(String.format("UUID: %s\n", c.<UUID>getOptional("uuid").orElse(null)))))
|
||||||
.command(mgr.commandBuilder("give")
|
.command(mgr.commandBuilder("give")
|
||||||
.withSenderType(Player.class)
|
.withSenderType(Player.class)
|
||||||
|
.flag(mgr.flagBuilder("color")
|
||||||
|
.withArgument(EnumArgument.of(ChatColor.class, "color"))
|
||||||
|
.build())
|
||||||
.argument(EnumArgument.of(Material.class, "material"))
|
.argument(EnumArgument.of(Material.class, "material"))
|
||||||
.argument(IntegerArgument.of("amount"))
|
.argument(IntegerArgument.of("amount"))
|
||||||
.handler(c -> {
|
.handler(c -> {
|
||||||
final Material material = c.get("material");
|
final Material material = c.get("material");
|
||||||
final int amount = c.get("amount");
|
final int amount = c.get("amount");
|
||||||
final ItemStack itemStack = new ItemStack(material, amount);
|
final ItemStack itemStack = new ItemStack(material, amount);
|
||||||
|
|
||||||
|
final ChatColor color = c.flags().getValue("color", ChatColor.GOLD);
|
||||||
|
final ItemMeta itemMeta = itemStack.getItemMeta();
|
||||||
|
itemMeta.setDisplayName(color + String.format("%s's item", c.getSender().getName()));
|
||||||
|
itemStack.setItemMeta(itemMeta);
|
||||||
|
|
||||||
((Player) c.getSender()).getInventory().addItem(itemStack);
|
((Player) c.getSender()).getInventory().addItem(itemStack);
|
||||||
c.getSender().sendMessage("You've been given stuff, bro.");
|
c.getSender().sendMessage("You've been given stuff, bro.");
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -156,10 +156,6 @@
|
||||||
<property name="processJavadoc" value="true"/>
|
<property name="processJavadoc" value="true"/>
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
<!-- Checks for Size Violations. -->
|
|
||||||
<!-- See https://checkstyle.org/config_sizes.html -->
|
|
||||||
<module name="MethodLength"/>
|
|
||||||
|
|
||||||
<!-- Checks for whitespace -->
|
<!-- Checks for whitespace -->
|
||||||
<!-- See https://checkstyle.org/config_whitespace.html -->
|
<!-- See https://checkstyle.org/config_whitespace.html -->
|
||||||
<module name="EmptyForIteratorPad"/>
|
<module name="EmptyForIteratorPad"/>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue