Allow overriding of all argument suggestions

This commit is contained in:
Alexander Söderberg 2020-09-19 23:23:28 +02:00
parent 62bc4dc005
commit 95f903bb1f
No known key found for this signature in database
GPG key ID: C0207FF7EA146678
15 changed files with 156 additions and 46 deletions

View file

@ -299,18 +299,18 @@ public final class CommandTree<C> {
return Collections.emptyList();
// return child.getValue().getParser().suggestions(commandContext, "");
} else if (child.isLeaf() && commandQueue.size() < 2) {
return child.getValue().getParser().suggestions(commandContext, commandQueue.peek());
return child.getValue().getSuggestionsProvider().apply(commandContext, commandQueue.peek());
} else if (child.isLeaf()) {
return Collections.emptyList();
} else if (commandQueue.peek().isEmpty()) {
return child.getValue().getParser().suggestions(commandContext, commandQueue.remove());
return child.getValue().getSuggestionsProvider().apply(commandContext, commandQueue.remove());
}
final ArgumentParseResult<?> result = child.getValue().getParser().parse(commandContext, commandQueue);
if (result.getParsedValue().isPresent()) {
commandContext.store(child.getValue().getName(), result.getParsedValue().get());
return this.getSuggestions(commandContext, commandQueue, child);
} else if (result.getFailure().isPresent()) {
return child.getValue().getParser().suggestions(commandContext, commandQueue.peek());
return child.getValue().getSuggestionsProvider().apply(commandContext, commandQueue.peek());
}
}
}
@ -336,8 +336,8 @@ public final class CommandTree<C> {
if (argument.getValue() == null || this.isPermitted(commandContext.getSender(), argument) != null) {
continue;
}
suggestions.addAll(
argument.getValue().getParser().suggestions(commandContext, stringOrEmpty(commandQueue.peek())));
suggestions.addAll(argument.getValue().getSuggestionsProvider()
.apply(commandContext, stringOrEmpty(commandQueue.peek())));
}
return suggestions;
}

View file

@ -29,10 +29,13 @@ import com.intellectualsites.commands.CommandManager;
import com.intellectualsites.commands.arguments.parser.ArgumentParseResult;
import com.intellectualsites.commands.arguments.parser.ArgumentParser;
import com.intellectualsites.commands.arguments.parser.ParserParameters;
import com.intellectualsites.commands.context.CommandContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.regex.Pattern;
/**
@ -75,6 +78,10 @@ public class CommandArgument<C, T> implements Comparable<CommandArgument<?, ?>>
* The type that is produces by the argument's parser
*/
private final Class<T> valueType;
/**
* Suggestion provider
*/
private final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider;
private Command<C> owningCommand;
@ -86,12 +93,14 @@ public class CommandArgument<C, T> implements Comparable<CommandArgument<?, ?>>
* @param parser The argument parser
* @param defaultValue Default value used when no value is provided by the command sender
* @param valueType Type produced by the parser
* @param suggestionsProvider Suggestions provider
*/
public CommandArgument(final boolean required,
@Nonnull final String name,
@Nonnull final ArgumentParser<C, T> parser,
@Nonnull final String defaultValue,
@Nonnull final Class<T> valueType) {
@Nonnull final Class<T> valueType,
@Nullable final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
this.required = required;
this.name = Objects.requireNonNull(name, "Name may not be null");
if (!NAME_PATTERN.asPredicate().test(name)) {
@ -100,6 +109,9 @@ public class CommandArgument<C, T> implements Comparable<CommandArgument<?, ?>>
this.parser = Objects.requireNonNull(parser, "Parser may not be null");
this.defaultValue = defaultValue;
this.valueType = valueType;
this.suggestionsProvider = suggestionsProvider == null
? buildDefaultSuggestionsProvider(this)
: suggestionsProvider;
}
/**
@ -114,7 +126,12 @@ public class CommandArgument<C, T> implements Comparable<CommandArgument<?, ?>>
@Nonnull final String name,
@Nonnull final ArgumentParser<C, T> parser,
@Nonnull final Class<T> valueType) {
this(required, name, parser, "", valueType);
this(required, name, parser, "", valueType, null);
}
private static <C> BiFunction<CommandContext<C>, String, List<String>> buildDefaultSuggestionsProvider(
@Nonnull final CommandArgument<C, ?> argument) {
return (context, s) -> argument.getParser().suggestions(context, s);
}
/**
@ -190,6 +207,16 @@ public class CommandArgument<C, T> implements Comparable<CommandArgument<?, ?>>
this.owningCommand = owningCommand;
}
/**
* Get the argument suggestions provider
*
* @return Suggestions provider
*/
@Nonnull
public final BiFunction<CommandContext<C>, String, List<String>> getSuggestionsProvider() {
return this.suggestionsProvider;
}
@Override
public final boolean equals(final Object o) {
if (this == o) {
@ -269,6 +296,7 @@ public class CommandArgument<C, T> implements Comparable<CommandArgument<?, ?>>
private boolean required = true;
private ArgumentParser<C, T> parser;
private String defaultValue = "";
private BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider;
protected Builder(@Nonnull final Class<T> valueType,
@Nonnull final String name) {
@ -348,6 +376,19 @@ public class CommandArgument<C, T> implements Comparable<CommandArgument<?, ?>>
return this;
}
/**
* Set the suggestions provider
*
* @param suggestionsProvider Suggestions provider
* @return Builder instance
*/
@Nonnull
public Builder<C, T> withSuggestionsProvider(
@Nonnull final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
this.suggestionsProvider = suggestionsProvider;
return this;
}
/**
* Construct a command argument from the builder settings
*
@ -363,7 +404,11 @@ public class CommandArgument<C, T> implements Comparable<CommandArgument<?, ?>>
this.parser = (c, i) -> ArgumentParseResult
.failure(new UnsupportedOperationException("No parser was specified"));
}
return new CommandArgument<>(this.required, this.name, this.parser, this.defaultValue, this.valueType);
if (suggestionsProvider == null) {
suggestionsProvider = this.parser::suggestions;
}
return new CommandArgument<>(this.required, this.name, this.parser,
this.defaultValue, this.valueType, this.suggestionsProvider);
}
@Nonnull
@ -384,6 +429,12 @@ public class CommandArgument<C, T> implements Comparable<CommandArgument<?, ?>>
protected final String getDefaultValue() {
return this.defaultValue;
}
@Nonnull
protected final BiFunction<CommandContext<C>, String, List<String>> getSuggestionsProvider() {
return this.suggestionsProvider;
}
}
}

View file

@ -29,17 +29,20 @@ import com.intellectualsites.commands.arguments.parser.ArgumentParser;
import com.intellectualsites.commands.context.CommandContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.Queue;
import java.util.function.BiFunction;
@SuppressWarnings("unused")
public final class BooleanArgument<C> extends CommandArgument<C, Boolean> {
private final boolean liberal;
private BooleanArgument(final boolean required, @Nonnull final String name,
final boolean liberal, @Nonnull final String defaultValue) {
super(required, name, new BooleanParser<>(liberal), defaultValue, Boolean.class);
final boolean liberal, @Nonnull final String defaultValue,
@Nullable final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
super(required, name, new BooleanParser<>(liberal), defaultValue, Boolean.class, suggestionsProvider);
this.liberal = liberal;
}
@ -130,7 +133,8 @@ public final class BooleanArgument<C> extends CommandArgument<C, Boolean> {
@Nonnull
@Override
public BooleanArgument<C> build() {
return new BooleanArgument<>(this.isRequired(), this.getName(), this.liberal, this.getDefaultValue());
return new BooleanArgument<>(this.isRequired(), this.getName(), this.liberal,
this.getDefaultValue(), this.getSuggestionsProvider());
}
}

View file

@ -30,8 +30,10 @@ import com.intellectualsites.commands.context.CommandContext;
import com.intellectualsites.commands.exceptions.parsing.NumberParseException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Queue;
import java.util.function.BiFunction;
@SuppressWarnings("unused")
public final class ByteArgument<C> extends CommandArgument<C, Byte> {
@ -40,8 +42,9 @@ public final class ByteArgument<C> extends CommandArgument<C, Byte> {
private final byte max;
private ByteArgument(final boolean required, @Nonnull final String name, final byte min,
final byte max, final String defaultValue) {
super(required, name, new ByteParser<>(min, max), defaultValue, Byte.class);
final byte max, final String defaultValue,
@Nullable final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
super(required, name, new ByteParser<>(min, max), defaultValue, Byte.class, suggestionsProvider);
this.min = min;
this.max = max;
}
@ -155,7 +158,8 @@ public final class ByteArgument<C> extends CommandArgument<C, Byte> {
@Nonnull
@Override
public ByteArgument<C> build() {
return new ByteArgument<>(this.isRequired(), this.getName(), this.min, this.max, this.getDefaultValue());
return new ByteArgument<>(this.isRequired(), this.getName(), this.min, this.max,
this.getDefaultValue(), this.getSuggestionsProvider());
}
}

View file

@ -29,14 +29,18 @@ import com.intellectualsites.commands.arguments.parser.ArgumentParser;
import com.intellectualsites.commands.context.CommandContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Queue;
import java.util.function.BiFunction;
@SuppressWarnings("unused")
public final class CharArgument<C> extends CommandArgument<C, Character> {
private CharArgument(final boolean required, @Nonnull final String name,
@Nonnull final String defaultValue) {
super(required, name, new CharacterParser<>(), defaultValue, Character.class);
@Nonnull final String defaultValue, @Nullable
final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
super(required, name, new CharacterParser<>(), defaultValue, Character.class, suggestionsProvider);
}
/**
@ -104,7 +108,8 @@ public final class CharArgument<C> extends CommandArgument<C, Character> {
@Nonnull
@Override
public CharArgument<C> build() {
return new CharArgument<>(this.isRequired(), this.getName(), this.getDefaultValue());
return new CharArgument<>(this.isRequired(), this.getName(),
this.getDefaultValue(), this.getSuggestionsProvider());
}
}

View file

@ -30,7 +30,10 @@ import com.intellectualsites.commands.context.CommandContext;
import com.intellectualsites.commands.exceptions.parsing.NumberParseException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Queue;
import java.util.function.BiFunction;
@SuppressWarnings("unused")
public final class DoubleArgument<C> extends CommandArgument<C, Double> {
@ -42,8 +45,9 @@ public final class DoubleArgument<C> extends CommandArgument<C, Double> {
@Nonnull final String name,
final double min,
final double max,
final String defaultValue) {
super(required, name, new DoubleParser<>(min, max), defaultValue, Double.class);
final String defaultValue,
@Nullable final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
super(required, name, new DoubleParser<>(min, max), defaultValue, Double.class, suggestionsProvider);
this.min = min;
this.max = max;
}
@ -157,7 +161,8 @@ public final class DoubleArgument<C> extends CommandArgument<C, Double> {
@Nonnull
@Override
public DoubleArgument<C> build() {
return new DoubleArgument<>(this.isRequired(), this.getName(), this.min, this.max, this.getDefaultValue());
return new DoubleArgument<>(this.isRequired(), this.getName(), this.min, this.max,
this.getDefaultValue(), this.getSuggestionsProvider());
}
}

View file

@ -29,9 +29,11 @@ import com.intellectualsites.commands.arguments.parser.ArgumentParser;
import com.intellectualsites.commands.context.CommandContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.EnumSet;
import java.util.List;
import java.util.Queue;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
/**
@ -46,8 +48,9 @@ public class EnumArgument<C, E extends Enum<E>> extends CommandArgument<C, E> {
protected EnumArgument(@Nonnull final Class<E> enumClass,
final boolean required,
@Nonnull final String name,
@Nonnull final String defaultValue) {
super(required, name, new EnumParser<>(enumClass), defaultValue, enumClass);
@Nonnull final String defaultValue,
@Nullable final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
super(required, name, new EnumParser<>(enumClass), defaultValue, enumClass, suggestionsProvider);
}
/**
@ -124,7 +127,8 @@ public class EnumArgument<C, E extends Enum<E>> extends CommandArgument<C, E> {
@Nonnull
@Override
public CommandArgument<C, E> build() {
return new EnumArgument<>(this.enumClass, this.isRequired(), this.getName(), this.getDefaultValue());
return new EnumArgument<>(this.enumClass, this.isRequired(), this.getName(),
this.getDefaultValue(), this.getSuggestionsProvider());
}
}

View file

@ -30,7 +30,10 @@ import com.intellectualsites.commands.context.CommandContext;
import com.intellectualsites.commands.exceptions.parsing.NumberParseException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Queue;
import java.util.function.BiFunction;
@SuppressWarnings("unused")
public final class FloatArgument<C> extends CommandArgument<C, Float> {
@ -42,8 +45,9 @@ public final class FloatArgument<C> extends CommandArgument<C, Float> {
@Nonnull final String name,
final float min,
final float max,
final String defaultValue) {
super(required, name, new FloatParser<>(min, max), defaultValue, Float.class);
final String defaultValue,
@Nullable final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
super(required, name, new FloatParser<>(min, max), defaultValue, Float.class, suggestionsProvider);
this.min = min;
this.max = max;
}
@ -157,7 +161,8 @@ public final class FloatArgument<C> extends CommandArgument<C, Float> {
@Nonnull
@Override
public FloatArgument<C> build() {
return new FloatArgument<>(this.isRequired(), this.getName(), this.min, this.max, this.getDefaultValue());
return new FloatArgument<>(this.isRequired(), this.getName(), this.min, this.max,
this.getDefaultValue(), this.getSuggestionsProvider());
}
}

View file

@ -30,10 +30,12 @@ import com.intellectualsites.commands.context.CommandContext;
import com.intellectualsites.commands.exceptions.parsing.NumberParseException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@ -50,8 +52,9 @@ public final class IntegerArgument<C> extends CommandArgument<C, Integer> {
@Nonnull final String name,
final int min,
final int max,
final String defaultValue) {
super(required, name, new IntegerParser<>(min, max), defaultValue, Integer.class);
final String defaultValue,
@Nullable final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
super(required, name, new IntegerParser<>(min, max), defaultValue, Integer.class, suggestionsProvider);
this.min = min;
this.max = max;
}
@ -165,7 +168,8 @@ public final class IntegerArgument<C> extends CommandArgument<C, Integer> {
@Nonnull
@Override
public IntegerArgument<C> build() {
return new IntegerArgument<>(this.isRequired(), this.getName(), this.min, this.max, this.getDefaultValue());
return new IntegerArgument<>(this.isRequired(), this.getName(), this.min, this.max,
this.getDefaultValue(), this.getSuggestionsProvider());
}
}

View file

@ -30,8 +30,10 @@ import com.intellectualsites.commands.context.CommandContext;
import com.intellectualsites.commands.exceptions.parsing.NumberParseException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Queue;
import java.util.function.BiFunction;
@SuppressWarnings("unused")
public final class LongArgument<C> extends CommandArgument<C, Long> {
@ -43,8 +45,9 @@ public final class LongArgument<C> extends CommandArgument<C, Long> {
@Nonnull final String name,
final long min,
final long max,
final String defaultValue) {
super(required, name, new LongParser<>(min, max), defaultValue, Long.class);
final String defaultValue,
@Nullable final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
super(required, name, new LongParser<>(min, max), defaultValue, Long.class, suggestionsProvider);
this.min = min;
this.max = max;
}
@ -158,7 +161,8 @@ public final class LongArgument<C> extends CommandArgument<C, Long> {
@Nonnull
@Override
public LongArgument<C> build() {
return new LongArgument<>(this.isRequired(), this.getName(), this.min, this.max, this.getDefaultValue());
return new LongArgument<>(this.isRequired(), this.getName(), this.min,
this.max, this.getDefaultValue(), this.getSuggestionsProvider());
}
}

View file

@ -30,8 +30,10 @@ import com.intellectualsites.commands.context.CommandContext;
import com.intellectualsites.commands.exceptions.parsing.NumberParseException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Queue;
import java.util.function.BiFunction;
@SuppressWarnings("unused")
public final class ShortArgument<C> extends CommandArgument<C, Short> {
@ -43,8 +45,9 @@ public final class ShortArgument<C> extends CommandArgument<C, Short> {
@Nonnull final String name,
final short min,
final short max,
final String defaultValue) {
super(required, name, new ShortParser<>(min, max), defaultValue, Short.class);
final String defaultValue,
@Nullable final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
super(required, name, new ShortParser<>(min, max), defaultValue, Short.class, suggestionsProvider);
this.min = min;
this.max = max;
}
@ -158,7 +161,8 @@ public final class ShortArgument<C> extends CommandArgument<C, Short> {
@Nonnull
@Override
public ShortArgument<C> build() {
return new ShortArgument<>(this.isRequired(), this.getName(), this.min, this.max, this.getDefaultValue());
return new ShortArgument<>(this.isRequired(), this.getName(), this.min, this.max,
this.getDefaultValue(), this.getSuggestionsProvider());
}
}

View file

@ -45,7 +45,8 @@ public final class StringArgument<C> extends CommandArgument<C, String> {
@Nonnull final StringMode stringMode,
@Nonnull final String defaultValue,
@Nonnull final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
super(required, name, new StringParser<>(stringMode, suggestionsProvider), defaultValue, String.class);
super(required, name, new StringParser<>(stringMode, suggestionsProvider),
defaultValue, String.class, suggestionsProvider);
this.stringMode = stringMode;
}

View file

@ -58,6 +58,11 @@ public class CommandSuggestionsTest {
.argument(IntegerArgument.<TestCommandSender>newBuilder("num")
.withMin(1).withMax(95).asOptional().build())
.build());
manager.command(manager.commandBuilder("test")
.literal("alt")
.argument(IntegerArgument.<TestCommandSender>newBuilder("num")
.withSuggestionsProvider((c, s) -> Arrays.asList("3", "33", "333")).build())
.build());
}
@Test
@ -106,6 +111,13 @@ public class CommandSuggestionsTest {
Assertions.assertEquals(Arrays.asList("9", "90", "91", "92", "93", "94", "95"), suggestions3);
}
@Test
void testAltered() {
final String input = "test alt ";
final List<String> suggestions = manager.suggest(new TestCommandSender(), input);
Assertions.assertEquals(Arrays.asList("3", "33", "333"), suggestions);
}
public enum TestEnum {
FOO,

View file

@ -30,8 +30,11 @@ import com.intellectualsites.commands.context.CommandContext;
import org.bukkit.Material;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.EnumSet;
import java.util.List;
import java.util.Queue;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
/**
@ -43,8 +46,9 @@ public class MaterialArgument<C> extends CommandArgument<C, Material> {
protected MaterialArgument(final boolean required,
@Nonnull final String name,
@Nonnull final String defaultValue) {
super(required, name, new MaterialParser<>(), defaultValue, Material.class);
@Nonnull final String defaultValue,
@Nullable final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
super(required, name, new MaterialParser<>(), defaultValue, Material.class, suggestionsProvider);
}
/**

View file

@ -31,8 +31,10 @@ import org.bukkit.Bukkit;
import org.bukkit.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Queue;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
/**
@ -44,8 +46,9 @@ public class WorldArgument<C> extends CommandArgument<C, World> {
protected WorldArgument(final boolean required,
@Nonnull final String name,
@Nonnull final String defaultValue) {
super(required, name, new WorldParser<>(), defaultValue, World.class);
@Nonnull final String defaultValue,
@Nullable final BiFunction<CommandContext<C>, String, List<String>> suggestionsProvider) {
super(required, name, new WorldParser<>(), defaultValue, World.class, suggestionsProvider);
}
/**
@ -108,7 +111,7 @@ public class WorldArgument<C> extends CommandArgument<C, World> {
@Nonnull
@Override
public CommandArgument<C, World> build() {
return new WorldArgument<>(this.isRequired(), this.getName(), this.getDefaultValue());
return new WorldArgument<>(this.isRequired(), this.getName(), this.getDefaultValue(), this.getSuggestionsProvider());
}
}