BAZEL + some code
This commit is contained in:
parent
dd25337ed6
commit
4db84feb43
44 changed files with 627 additions and 389 deletions
|
|
@ -6,13 +6,14 @@ java_library(
|
|||
srcs = glob(["src/main/**/*.java"]),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
artifact("org.projectlombok:lombok"),
|
||||
artifact("com.leakyabstractions:result-api"),
|
||||
artifact("com.leakyabstractions:result"),
|
||||
artifact("org.jetbrains:annotations"),
|
||||
artifact("com.google.guava:guava"),
|
||||
artifact("org.slf4j:slf4j-api"),
|
||||
artifact("net.kyori:adventure-api"),
|
||||
artifact("org.projectlombok:lombok"),
|
||||
],
|
||||
plugins = [ "//third_party:lombok_plugin" ],
|
||||
)
|
||||
)
|
||||
load("@rules_java//toolchains:default_java_toolchain.bzl", "default_java_toolchain")
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
package de.kentoj.kencommandapi.api;
|
||||
|
||||
import de.kentoj.kencommandapi.api.invocation.CommandContext;
|
||||
import de.kentoj.kencommandapi.api.literal.RootLiteral;
|
||||
import de.kentoj.kencommandapi.api.literal.Literal;
|
||||
import de.kentoj.kencommandapi.api.platform.HasPermissionMethod;
|
||||
import de.kentoj.kencommandapi.api.platform.SendMessageMethod;
|
||||
import de.kentoj.kencommandapi.internal.parser.CommandParseHelper;
|
||||
import de.kentoj.kencommandapi.internal.parser.InvocationCommandParser;
|
||||
import de.kentoj.kencommandapi.internal.parser.SuggestionCommandParser;
|
||||
import de.kentoj.kencommandapi.api.platform.HasPermissionMethod;
|
||||
import de.kentoj.kencommandapi.api.platform.SendMessageMethod;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
|
@ -28,23 +27,25 @@ public class CommandHandler<T> {
|
|||
suggestionParser = new SuggestionCommandParser<>(parseHelper);
|
||||
}
|
||||
|
||||
@SuppressWarnings("CodeBlock2Expr")
|
||||
public void invoke(RootLiteral<T> rootLiteral, T sender, Stream<String> args) {
|
||||
public void invoke(Literal<T> rootLiteral, T sender, Stream<String> args) {
|
||||
// FIXME uses rootLiteral's message style
|
||||
invocationParser.parse(rootLiteral, sender, args.toList().iterator())
|
||||
.ifSuccessOrElse(data -> {
|
||||
var ctx = new CommandContext<>(sender, data.getArguments());
|
||||
data.getExecutor().execute(ctx).whenComplete((result, ex) -> {
|
||||
if (ex != null)
|
||||
sendMessageMethod.send(sender, rootLiteral.getMessageStyle().exception(ex));
|
||||
result.ifFailure(err ->
|
||||
sendMessageMethod.send(sender, rootLiteral.getMessageStyle().err(err)));
|
||||
});
|
||||
}, err -> {
|
||||
sendMessageMethod.send(sender, rootLiteral.getMessageStyle().err(err));
|
||||
.ifSuccessOrElse(data -> exec(rootLiteral, data),
|
||||
err -> sendMessageMethod.send(sender, rootLiteral.getMessageStyle().err(err)));
|
||||
}
|
||||
|
||||
private void exec(Literal<T> rootLiteral, InvocationCommandParser<T>.ExecutionData data) {
|
||||
var sender = data.getContext().getSender();
|
||||
data.getExecutor().execute(data.getContext())
|
||||
.whenComplete((result, ex) -> {
|
||||
if (ex != null)
|
||||
sendMessageMethod.send(sender, rootLiteral.getMessageStyle().exception(ex));
|
||||
result.ifFailure(err ->
|
||||
sendMessageMethod.send(sender, rootLiteral.getMessageStyle().err(err)));
|
||||
});
|
||||
}
|
||||
|
||||
public List<String> getSuggestions(RootLiteral<T> rootNode, T sender, String[] args, boolean trailingSpace) {
|
||||
public List<String> getSuggestions(Literal<T> rootNode, T sender, String[] args, boolean trailingSpace) {
|
||||
return suggestionParser.suggest(rootNode, sender, Arrays.stream(args).iterator(), trailingSpace);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package de.kentoj.kencommandapi.api.argument;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* @param <V> type of the parsed argument value
|
||||
*/
|
||||
@Value
|
||||
public class ArgumentRequirement<V> {
|
||||
Predicate<V> predicate;
|
||||
String message;
|
||||
}
|
||||
|
|
@ -2,14 +2,24 @@ package de.kentoj.kencommandapi.api.argument;
|
|||
|
||||
import de.kentoj.kencommandapi.api.suggestion.SuggestionProvider;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public interface ArgumentType<T, V> {
|
||||
|
||||
/**
|
||||
* parses the given input and returns it.
|
||||
* Unlike {@link CommandArgumentSpec#parseInput(String)}, this does not check any additional requirements.
|
||||
*
|
||||
* @throws IllegalArgumentException if string invalid
|
||||
* @see CommandArgumentSpec#parseInput(String)
|
||||
* @see CommandArgumentSpecBuilder#addRequirement(Predicate, String)
|
||||
*/
|
||||
V parseInput(String string);
|
||||
V parseInputUnchecked(String input) throws IllegalArgumentException;
|
||||
|
||||
SuggestionProvider<T> defaultSuggestionProvider();
|
||||
/**
|
||||
* @see CommandArgumentSpec#getSuggestionProvider()
|
||||
*/
|
||||
SuggestionProvider<T> getDefaultSuggestionProvider();
|
||||
|
||||
/**
|
||||
* @return whether this argument is greedy. Greedy arguments consume all remaining input instead of a single word.
|
||||
|
|
|
|||
|
|
@ -1,30 +1,8 @@
|
|||
package de.kentoj.kencommandapi.api.argument;
|
||||
|
||||
import de.kentoj.kencommandapi.api.suggestion.SuggestionProvider;
|
||||
import de.kentoj.kencommandapi.internal.CommandArgumentImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface CommandArgument<T, V> {
|
||||
|
||||
static <T, V> CommandArgument<T, V> arg(String id, ArgumentType<T, V> type) {
|
||||
return new CommandArgumentImpl<>(id, type);
|
||||
}
|
||||
V getValue();
|
||||
|
||||
String getId();
|
||||
|
||||
ArgumentType<T, V> getType();
|
||||
|
||||
void setDefaultValueProvider(@Nullable Function<T, V> defaultValueProvider);
|
||||
|
||||
@Nullable Function<T, V> getDefaultValueProvider();
|
||||
|
||||
void setSuggestionProvider(@Nullable SuggestionProvider<T> suggestionProvider);
|
||||
|
||||
/**
|
||||
* @return the explicitly set SuggestionProvider or the default suggestions for the type if unset/null
|
||||
*/
|
||||
@NotNull SuggestionProvider<T> getSuggestionProvider();
|
||||
CommandArgumentSpec<T, V> getArgument();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package de.kentoj.kencommandapi.api.argument;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
public class CommandArgumentImpl<T, V> implements CommandArgument<T, V> {
|
||||
V value;
|
||||
CommandArgumentSpec<T, V> argument;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package de.kentoj.kencommandapi.api.argument;
|
||||
|
||||
import de.kentoj.kencommandapi.api.invocation.CommandContext;
|
||||
import de.kentoj.kencommandapi.api.suggestion.SuggestionProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public sealed interface CommandArgumentSpec<T, V> permits CommandArgumentSpecImpl {
|
||||
|
||||
static <T, V> CommandArgumentSpecBuilder<T, V> builder(String id, ArgumentType<T, V> type) {
|
||||
return new CommandArgumentSpecBuilder<>(id, type);
|
||||
}
|
||||
|
||||
String getId();
|
||||
|
||||
ArgumentType<T, V> getType();
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if string invalid or if a requirement is not met
|
||||
*/
|
||||
V parseInput(String rawInput);
|
||||
|
||||
@Nullable Function<CommandContext<T>, V> getDefaultValueProvider();
|
||||
|
||||
/**
|
||||
* @return the explicitly set SuggestionProvider or the default suggestions for the type if unset/null
|
||||
*/
|
||||
/* explicit @NotNull to avoid confusion */
|
||||
@NotNull SuggestionProvider<T> getSuggestionProvider();
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package de.kentoj.kencommandapi.api.argument;
|
||||
|
||||
import de.kentoj.kencommandapi.api.invocation.CommandContext;
|
||||
import de.kentoj.kencommandapi.api.suggestion.SuggestionProvider;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* @param <T> type of the command sender
|
||||
* @param <V> type of the value
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public class CommandArgumentSpecBuilder<T, V> {
|
||||
|
||||
private final String id;
|
||||
private final ArgumentType<T, V> type;
|
||||
|
||||
private @Nullable Function<CommandContext<T>, V> defaultValueProvider;
|
||||
private @Nullable SuggestionProvider<T> suggestionProvider;
|
||||
|
||||
private final List<ArgumentRequirement<V>> requirements = new ArrayList<>();
|
||||
|
||||
public CommandArgumentSpecBuilder<T, V> withRequirement(Predicate<V> predicate, String message) {
|
||||
requirements.add(new ArgumentRequirement<>(predicate, message));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandArgumentSpecBuilder<T, V> withDefaultValue(@Nullable Function<CommandContext<T>, V> defaultValueProvider) {
|
||||
this.defaultValueProvider = defaultValueProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandArgumentSpecBuilder<T, V> withSuggestionProvider(@Nullable SuggestionProvider<T> suggestionProvider) {
|
||||
this.suggestionProvider = suggestionProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandArgumentSpec<T, V> build() {
|
||||
return new CommandArgumentSpecImpl<>(id, type, requirements, defaultValueProvider, suggestionProvider);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package de.kentoj.kencommandapi.api.argument;
|
||||
|
||||
import de.kentoj.kencommandapi.api.invocation.CommandContext;
|
||||
import de.kentoj.kencommandapi.api.suggestion.SuggestionProvider;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class CommandArgumentSpecImpl<T, V> implements CommandArgumentSpec<T, V> {
|
||||
@Getter
|
||||
private final String id;
|
||||
@Getter
|
||||
private final ArgumentType<T, V> type;
|
||||
private final List<ArgumentRequirement<V>> requirements;
|
||||
private final Function<CommandContext<T>, V> defaultValueProvider;
|
||||
private final @Nullable SuggestionProvider<T> suggestionProvider;
|
||||
|
||||
@Override
|
||||
public V parseInput(String rawInput) {
|
||||
var parsed = type.parseInputUnchecked(rawInput);
|
||||
for (var requirement : requirements) {
|
||||
if (!requirement.getPredicate().test(parsed))
|
||||
throw new IllegalArgumentException(requirement.getMessage());
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Function<CommandContext<T>, V> getDefaultValueProvider() {
|
||||
return defaultValueProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull SuggestionProvider<T> getSuggestionProvider() {
|
||||
return suggestionProvider != null ? suggestionProvider : type.getDefaultSuggestionProvider();
|
||||
}
|
||||
}
|
||||
|
|
@ -2,17 +2,16 @@ package de.kentoj.kencommandapi.api.argument.types;
|
|||
|
||||
import de.kentoj.kencommandapi.api.argument.ArgumentType;
|
||||
import de.kentoj.kencommandapi.api.suggestion.SuggestionProvider;
|
||||
import de.kentoj.kencommandapi.api.suggestion.NoSuggestionProvider;
|
||||
|
||||
public class IntegerArgumentType<T> implements ArgumentType<T, Integer> {
|
||||
|
||||
@Override
|
||||
public Integer parseInput(String string) {
|
||||
public Integer parseInputUnchecked(String string) {
|
||||
return Integer.parseInt(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuggestionProvider<T> defaultSuggestionProvider() {
|
||||
return new NoSuggestionProvider<>();
|
||||
public SuggestionProvider<T> getDefaultSuggestionProvider() {
|
||||
return SuggestionProvider.none();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package de.kentoj.kencommandapi.api.argument.types;
|
|||
|
||||
import de.kentoj.kencommandapi.api.argument.ArgumentType;
|
||||
import de.kentoj.kencommandapi.api.suggestion.SuggestionProvider;
|
||||
import de.kentoj.kencommandapi.api.suggestion.NoSuggestionProvider;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
|
|
@ -15,13 +14,13 @@ public class StringArgumentType<T> implements ArgumentType<T, String> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String parseInput(String string) {
|
||||
public String parseInputUnchecked(String string) {
|
||||
return string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuggestionProvider<T> defaultSuggestionProvider() {
|
||||
return new NoSuggestionProvider<>();
|
||||
public SuggestionProvider<T> getDefaultSuggestionProvider() {
|
||||
return SuggestionProvider.none();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,37 +1,37 @@
|
|||
package de.kentoj.kencommandapi.api.invocation;
|
||||
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgument;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CommandContext<T> {
|
||||
@Getter
|
||||
private final T sender;
|
||||
@Getter
|
||||
private final Map<String, ParsedArgument<T, ?>> parsedArguments;
|
||||
public interface CommandContext<T> {
|
||||
|
||||
public <V> ParsedArgument<T, V> getParsedArgument(String name) {
|
||||
try {
|
||||
//noinspection unchecked
|
||||
return (ParsedArgument<T, V>) parsedArguments.get(name);
|
||||
} catch (ClassCastException e) {
|
||||
throw new RuntimeException("requested argument with wrong type", e);
|
||||
}
|
||||
}
|
||||
T getSender();
|
||||
|
||||
<V> CommandArgument<T, V> getParsedArgument(String id);
|
||||
|
||||
/**
|
||||
* @return the value of the argument with the specified id
|
||||
* @param <V> the type of the value of the argument with the specified id
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> V getArg(String name) {
|
||||
return (V) getParsedArgument(name).getValue();
|
||||
default <V> V getArg(String id) {
|
||||
return (V) getParsedArgument(id).getValue();
|
||||
}
|
||||
|
||||
public <V> V getArg(CommandArgument<T, V> arg) {
|
||||
/**
|
||||
* @param arg the argument whose value to return
|
||||
* @return the value of the argument
|
||||
* @param <V> the type of the value of the argument
|
||||
*/
|
||||
default <V> V getArg(CommandArgumentSpec<T, V> arg) {
|
||||
return getArg(arg.getId());
|
||||
}
|
||||
|
||||
public <V> ParsedArgument<T, V> getParsedArgument(CommandArgument<T, V> arg) {
|
||||
default <V> CommandArgument<T, V> getParsedArgument(CommandArgumentSpec<T, V> arg) {
|
||||
return getParsedArgument(arg.getId());
|
||||
}
|
||||
|
||||
Map<String, CommandArgument<T, ?>> getParsedArguments();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
package de.kentoj.kencommandapi.api.invocation;
|
||||
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgument;
|
||||
|
||||
public interface ParsedArgument<T, V> {
|
||||
|
||||
V getValue();
|
||||
|
||||
CommandArgument<T, V> getArgument();
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
package de.kentoj.kencommandapi.api.literal;
|
||||
|
||||
import de.kentoj.kencommandapi.api.platform.MessageStyle;
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgument;
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
|
||||
import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
|
||||
import de.kentoj.kencommandapi.internal.LiteralImpl;
|
||||
import de.kentoj.kencommandapi.internal.RootLiteralImpl;
|
||||
import de.kentoj.kencommandapi.api.invocation.SyncCommandExecutor;
|
||||
import de.kentoj.kencommandapi.api.platform.MessageStyle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
|
@ -12,51 +11,26 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
public interface Literal<T> {
|
||||
static <T> Literal<T> literal(String... name) {
|
||||
return new LiteralImpl<>(name);
|
||||
}
|
||||
|
||||
static <T> RootLiteral<T> rootLiteral(MessageStyle messageStyle, String...name) {
|
||||
return new RootLiteralImpl<>(messageStyle, name);
|
||||
static <T> LiteralBuilder<T> builder(String... name) {
|
||||
return new LiteralBuilder<>(name);
|
||||
}
|
||||
|
||||
@NotNull String[] getNames();
|
||||
|
||||
void setDescription(@Nullable String description);
|
||||
|
||||
/**
|
||||
* @return what the literal does
|
||||
*/
|
||||
@Nullable String getDescription();
|
||||
|
||||
/*
|
||||
* arguments
|
||||
*/
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if there is already an argument with the same id
|
||||
* @throws IllegalStateException if a greedy argument was added to the literal previously
|
||||
*/
|
||||
<V> void addArgument(CommandArgument<T, V> argument);
|
||||
|
||||
List<CommandArgument<T, ?>> getArguments();
|
||||
|
||||
/*
|
||||
* literals
|
||||
*/
|
||||
|
||||
void setExecutor(@Nullable CommandExecutor<T> executor);
|
||||
List<CommandArgumentSpec<T, ?>> getArguments();
|
||||
|
||||
@Nullable CommandExecutor<T> getExecutor();
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if there is already a literal with the same name
|
||||
* @throws IllegalStateException if a greedy argument was added to the literal previously
|
||||
*/
|
||||
void addLiteral(@NotNull Literal<T> literal);
|
||||
|
||||
@Nullable Literal<T> getLiteral(@NotNull String name);
|
||||
|
||||
@NotNull Set<Literal<T>> getLiterals();
|
||||
@NotNull List<Literal<T>> getLiterals();
|
||||
|
||||
@Nullable String getPermission();
|
||||
|
||||
void setPermission(@Nullable String permission);
|
||||
MessageStyle getMessageStyle();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
package de.kentoj.kencommandapi.api.literal;
|
||||
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
|
||||
import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
|
||||
import de.kentoj.kencommandapi.api.invocation.SyncCommandExecutor;
|
||||
import de.kentoj.kencommandapi.api.platform.MessageStyle;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
public final class LiteralBuilder<T> {
|
||||
|
||||
private final String[] names;
|
||||
private @Nullable String description;
|
||||
private @Nullable CommandExecutor<T> executor;
|
||||
private @Nullable String permission;
|
||||
private @Nullable MessageStyle messageStyle;
|
||||
private final List<CommandArgumentSpec<T, ?>> arguments = new ArrayList<>();
|
||||
private final List<Literal<T>> literals = new ArrayList<>();
|
||||
|
||||
LiteralBuilder(String... names) {
|
||||
checkArgument(names.length > 0, "at least one name is required");
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param description what the literal does
|
||||
*/
|
||||
public LiteralBuilder<T> withDescription(@Nullable String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LiteralBuilder<T> withExecutor(@Nullable CommandExecutor<T> executor) {
|
||||
this.executor = executor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LiteralBuilder<T> withSyncExecutor(@Nullable SyncCommandExecutor<T> executor) {
|
||||
return withExecutor(executor);
|
||||
}
|
||||
|
||||
public LiteralBuilder<T> withPermission(@Nullable String permission) {
|
||||
this.permission = permission;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LiteralBuilder<T> withStyle(MessageStyle messageStyle) {
|
||||
this.messageStyle = messageStyle;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if there is already an argument with the same id
|
||||
* @throws IllegalStateException if a greedy argument was added to the literal previously
|
||||
*/
|
||||
public LiteralBuilder<T> withArgument(CommandArgumentSpec<T, ?> argument) {
|
||||
checkArgument(!hasGreedyArg(), "cannot add an argument after a greedy argument");
|
||||
if (arguments.stream().anyMatch(arg -> arg.getId().equals(argument.getId())))
|
||||
throw new IllegalArgumentException("cannot add multiple arguments with the same id");
|
||||
|
||||
this.arguments.add(argument);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if there is already a literal with the same name
|
||||
* @throws IllegalStateException if a greedy argument was added to the literal previously
|
||||
*/
|
||||
public LiteralBuilder<T> withLiteral(Literal<T> literal) {
|
||||
checkArgument(!hasGreedyArg(), "cannot add a literal after a greedy argument");
|
||||
for (String name : literal.getNames())
|
||||
for (var l : literals)
|
||||
if (l.getLiteral(name) != null)
|
||||
throw new IllegalArgumentException("literal with same name already exists");
|
||||
|
||||
this.literals.add(literal);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Literal<T> build() {
|
||||
return new LiteralImpl<>(
|
||||
names,
|
||||
literals,
|
||||
arguments,
|
||||
executor,
|
||||
permission,
|
||||
messageStyle == null ? MessageStyle.PLAIN : messageStyle
|
||||
);
|
||||
}
|
||||
|
||||
private boolean hasGreedyArg() {
|
||||
if (arguments.isEmpty()) return false;
|
||||
var arg = arguments.getLast();
|
||||
return arg != null && arg.getType().isGreedy();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package de.kentoj.kencommandapi.api.literal;
|
||||
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
|
||||
import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
|
||||
import de.kentoj.kencommandapi.api.platform.MessageStyle;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public class LiteralImpl<T> implements Literal<T> {
|
||||
private final String[] names;
|
||||
private final List<Literal<T>> literals;
|
||||
private final List<CommandArgumentSpec<T, ?>> arguments;
|
||||
private final CommandExecutor<T> executor;
|
||||
/**
|
||||
* what the literal does
|
||||
*/
|
||||
private String description;
|
||||
private final @Nullable String permission;
|
||||
private final MessageStyle messageStyle;
|
||||
|
||||
@Override
|
||||
public @Nullable Literal<T> getLiteral(@NotNull String name) {
|
||||
for (Literal<T> literal : literals) {
|
||||
for (var literalName : literal.getNames()) {
|
||||
if (literalName.equalsIgnoreCase(name))
|
||||
return literal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package de.kentoj.kencommandapi.api.literal;
|
||||
|
||||
import de.kentoj.kencommandapi.api.platform.MessageStyle;
|
||||
|
||||
public interface RootLiteral<T> extends Literal<T> {
|
||||
|
||||
MessageStyle getMessageStyle();
|
||||
|
||||
void setMessageStyle(MessageStyle messageStyle);
|
||||
}
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
package de.kentoj.kencommandapi.api.platform;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
public class PlainMessageStyle implements MessageStyle {
|
||||
@NoArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
class PlainMessageStyle implements MessageStyle {
|
||||
@Override
|
||||
public Component ok(Component msg) {
|
||||
return msg;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
package de.kentoj.kencommandapi.api.suggestion;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class NoSuggestionProvider<T> implements SuggestionProvider<T> {
|
||||
@NoArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
class NoSuggestionProvider<T> implements SuggestionProvider<T> {
|
||||
|
||||
@Override
|
||||
public List<String> suggest(T __) {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
package de.kentoj.kencommandapi.api.suggestion;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface SuggestionProvider<T> {
|
||||
|
||||
static <T> SuggestionProvider<T> none() {
|
||||
return new NoSuggestionProvider<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an unfiltered(no permission checks or filtering by input) list of strings that may be used for the argument/literal
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
package de.kentoj.kencommandapi.internal;
|
||||
|
||||
import de.kentoj.kencommandapi.api.argument.ArgumentType;
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgument;
|
||||
import de.kentoj.kencommandapi.api.suggestion.SuggestionProvider;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CommandArgumentImpl<T, V> implements CommandArgument<T, V> {
|
||||
|
||||
@Getter
|
||||
private final String id;
|
||||
@Getter
|
||||
private final ArgumentType<T, V> type;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private @Nullable Function<T, V> defaultValueProvider = null;
|
||||
@Setter
|
||||
private @Nullable SuggestionProvider<T> suggestionProvider;
|
||||
|
||||
@Override
|
||||
public @NotNull SuggestionProvider<T> getSuggestionProvider() {
|
||||
if (suggestionProvider == null)
|
||||
return getType().defaultSuggestionProvider();
|
||||
return this.suggestionProvider;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package de.kentoj.kencommandapi.internal;
|
||||
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgument;
|
||||
import de.kentoj.kencommandapi.api.invocation.CommandContext;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CommandContextImpl<T> implements CommandContext<T> {
|
||||
@Getter
|
||||
private final T sender;
|
||||
@Getter
|
||||
private final Map<String, CommandArgument<T, ?>> parsedArguments;
|
||||
|
||||
@Override
|
||||
public <V> CommandArgument<T, V> getParsedArgument(String id) {
|
||||
try {
|
||||
//noinspection unchecked
|
||||
return (CommandArgument<T, V>) parsedArguments.get(id);
|
||||
} catch (ClassCastException e) {
|
||||
throw new RuntimeException("requested argument with wrong type", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
package de.kentoj.kencommandapi.internal;
|
||||
|
||||
import de.kentoj.kencommandapi.api.literal.Literal;
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgument;
|
||||
import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class LiteralImpl<T> implements Literal<T> {
|
||||
|
||||
@Getter
|
||||
private final String[] names;
|
||||
@Getter
|
||||
private final Set<Literal<T>> literals = new HashSet<>();
|
||||
@Getter
|
||||
private final List<CommandArgument<T, ?>> arguments = new ArrayList<>();
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private @Nullable CommandExecutor<T> executor;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String description;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private @Nullable String permission = null;
|
||||
|
||||
public LiteralImpl(String[] names) {
|
||||
if (names.length == 0) throw new IllegalArgumentException("at least one name is required");
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLiteral(@NotNull Literal<T> literal) {
|
||||
if (isGreedy()) throw new IllegalStateException("can't add literal to a node with a greedy argument");
|
||||
for (String name : literal.getNames())
|
||||
if (getLiteral(name) != null)
|
||||
throw new IllegalArgumentException("literal with same name already exists");
|
||||
literals.add(literal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Literal<T> getLiteral(@NotNull String name) {
|
||||
for (var literal : literals)
|
||||
for (String literalName : literal.getNames())
|
||||
if (literalName.equalsIgnoreCase(name)) return literal;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> void addArgument(CommandArgument<T, V> argument) {
|
||||
if (isGreedy()) throw new IllegalStateException("can't add literal to a node with a greedy argument");
|
||||
if (arguments.stream().anyMatch(arg -> arg.getId().equals(argument.getId())))
|
||||
throw new IllegalArgumentException("argument with same identifier is already added");
|
||||
arguments.add(argument);
|
||||
}
|
||||
|
||||
private boolean isGreedy() {
|
||||
if (arguments.isEmpty()) return false;
|
||||
var arg = arguments.getLast();
|
||||
return arg != null && arg.getType().isGreedy();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
package de.kentoj.kencommandapi.internal;
|
||||
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgument;
|
||||
import de.kentoj.kencommandapi.api.invocation.ParsedArgument;
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
public class ParsedArgumentImpl<T, V> implements ParsedArgument<T, V> {
|
||||
V value;
|
||||
CommandArgument<T, V> argument;
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package de.kentoj.kencommandapi.internal;
|
||||
|
||||
import de.kentoj.kencommandapi.api.platform.MessageStyle;
|
||||
import de.kentoj.kencommandapi.api.literal.RootLiteral;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class RootLiteralImpl<T> extends LiteralImpl<T> implements RootLiteral<T> {
|
||||
@Setter
|
||||
@Getter
|
||||
private MessageStyle messageStyle;
|
||||
|
||||
public RootLiteralImpl(MessageStyle messageStyle, String[] names) {
|
||||
super(names);
|
||||
this.messageStyle = messageStyle;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,13 @@ package de.kentoj.kencommandapi.internal.parser;
|
|||
|
||||
import com.leakyabstractions.result.api.Result;
|
||||
import com.leakyabstractions.result.core.Results;
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgument;
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
|
||||
import de.kentoj.kencommandapi.api.invocation.CommandContext;
|
||||
import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
|
||||
import de.kentoj.kencommandapi.api.invocation.ParsedArgument;
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgument;
|
||||
import de.kentoj.kencommandapi.api.literal.Literal;
|
||||
import de.kentoj.kencommandapi.api.literal.RootLiteral;
|
||||
import de.kentoj.kencommandapi.internal.ParsedArgumentImpl;
|
||||
import de.kentoj.kencommandapi.api.argument.CommandArgumentImpl;
|
||||
import de.kentoj.kencommandapi.internal.CommandContextImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
|
|
@ -20,17 +21,17 @@ public class InvocationCommandParser<T> {
|
|||
private final CommandParseHelper<T> helper;
|
||||
|
||||
public Result<ExecutionData, String> parse(
|
||||
RootLiteral<T> rootLiteral,
|
||||
Literal<T> rootLiteral,
|
||||
T sender,
|
||||
Iterator<String> tokenIter
|
||||
) {
|
||||
Literal<T> currentLiteral = rootLiteral;
|
||||
Map<String, ParsedArgument<T, ?>> parsedArguments = new HashMap<>();
|
||||
var ctx = new CommandContextImpl<>(sender, new HashMap<>());
|
||||
|
||||
while (true) {
|
||||
{
|
||||
var result = processArguments(currentLiteral, sender, tokenIter)
|
||||
.ifSuccess(parsedArguments::putAll);
|
||||
var result = processArguments(currentLiteral, ctx, tokenIter)
|
||||
.ifSuccess(ctx.getParsedArguments()::putAll);
|
||||
if (result.hasFailure())
|
||||
return result.mapSuccess(__ -> null);
|
||||
}
|
||||
|
|
@ -49,35 +50,35 @@ public class InvocationCommandParser<T> {
|
|||
currentLiteral = nextLiteral;
|
||||
}
|
||||
|
||||
return Results.success(new ExecutionData(currentLiteral.getExecutor(), parsedArguments));
|
||||
return Results.success(new ExecutionData(currentLiteral.getExecutor(), ctx));
|
||||
}
|
||||
|
||||
private Result<Map<String, ParsedArgument<T, ?>>, String> processArguments(
|
||||
private Result<Map<String, CommandArgument<T, ?>>, String> processArguments(
|
||||
Literal<T> literal,
|
||||
T sender,
|
||||
CommandContext<T> ctx,
|
||||
Iterator<String> tokenIter
|
||||
) {
|
||||
Map<String, ParsedArgument<T, ?>> parsedArguments = new HashMap<>();
|
||||
Map<String, CommandArgument<T, ?>> parsedArguments = new HashMap<>();
|
||||
|
||||
for (var _argument : literal.getArguments()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
var argument = ((CommandArgument<T, Object>) _argument);
|
||||
var argument = ((CommandArgumentSpec<T, Object>) _argument);
|
||||
|
||||
Object value;
|
||||
if (!tokenIter.hasNext()) {
|
||||
if (argument.getDefaultValueProvider() == null)
|
||||
return Results.failure("Argument expected: " + argument.getId());
|
||||
value = argument.getDefaultValueProvider().apply(sender);
|
||||
value = argument.getDefaultValueProvider().apply(ctx);
|
||||
} else {
|
||||
var input = helper.parseInput(tokenIter, argument.getType().isGreedy());
|
||||
try {
|
||||
value = argument.getType().parseInput(input);
|
||||
value = argument.parseInput(input);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return Results.failure("Illegal argument '" + input + "' for " + argument.getId() + ": " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
parsedArguments.put(argument.getId(), new ParsedArgumentImpl<>(value, argument));
|
||||
parsedArguments.put(argument.getId(), new CommandArgumentImpl<>(value, argument));
|
||||
}
|
||||
|
||||
return Results.success(parsedArguments);
|
||||
|
|
@ -86,6 +87,6 @@ public class InvocationCommandParser<T> {
|
|||
@Value
|
||||
public class ExecutionData {
|
||||
CommandExecutor<T> executor;
|
||||
Map<String, ParsedArgument<T, ?>> arguments;
|
||||
CommandContext<T> context;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package de.kentoj.kencommandapi.internal.parser;
|
||||
|
||||
import de.kentoj.kencommandapi.api.literal.Literal;
|
||||
import de.kentoj.kencommandapi.api.literal.RootLiteral;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
|
@ -16,7 +15,7 @@ public class SuggestionCommandParser<T> {
|
|||
private final CommandParseHelper<T> helper;
|
||||
|
||||
public List<String> suggest(
|
||||
RootLiteral<T> rootLiteral,
|
||||
Literal<T> rootLiteral,
|
||||
T sender,
|
||||
Iterator<String> tokenIter,
|
||||
boolean suggestNext
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package de.kentoj.kencommandapi.api.parser;
|
|||
import de.kentoj.kencommandapi.api.argument.CommandArgument;
|
||||
import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
|
||||
import de.kentoj.kencommandapi.api.literal.Literal;
|
||||
import de.kentoj.kencommandapi.api.literal.RootLiteral;
|
||||
import de.kentoj.kencommandapi.api.literal.Literal;
|
||||
import de.kentoj.kencommandapi.api.platform.MessageStyle;
|
||||
import de.kentoj.kencommandapi.internal.parser.SuggestionCommandParser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -18,7 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
public class SuggestionCommandParserTest {
|
||||
|
||||
private final SuggestionCommandParser<Object> suggestionParser;
|
||||
private final RootLiteral<Object> rootLiteral;
|
||||
private final Literal<Object> rootLiteral;
|
||||
|
||||
public SuggestionCommandParserTest() {
|
||||
rootLiteral = Literal.rootLiteral(MessageStyle.PLAIN, "someRootNode");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue