mirror of https://github.com/Minestom/Minestom.git
Initial cleanup attempt
Signed-off-by: TheMode <themode@outlook.fr>
This commit is contained in:
parent
0bd519c894
commit
5ce7c6ccdb
|
@ -214,7 +214,7 @@ public final class CommandManager {
|
|||
}
|
||||
|
||||
final ArgumentQueryResult queryResult = CommandParser.findEligibleArgument(commandQueryResult.command,
|
||||
commandQueryResult.args, input, false, true, syntax -> true, argument -> true);
|
||||
commandQueryResult.content(), input, false, true, syntax -> true, argument -> true);
|
||||
if (queryResult == null) {
|
||||
// Invalid argument, return command node (default to root)
|
||||
final int commandNode = commandIdentityMap.getOrDefault(commandQueryResult.command, 0);
|
||||
|
|
|
@ -7,7 +7,6 @@ import java.util.Map;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class CommandData {
|
||||
|
||||
private final Map<String, Object> dataMap = new ConcurrentHashMap<>();
|
||||
|
||||
public CommandData set(@NotNull String key, Object value) {
|
||||
|
@ -15,8 +14,7 @@ public class CommandData {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T get(@NotNull String key) {
|
||||
public <T> @Nullable T get(@NotNull String key) {
|
||||
return (T) dataMap.get(key);
|
||||
}
|
||||
|
||||
|
@ -24,8 +22,7 @@ public class CommandData {
|
|||
return dataMap.containsKey(key);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<String, Object> getDataMap() {
|
||||
public @NotNull Map<String, Object> getDataMap() {
|
||||
return dataMap;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,9 @@ import java.util.concurrent.TimeUnit;
|
|||
/**
|
||||
* Class responsible for parsing {@link Command}.
|
||||
*/
|
||||
public class CommandDispatcher {
|
||||
|
||||
public final class CommandDispatcher {
|
||||
private final Map<String, Command> commandMap = new HashMap<>();
|
||||
private final Set<Command> commands = new HashSet<>();
|
||||
|
||||
private final Cache<String, CommandResult> cache = Caffeine.newBuilder()
|
||||
.expireAfterWrite(30, TimeUnit.SECONDS)
|
||||
.build();
|
||||
|
@ -37,7 +35,6 @@ public class CommandDispatcher {
|
|||
*/
|
||||
public void register(@NotNull Command command) {
|
||||
this.commandMap.put(command.getName().toLowerCase(), command);
|
||||
|
||||
// Register aliases
|
||||
final String[] aliases = command.getAliases();
|
||||
if (aliases != null) {
|
||||
|
@ -45,20 +42,17 @@ public class CommandDispatcher {
|
|||
this.commandMap.put(alias.toLowerCase(), command);
|
||||
}
|
||||
}
|
||||
|
||||
this.commands.add(command);
|
||||
}
|
||||
|
||||
public void unregister(@NotNull Command command) {
|
||||
this.commandMap.remove(command.getName().toLowerCase());
|
||||
|
||||
final String[] aliases = command.getAliases();
|
||||
if (aliases != null) {
|
||||
for (String alias : aliases) {
|
||||
this.commandMap.remove(alias.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
this.commands.remove(command);
|
||||
|
||||
// Clear cache
|
||||
|
@ -76,8 +70,7 @@ public class CommandDispatcher {
|
|||
* @return the {@link Command} associated with the name, null if not any
|
||||
*/
|
||||
public @Nullable Command findCommand(@NotNull String commandName) {
|
||||
commandName = commandName.toLowerCase();
|
||||
return commandMap.getOrDefault(commandName, null);
|
||||
return commandMap.getOrDefault(commandName.toLowerCase(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,9 +83,7 @@ public class CommandDispatcher {
|
|||
public @NotNull CommandResult execute(@NotNull CommandSender source, @NotNull String commandString) {
|
||||
CommandResult commandResult = parse(commandString);
|
||||
ParsedCommand parsedCommand = commandResult.parsedCommand;
|
||||
if (parsedCommand != null) {
|
||||
commandResult.commandData = parsedCommand.execute(source);
|
||||
}
|
||||
if (parsedCommand != null) commandResult.commandData = parsedCommand.execute(source);
|
||||
return commandResult;
|
||||
}
|
||||
|
||||
|
@ -117,16 +108,14 @@ public class CommandDispatcher {
|
|||
final String commandName = parts[0];
|
||||
|
||||
final CommandQueryResult commandQueryResult = CommandParser.findCommand(commandString);
|
||||
// Check if the command exists
|
||||
if (commandQueryResult == null) {
|
||||
return CommandResult.of(CommandResult.Type.UNKNOWN, commandName);
|
||||
}
|
||||
final Command command = commandQueryResult.command;
|
||||
|
||||
CommandResult result = new CommandResult();
|
||||
result.input = commandString;
|
||||
// Find the used syntax and fill CommandResult#type and CommandResult#parsedCommand
|
||||
findParsedCommand(command, commandName, commandQueryResult.args, commandString, result);
|
||||
findParsedCommand(commandQueryResult, result);
|
||||
|
||||
// Cache result
|
||||
this.cache.put(commandString, result);
|
||||
|
@ -134,32 +123,17 @@ public class CommandDispatcher {
|
|||
return result;
|
||||
}
|
||||
|
||||
private @Nullable ParsedCommand findParsedCommand(@NotNull Command command,
|
||||
@NotNull String commandName, @NotNull String[] args,
|
||||
@NotNull String commandString,
|
||||
@NotNull CommandResult result) {
|
||||
final boolean hasArgument = args.length > 0;
|
||||
|
||||
// Search for subcommand
|
||||
if (hasArgument) {
|
||||
final String firstArgument = args[0];
|
||||
for (Command subcommand : command.getSubcommands()) {
|
||||
if (Command.isValidName(subcommand, firstArgument)) {
|
||||
return findParsedCommand(subcommand,
|
||||
firstArgument, Arrays.copyOfRange(args, 1, args.length),
|
||||
commandString, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final String input = commandName + StringUtils.SPACE + String.join(StringUtils.SPACE, args);
|
||||
private void findParsedCommand(@NotNull CommandQueryResult queryResult,
|
||||
@NotNull CommandResult result) {
|
||||
final Command command = queryResult.command();
|
||||
final String commandString = queryResult.input();
|
||||
|
||||
ParsedCommand parsedCommand = new ParsedCommand();
|
||||
parsedCommand.command = command;
|
||||
parsedCommand.commandString = commandString;
|
||||
|
||||
// The default executor should be used if no argument is provided
|
||||
if (!hasArgument) {
|
||||
if (queryResult.argsInput().isEmpty()) {
|
||||
Optional<CommandSyntax> optionalSyntax = command.getSyntaxes()
|
||||
.stream()
|
||||
.filter(syntax -> syntax.getArguments().length == 0)
|
||||
|
@ -170,21 +144,21 @@ public class CommandDispatcher {
|
|||
final CommandSyntax syntax = optionalSyntax.get();
|
||||
parsedCommand.syntax = syntax;
|
||||
parsedCommand.executor = syntax.getExecutor();
|
||||
parsedCommand.context = new CommandContext(input);
|
||||
parsedCommand.context = new CommandContext(commandString);
|
||||
|
||||
result.type = CommandResult.Type.SUCCESS;
|
||||
result.parsedCommand = parsedCommand;
|
||||
return parsedCommand;
|
||||
return;
|
||||
} else {
|
||||
// No empty syntax, use default executor if any
|
||||
final CommandExecutor defaultExecutor = command.getDefaultExecutor();
|
||||
if (defaultExecutor != null) {
|
||||
parsedCommand.executor = defaultExecutor;
|
||||
parsedCommand.context = new CommandContext(input);
|
||||
parsedCommand.context = new CommandContext(commandString);
|
||||
|
||||
result.type = CommandResult.Type.SUCCESS;
|
||||
result.parsedCommand = parsedCommand;
|
||||
return parsedCommand;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,12 +174,12 @@ public class CommandDispatcher {
|
|||
Int2ObjectRBTreeMap<CommandSuggestionHolder> syntaxesSuggestions = new Int2ObjectRBTreeMap<>(Collections.reverseOrder());
|
||||
|
||||
for (CommandSyntax syntax : syntaxes) {
|
||||
CommandParser.parse(syntax, syntax.getArguments(), args, commandString, validSyntaxes, syntaxesSuggestions);
|
||||
CommandParser.parse(syntax, syntax.getArguments(), queryResult, validSyntaxes, syntaxesSuggestions);
|
||||
}
|
||||
|
||||
// Check if there is at least one correct syntax
|
||||
if (!validSyntaxes.isEmpty()) {
|
||||
CommandContext context = new CommandContext(input);
|
||||
CommandContext context = new CommandContext(commandString);
|
||||
// Search the syntax with all perfect args
|
||||
final ValidSyntaxHolder finalValidSyntax = CommandParser.findMostCorrectSyntax(validSyntaxes, context);
|
||||
if (finalValidSyntax != null) {
|
||||
|
@ -218,7 +192,7 @@ public class CommandDispatcher {
|
|||
|
||||
result.type = CommandResult.Type.SUCCESS;
|
||||
result.parsedCommand = parsedCommand;
|
||||
return parsedCommand;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,13 +212,12 @@ public class CommandDispatcher {
|
|||
|
||||
result.type = CommandResult.Type.INVALID_SYNTAX;
|
||||
result.parsedCommand = parsedCommand;
|
||||
return parsedCommand;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No syntax found
|
||||
result.type = CommandResult.Type.INVALID_SYNTAX;
|
||||
result.parsedCommand = ParsedCommand.withDefaultExecutor(command, input);
|
||||
return result.parsedCommand;
|
||||
result.parsedCommand = ParsedCommand.withDefaultExecutor(command, commandString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import net.minestom.server.command.builder.NodeMaker;
|
|||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||
import net.minestom.server.command.builder.parser.CommandParser;
|
||||
import net.minestom.server.command.builder.parser.ValidSyntaxHolder;
|
||||
import net.minestom.server.utils.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -26,14 +25,12 @@ public class ArgumentGroup extends Argument<CommandContext> {
|
|||
@Override
|
||||
public CommandContext parse(@NotNull String input) throws ArgumentSyntaxException {
|
||||
List<ValidSyntaxHolder> validSyntaxes = new ArrayList<>();
|
||||
CommandParser.parse(null, group, input.split(StringUtils.SPACE), input, validSyntaxes, null);
|
||||
CommandParser.parse(null, group, input, input, validSyntaxes, null);
|
||||
|
||||
CommandContext context = new CommandContext(input);
|
||||
CommandParser.findMostCorrectSyntax(validSyntaxes, context);
|
||||
if (validSyntaxes.isEmpty()) {
|
||||
if (validSyntaxes.isEmpty())
|
||||
throw new ArgumentSyntaxException("Invalid arguments", input, INVALID_ARGUMENTS_ERROR);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,10 @@ package net.minestom.server.command.builder.parser;
|
|||
|
||||
import net.minestom.server.command.builder.arguments.*;
|
||||
import net.minestom.server.command.builder.arguments.minecraft.*;
|
||||
import net.minestom.server.command.builder.arguments.minecraft.registry.*;
|
||||
import net.minestom.server.command.builder.arguments.minecraft.registry.ArgumentEnchantment;
|
||||
import net.minestom.server.command.builder.arguments.minecraft.registry.ArgumentEntityType;
|
||||
import net.minestom.server.command.builder.arguments.minecraft.registry.ArgumentParticle;
|
||||
import net.minestom.server.command.builder.arguments.minecraft.registry.ArgumentPotionEffect;
|
||||
import net.minestom.server.command.builder.arguments.number.ArgumentDouble;
|
||||
import net.minestom.server.command.builder.arguments.number.ArgumentFloat;
|
||||
import net.minestom.server.command.builder.arguments.number.ArgumentInteger;
|
||||
|
@ -41,10 +44,10 @@ public class ArgumentParser {
|
|||
ARGUMENT_FUNCTION_MAP.put("time", ArgumentTime::new);
|
||||
ARGUMENT_FUNCTION_MAP.put("enchantment", ArgumentEnchantment::new);
|
||||
ARGUMENT_FUNCTION_MAP.put("particle", ArgumentParticle::new);
|
||||
ARGUMENT_FUNCTION_MAP.put("resourceLocation", ArgumentResourceLocation::new);
|
||||
ARGUMENT_FUNCTION_MAP.put("resourcelocation", ArgumentResourceLocation::new);
|
||||
ARGUMENT_FUNCTION_MAP.put("potion", ArgumentPotionEffect::new);
|
||||
ARGUMENT_FUNCTION_MAP.put("entityType", ArgumentEntityType::new);
|
||||
ARGUMENT_FUNCTION_MAP.put("blockState", ArgumentBlockState::new);
|
||||
ARGUMENT_FUNCTION_MAP.put("entitytype", ArgumentEntityType::new);
|
||||
ARGUMENT_FUNCTION_MAP.put("blockstate", ArgumentBlockState::new);
|
||||
ARGUMENT_FUNCTION_MAP.put("intrange", ArgumentIntRange::new);
|
||||
ARGUMENT_FUNCTION_MAP.put("floatrange", ArgumentFloatRange::new);
|
||||
|
||||
|
@ -66,7 +69,6 @@ public class ArgumentParser {
|
|||
@ApiStatus.Experimental
|
||||
public static @NotNull Argument<?>[] generate(@NotNull String format) {
|
||||
List<Argument<?>> result = new ArrayList<>();
|
||||
|
||||
// 0 = no state
|
||||
// 1 = inside angle bracket <>
|
||||
int state = 0;
|
||||
|
@ -75,11 +77,9 @@ public class ArgumentParser {
|
|||
Function<String, Argument<?>> argumentFunction = null;
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
// test: Integer<name> String<hey>
|
||||
for (int i = 0; i < format.length(); i++) {
|
||||
char c = format.charAt(i);
|
||||
|
||||
final char c = format.charAt(i);
|
||||
// No state
|
||||
if (state == 0) {
|
||||
if (c == ' ') {
|
||||
|
@ -133,17 +133,15 @@ public class ArgumentParser {
|
|||
result.add(new ArgumentLiteral(argument));
|
||||
}
|
||||
}
|
||||
|
||||
return result.toArray(Argument[]::new);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ArgumentResult validate(@NotNull Argument<?> argument,
|
||||
@NotNull Argument<?>[] arguments, int argIndex,
|
||||
@NotNull String[] inputArguments, int inputIndex) {
|
||||
final boolean end = inputIndex == inputArguments.length;
|
||||
if (end) // Stop if there is no input to analyze left
|
||||
return null;
|
||||
public static @Nullable ArgumentResult validate(@NotNull Argument<?> argument,
|
||||
@NotNull Argument<?>[] arguments, int argIndex,
|
||||
@NotNull String input, int inputIndex) {
|
||||
final String[] inputArguments = input.split(StringUtils.SPACE);
|
||||
// Stop if there is no input to analyze left
|
||||
if (inputIndex == inputArguments.length) return null;
|
||||
|
||||
// the parsed argument value, null if incorrect
|
||||
Object parsedValue = null;
|
||||
|
@ -162,13 +160,10 @@ public class ArgumentParser {
|
|||
// Argument is supposed to take the rest of the command input
|
||||
for (int i = inputIndex; i < inputArguments.length; i++) {
|
||||
final String arg = inputArguments[i];
|
||||
if (builder.length() > 0)
|
||||
builder.append(StringUtils.SPACE);
|
||||
if (builder.length() > 0) builder.append(StringUtils.SPACE);
|
||||
builder.append(arg);
|
||||
}
|
||||
|
||||
rawArg = builder.toString();
|
||||
|
||||
try {
|
||||
parsedValue = argument.parse(rawArg);
|
||||
correct = true;
|
||||
|
@ -181,29 +176,22 @@ public class ArgumentParser {
|
|||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = inputIndex; i < inputArguments.length; i++) {
|
||||
builder.append(inputArguments[i]);
|
||||
|
||||
rawArg = builder.toString();
|
||||
|
||||
try {
|
||||
parsedValue = argument.parse(rawArg);
|
||||
|
||||
// Prevent quitting the parsing too soon if the argument
|
||||
// does not allow space
|
||||
final boolean lastArgumentIteration = argIndex + 1 == arguments.length;
|
||||
if (lastArgumentIteration && i + 1 < inputArguments.length) {
|
||||
if (!argument.allowSpace())
|
||||
break;
|
||||
if (!argument.allowSpace()) break;
|
||||
builder.append(StringUtils.SPACE);
|
||||
continue;
|
||||
}
|
||||
|
||||
correct = true;
|
||||
|
||||
inputIndex = i + 1;
|
||||
break;
|
||||
} catch (ArgumentSyntaxException exception) {
|
||||
argumentSyntaxException = exception;
|
||||
|
||||
if (!argument.allowSpace()) {
|
||||
// rawArg should be the remaining
|
||||
for (int j = i + 1; j < inputArguments.length; j++) {
|
||||
|
@ -247,5 +235,4 @@ public class ArgumentParser {
|
|||
// If correct
|
||||
public Object parsedValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,7 +11,10 @@ import net.minestom.server.utils.StringUtils;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static net.minestom.server.command.builder.parser.ArgumentParser.validate;
|
||||
|
@ -19,51 +22,43 @@ import static net.minestom.server.command.builder.parser.ArgumentParser.validate
|
|||
/**
|
||||
* Class used to parse complete command inputs.
|
||||
*/
|
||||
public class CommandParser {
|
||||
|
||||
public final class CommandParser {
|
||||
private static final CommandManager COMMAND_MANAGER = MinecraftServer.getCommandManager();
|
||||
|
||||
@Nullable
|
||||
public static CommandQueryResult findCommand(@Nullable Command parentCommand, @NotNull String commandName, @NotNull String[] args) {
|
||||
public static @Nullable CommandQueryResult findCommand(@Nullable Command parentCommand, @NotNull String commandName,
|
||||
@NotNull String argsInput, @NotNull String input) {
|
||||
Command command = parentCommand == null ? COMMAND_MANAGER.getDispatcher().findCommand(commandName) : parentCommand;
|
||||
if (command == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CommandQueryResult commandQueryResult = new CommandQueryResult();
|
||||
commandQueryResult.command = command;
|
||||
commandQueryResult.commandName = commandName;
|
||||
commandQueryResult.args = args;
|
||||
|
||||
if (command == null) return null;
|
||||
// Search for subcommand
|
||||
if (args.length > 0) {
|
||||
final String subCommandName = args[0];
|
||||
final int nextArgIndex = argsInput.indexOf(StringUtils.SPACE);
|
||||
if (nextArgIndex != -1) {
|
||||
final String subCommandName = argsInput.substring(0, nextArgIndex);
|
||||
for (Command subcommand : command.getSubcommands()) {
|
||||
if (Command.isValidName(subcommand, subCommandName)) {
|
||||
final String[] subArgs = Arrays.copyOfRange(args, 1, args.length);
|
||||
commandQueryResult.command = subcommand;
|
||||
commandQueryResult.commandName = subCommandName;
|
||||
commandQueryResult.args = subArgs;
|
||||
return findCommand(subcommand, subCommandName, subArgs);
|
||||
final String updated = StringUtils.trimLeft(argsInput.replaceFirst(commandName, ""));
|
||||
return findCommand(subcommand, subCommandName, updated, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return commandQueryResult;
|
||||
return new CommandQueryResult(command, argsInput, input);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CommandQueryResult findCommand(@NotNull String input) {
|
||||
final String[] parts = input.split(StringUtils.SPACE);
|
||||
final String commandName = parts[0];
|
||||
|
||||
String[] args = new String[parts.length - 1];
|
||||
System.arraycopy(parts, 1, args, 0, args.length);
|
||||
return CommandParser.findCommand(null, commandName, args);
|
||||
public static @Nullable CommandQueryResult findCommand(@NotNull String input) {
|
||||
final String commandName;
|
||||
final String content;
|
||||
final int commandNameEnd = input.indexOf(StringUtils.SPACE);
|
||||
if (commandNameEnd != -1) {
|
||||
commandName = input.substring(0, commandNameEnd);
|
||||
content = StringUtils.trimLeft(input.replaceFirst(commandName, ""));
|
||||
} else {
|
||||
commandName = input;
|
||||
content = "";
|
||||
}
|
||||
return CommandParser.findCommand(null, commandName, content, input);
|
||||
}
|
||||
|
||||
public static void parse(@Nullable CommandSyntax syntax, @NotNull Argument<?>[] commandArguments, @NotNull String[] inputArguments,
|
||||
@NotNull String commandString,
|
||||
public static void parse(@Nullable CommandSyntax syntax, @NotNull Argument<?>[] commandArguments,
|
||||
@NotNull CommandQueryResult queryResult,
|
||||
@Nullable List<ValidSyntaxHolder> validSyntaxes,
|
||||
@Nullable Int2ObjectRBTreeMap<CommandSuggestionHolder> syntaxesSuggestions) {
|
||||
final Map<Argument<?>, ArgumentParser.ArgumentResult> argumentValueMap = new HashMap<>();
|
||||
|
@ -76,10 +71,8 @@ public class CommandParser {
|
|||
// Check the validity of the arguments...
|
||||
for (int argIndex = 0; argIndex < commandArguments.length; argIndex++) {
|
||||
final Argument<?> argument = commandArguments[argIndex];
|
||||
ArgumentParser.ArgumentResult argumentResult = validate(argument, commandArguments, argIndex, inputArguments, inputIndex);
|
||||
if (argumentResult == null) {
|
||||
break;
|
||||
}
|
||||
ArgumentParser.ArgumentResult argumentResult = validate(argument, commandArguments, argIndex, queryResult.argsInput(), inputIndex);
|
||||
if (argumentResult == null) break;
|
||||
|
||||
// Update local var
|
||||
useRemaining = argumentResult.useRemaining;
|
||||
|
@ -107,7 +100,7 @@ public class CommandParser {
|
|||
if (commandArguments.length == argumentValueMap.size() || useRemaining) {
|
||||
if (validSyntaxes != null) {
|
||||
ValidSyntaxHolder validSyntaxHolder = new ValidSyntaxHolder();
|
||||
validSyntaxHolder.commandString = commandString;
|
||||
validSyntaxHolder.commandString = queryResult.input();
|
||||
validSyntaxHolder.syntax = syntax;
|
||||
validSyntaxHolder.argumentResults = argumentValueMap;
|
||||
|
||||
|
@ -125,27 +118,20 @@ public class CommandParser {
|
|||
* @param context the recipient of the argument parsed values
|
||||
* @return the command syntax with all of its arguments correct and with the most arguments count, null if not any
|
||||
*/
|
||||
@Nullable
|
||||
public static ValidSyntaxHolder findMostCorrectSyntax(@NotNull List<ValidSyntaxHolder> validSyntaxes,
|
||||
@NotNull CommandContext context) {
|
||||
if (validSyntaxes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
public static @Nullable ValidSyntaxHolder findMostCorrectSyntax(@NotNull List<ValidSyntaxHolder> validSyntaxes,
|
||||
@NotNull CommandContext context) {
|
||||
if (validSyntaxes.isEmpty()) return null;
|
||||
|
||||
ValidSyntaxHolder finalSyntax = null;
|
||||
int maxArguments = 0;
|
||||
CommandContext finalContext = null;
|
||||
|
||||
for (ValidSyntaxHolder validSyntaxHolder : validSyntaxes) {
|
||||
final Map<Argument<?>, ArgumentParser.ArgumentResult> argsValues = validSyntaxHolder.argumentResults;
|
||||
|
||||
final int argsSize = argsValues.size();
|
||||
|
||||
// Check if the syntax has more valid arguments
|
||||
if (argsSize > maxArguments) {
|
||||
finalSyntax = validSyntaxHolder;
|
||||
maxArguments = argsSize;
|
||||
|
||||
// Fill arguments map
|
||||
finalContext = new CommandContext(validSyntaxHolder.commandString);
|
||||
for (var entry : argsValues.entrySet()) {
|
||||
|
@ -155,30 +141,21 @@ public class CommandParser {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the arguments values
|
||||
if (finalSyntax != null) {
|
||||
context.copy(finalContext);
|
||||
}
|
||||
|
||||
if (finalSyntax != null) context.copy(finalContext);
|
||||
return finalSyntax;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ArgumentQueryResult findEligibleArgument(@NotNull Command command, String[] args, String commandString,
|
||||
boolean trailingSpace, boolean forceCorrect,
|
||||
Predicate<CommandSyntax> syntaxPredicate,
|
||||
Predicate<Argument<?>> argumentPredicate) {
|
||||
final Collection<CommandSyntax> syntaxes = command.getSyntaxes();
|
||||
|
||||
public static @Nullable ArgumentQueryResult findEligibleArgument(@NotNull CommandQueryResult result,
|
||||
boolean trailingSpace, boolean forceCorrect,
|
||||
Predicate<CommandSyntax> syntaxPredicate,
|
||||
Predicate<Argument<?>> argumentPredicate) {
|
||||
final String[] args = result.argsInput().split(StringUtils.SPACE);
|
||||
Int2ObjectRBTreeMap<ArgumentQueryResult> suggestions = new Int2ObjectRBTreeMap<>(Collections.reverseOrder());
|
||||
for (CommandSyntax syntax : result.command().getSyntaxes()) {
|
||||
if (!syntaxPredicate.test(syntax)) continue;
|
||||
|
||||
for (CommandSyntax syntax : syntaxes) {
|
||||
if (!syntaxPredicate.test(syntax)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final CommandContext context = new CommandContext(commandString);
|
||||
final CommandContext context = new CommandContext(result.input());
|
||||
|
||||
final Argument<?>[] commandArguments = syntax.getArguments();
|
||||
int inputIndex = 0;
|
||||
|
@ -187,7 +164,7 @@ public class CommandParser {
|
|||
int maxArgIndex = 0;
|
||||
for (int argIndex = 0; argIndex < commandArguments.length; argIndex++) {
|
||||
Argument<?> argument = commandArguments[argIndex];
|
||||
ArgumentParser.ArgumentResult argumentResult = validate(argument, commandArguments, argIndex, args, inputIndex);
|
||||
ArgumentParser.ArgumentResult argumentResult = validate(argument, commandArguments, argIndex, result.argsInput(), inputIndex);
|
||||
if (argumentResult == null) {
|
||||
// Nothing to analyze, create a dummy object
|
||||
argumentResult = new ArgumentParser.ArgumentResult();
|
||||
|
@ -219,29 +196,17 @@ public class CommandParser {
|
|||
}
|
||||
|
||||
// Don't compute following arguments if the syntax is incorrect
|
||||
if (!argumentResult.correct) {
|
||||
break;
|
||||
}
|
||||
if (!argumentResult.correct) break;
|
||||
|
||||
// Don't compute unrelated arguments
|
||||
final boolean isLast = inputIndex == args.length;
|
||||
if (isLast && !trailingSpace) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (maxArg != null) {
|
||||
suggestions.put(maxArgIndex, maxArg);
|
||||
if (isLast && !trailingSpace) break;
|
||||
}
|
||||
if (maxArg != null) suggestions.put(maxArgIndex, maxArg);
|
||||
}
|
||||
|
||||
if (suggestions.isEmpty()) {
|
||||
// No suggestion
|
||||
return null;
|
||||
}
|
||||
|
||||
if (suggestions.isEmpty()) return null;
|
||||
final int max = suggestions.firstIntKey();
|
||||
return suggestions.get(max);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,8 +2,26 @@ package net.minestom.server.command.builder.parser;
|
|||
|
||||
import net.minestom.server.command.builder.Command;
|
||||
|
||||
public class CommandQueryResult {
|
||||
public Command command;
|
||||
public String commandName;
|
||||
public String[] args;
|
||||
public final class CommandQueryResult {
|
||||
private final Command command;
|
||||
private final String argsInput;
|
||||
private final String input;
|
||||
|
||||
public CommandQueryResult(Command command, String argsInput, String input) {
|
||||
this.command = command;
|
||||
this.argsInput = argsInput;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public Command command() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public String argsInput() {
|
||||
return argsInput;
|
||||
}
|
||||
|
||||
public String input() {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,13 +27,8 @@ public class TabCompleteListener {
|
|||
String args = commandString.replaceFirst(Pattern.quote(commandName), "");
|
||||
|
||||
final CommandQueryResult commandQueryResult = CommandParser.findCommand(commandString);
|
||||
if (commandQueryResult == null) {
|
||||
// Command not found
|
||||
return;
|
||||
}
|
||||
|
||||
final ArgumentQueryResult queryResult = CommandParser.findEligibleArgument(commandQueryResult.command,
|
||||
commandQueryResult.args, commandString, text.endsWith(StringUtils.SPACE), false,
|
||||
if (commandQueryResult == null) return;
|
||||
final ArgumentQueryResult queryResult = CommandParser.findEligibleArgument(commandQueryResult, text.endsWith(StringUtils.SPACE), false,
|
||||
CommandSyntax::hasSuggestion, Argument::hasSuggestion);
|
||||
if (queryResult == null) {
|
||||
// Suggestible argument not found
|
||||
|
|
|
@ -21,6 +21,12 @@ public class StringUtils {
|
|||
return count;
|
||||
}
|
||||
|
||||
public static String trimLeft(String input) {
|
||||
int i = 0;
|
||||
while (i < input.length() && Character.isWhitespace(input.charAt(i))) i++;
|
||||
return input.substring(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the Jaro-Winkler distance algorithm to the given strings, providing information about the
|
||||
* similarity of them.
|
||||
|
|
Loading…
Reference in New Issue