This commit is contained in:
kento2 2026-04-15 10:58:36 +02:00
parent fc431bf8df
commit 81a36c0440
8 changed files with 111 additions and 23 deletions

View file

@ -0,0 +1,27 @@
package de.kencommand;
import de.kencommand.api.KenCommandApi;
import de.kencommand.api.structure.argument.types.IntegerArgumentType;
import de.kencommand.impl.KenCommandApiImpl;
import java.io.PrintStream;
public class Main {
public static void main(String[] args) {
KenCommandApi<PrintStream> api = new KenCommandApiImpl<>();
var root = api.createNode("coins");
var addNode = api.createNode("add", "deposit");
addNode.setExecutor(ctx -> {
int amount = ctx.getArg("amount");
ctx.getSender().println("adding " + amount + "$ to your balance");
});
addNode.addArgument(api.createArgument("amount", IntegerArgumentType.create()));
root.addLiteral(addNode);
api.invoke(root, System.out, new String[] { "add", "100" });
}
}

View file

@ -1,17 +1,14 @@
package de.kencommand.api;
import de.kencommand.api.processing.CommandExecutor;
import de.kencommand.api.processing.ParsedArgument;
import de.kencommand.api.structure.argument.ArgumentType;
import de.kencommand.api.structure.argument.CommandArgument;
import de.kencommand.api.structure.node.CommandNode;
import java.util.Iterator;
import java.util.Map;
public interface KenCommandApi<T> {
CommandNode<T> createNode(String... name);
<V> CommandArgument<T, V> createArgument(String id, ArgumentType<V> type);
void invoke(CommandNode<T> node, T sender, String[] args);
CommandExecutor<T> processLiterals(CommandNode<T> node, Iterator<String> argsIterator);
Map<String, ParsedArgument<T, ?>> parseArguments(CommandNode<T> node, Iterator<String> argsIterator);
}

View file

@ -1,6 +1,5 @@
package de.kencommand.api.structure.argument;
import de.kencommand.api.processing.CommandContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View file

@ -0,0 +1,25 @@
package de.kencommand.api.structure.argument.suggestion;
import de.kencommand.api.processing.CommandContext;
import de.kencommand.api.structure.argument.SuggestionProvider;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.Set;
@NoArgsConstructor(access = AccessLevel.NONE)
public class NoSuggestionProvider implements SuggestionProvider<Object> {
@Getter(value = AccessLevel.PRIVATE, lazy = true)
private static final SuggestionProvider<Object> instance = new NoSuggestionProvider();
public static SuggestionProvider<Object> create() {
return getInstance();
}
@Override
public Set<String> suggest(CommandContext<Object> context) {
return Set.of();
}
}

View file

@ -0,0 +1,25 @@
package de.kencommand.api.structure.argument.types;
import de.kencommand.api.structure.argument.ArgumentType;
import de.kencommand.api.structure.argument.SuggestionProvider;
import de.kencommand.api.structure.argument.suggestion.NoSuggestionProvider;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class IntegerArgumentType implements ArgumentType<Integer> {
@Override
public Integer parseInput(String string) {
return Integer.parseInt(string);
}
@Override
public SuggestionProvider<?> defaultSuggestionProvider() {
return NoSuggestionProvider.create();
}
public static IntegerArgumentType create() {
return new IntegerArgumentType();
}
}

View file

@ -3,10 +3,13 @@ package de.kencommand.impl;
import de.kencommand.api.KenCommandApi;
import de.kencommand.api.processing.CommandExecutor;
import de.kencommand.api.processing.ParsedArgument;
import de.kencommand.api.structure.argument.ArgumentType;
import de.kencommand.api.structure.argument.CommandArgument;
import de.kencommand.api.structure.node.CommandNode;
import de.kencommand.impl.processing.CommandContextImpl;
import de.kencommand.impl.processing.ParsedArgumentImpl;
import de.kencommand.impl.structure.argument.CommandArgumentImpl;
import de.kencommand.impl.structure.node.CommandNodeImpl;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
@ -17,6 +20,16 @@ import java.util.Map;
@RequiredArgsConstructor
public class KenCommandApiImpl<T> implements KenCommandApi<T> {
@Override
public CommandNode<T> createNode(String... name) {
return new CommandNodeImpl<>(name);
}
@Override
public <V> CommandArgument<T, V> createArgument(String id, ArgumentType<V> type) {
return new CommandArgumentImpl<>(id, type);
}
@Override
public void invoke(CommandNode<T> node, T sender, String[] args) {
var iter = Arrays.stream(args).iterator();
@ -26,17 +39,18 @@ public class KenCommandApiImpl<T> implements KenCommandApi<T> {
executor.execute(new CommandContextImpl<>(sender, parsedArguments));
}
@Override
public CommandExecutor<T> processLiterals(CommandNode<T> commandNode, Iterator<String> iter) {
private CommandExecutor<T> processLiterals(CommandNode<T> commandNode, Iterator<String> iter) {
if (!iter.hasNext()) {
// literals/arguments are optional if the node itself is executable
if (commandNode.getExecutor() == null) throw new RuntimeException("no literal given but required");
// TODO parse arguments for executor ig, or rather do that in a separate method
return commandNode.getExecutor();
}
if (commandNode.getLiterals().isEmpty()) {
return commandNode.getExecutor();
}
final var arg = iter.next();
// TODO rethink
final var literal = commandNode.getLiteral(arg);
if (literal == null) {
throw new RuntimeException("Invalid literal: " + arg);
@ -44,10 +58,9 @@ public class KenCommandApiImpl<T> implements KenCommandApi<T> {
return processLiterals(literal, iter);
}
@Override
public Map<String, ParsedArgument<T, ?>> parseArguments(CommandNode<T> commandNode, Iterator<String> iter) {
private Map<String, ParsedArgument<T, ?>> parseArguments(CommandNode<T> commandNode, Iterator<String> iter) {
Map<String, ParsedArgument<T, ?>> parsedArguments = new HashMap<>();
for (CommandArgument<T, ?> argument : commandNode.getArguments()) {
for (var argument : commandNode.getArguments()) {
@SuppressWarnings("unchecked")
var arg = ((CommandArgument<T, Object>) argument);

View file

@ -1,6 +1,5 @@
package de.kencommand.impl.structure.argument;
import de.kencommand.api.processing.CommandContext;
import de.kencommand.api.structure.argument.ArgumentType;
import de.kencommand.api.structure.argument.CommandArgument;
import de.kencommand.api.structure.argument.SuggestionProvider;
@ -10,7 +9,7 @@ import lombok.Setter;
import org.jetbrains.annotations.Nullable;
@RequiredArgsConstructor
public class CommandArgumentImpl<T, S extends CommandContext<T>, V> implements CommandArgument<T, S, V> {
public class CommandArgumentImpl<T, V> implements CommandArgument<T, V> {
@Getter
private final String id;
@ -23,5 +22,5 @@ public class CommandArgumentImpl<T, S extends CommandContext<T>, V> implements C
@Getter
@Setter
private @Nullable SuggestionProvider<T, S> suggestionProvider;
private @Nullable SuggestionProvider<T> suggestionProvider;
}

View file

@ -1,11 +1,10 @@
package de.kencommand.impl.structure.node;
import de.kencommand.api.processing.CommandContext;
import de.kencommand.api.processing.CommandExecutor;
import de.kencommand.api.structure.argument.CommandArgument;
import de.kencommand.api.structure.node.CommandNode;
import de.kencommand.api.structure.node.LiteralNode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -13,12 +12,16 @@ import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
@RequiredArgsConstructor
public class CommandNodeImpl<T> implements CommandNode<T> {
@Getter
private final String[] names;
public CommandNodeImpl(String[] names) {
if (names.length == 0) throw new IllegalArgumentException("at least one name is required");
this.names = names;
}
@Getter
private final Set<CommandNode<T>> literals = new HashSet<>();
@Getter