Skip to content

Commit

Permalink
Added Flag and Option annotations for parsing options via arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
Despical committed Sep 20, 2024
1 parent c84823c commit fe7007d
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 24 deletions.
32 changes: 30 additions & 2 deletions src/main/java/me/despical/commandframework/CommandArguments.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@

import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

/**
* A utility class to use command arguments without external
Expand All @@ -41,10 +44,14 @@
*/
public final class CommandArguments {

final me.despical.commandframework.annotations.Command command;
private Set<String> parsedFlags;
private Map<String, List<String>> parsedArguments;

private final me.despical.commandframework.annotations.Command command;
private final CommandSender commandSender;
private final Command bukkitCommand;
private final String label, arguments[];
private final String label;
private final String [] arguments;

CommandArguments(CommandSender commandSender,
Command bukkitCommand,
Expand Down Expand Up @@ -447,4 +454,25 @@ public boolean isFloatingDecimal(String string) {
public boolean checkCooldown() {
return CommandFramework.instance.getCooldownManager().hasCooldown(this);
}

void setParsedArguments(Map<String, List<String>> parsedArguments) {
this.parsedArguments = parsedArguments;
}

@Nullable
public List<String> getOption(final @NotNull String option) {
return this.parsedArguments.get(option);
}

public Optional<List<String>> findOption(final @NotNull String option) {
return Optional.ofNullable(this.getOption(option));
}

void setParsedFlags(Set<String> parsedFlags) {
this.parsedFlags = parsedFlags;
}

public boolean isFlagPresent(final @NotNull String flag) {
return this.parsedFlags != null && this.parsedFlags.contains(flag);
}
}
11 changes: 1 addition & 10 deletions src/main/java/me/despical/commandframework/CommandFramework.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,20 @@ public class CommandFramework extends CommandHandler {

protected final Plugin plugin;
private final OptionManager optionManager;
private final ParameterHandler parameterHandler;
private final CommandRegistry registry;

public CommandFramework(@NotNull Plugin plugin) {
this.checkRelocation();
this.checkIsAlreadyInitialized();

this.plugin = plugin;
this.optionManager = new OptionManager();
this.registry = new CommandRegistry();
this.parameterHandler = new ParameterHandler();
this.optionManager = new OptionManager();
this.initializeLogger();
super.setRegistry(this);
}

private void checkRelocation() {
if (this.isOptionEnabled(Option.DEBUG)) return;

String suppressRelocation = System.getProperty("commandframework.suppressrelocation");

if ("true".equals(suppressRelocation)) return;
Expand Down Expand Up @@ -205,11 +201,6 @@ final CommandRegistry getRegistry() {
return registry;
}

@ApiStatus.Internal
final ParameterHandler getParameterHandler() {
return parameterHandler;
}

@ApiStatus.Internal
final boolean checkConfirmation(CommandSender sender, final Command command, final Method method) {
if (!isOptionEnabled(Option.CONFIRMATIONS)) return false;
Expand Down
23 changes: 16 additions & 7 deletions src/main/java/me/despical/commandframework/CommandHandler.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package me.despical.commandframework;

import me.despical.commandframework.annotations.Option;
import me.despical.commandframework.annotations.Command;
import me.despical.commandframework.annotations.Completer;
import me.despical.commandframework.exceptions.CooldownException;
import me.despical.commandframework.options.Option;
import me.despical.commandframework.parser.OptionParser;
import me.despical.commandframework.utils.Utils;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
Expand Down Expand Up @@ -31,14 +32,14 @@
*/
@ApiStatus.Internal
@ApiStatus.NonExtendable
public abstract class CommandHandler implements CommandExecutor, TabCompleter {
abstract class CommandHandler implements CommandExecutor, TabCompleter {

private CommandRegistry registry;
private CommandFramework commandFramework;
protected ParameterHandler parameterHandler;

void setRegistry(CommandFramework commandFramework) {
this.commandFramework = commandFramework;
this.registry = commandFramework.getRegistry();
this.parameterHandler = new ParameterHandler();
}

@Override
Expand Down Expand Up @@ -82,20 +83,28 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull org.bukkit.comm
}

final Method method = entry.getValue().getKey();
final CommandFramework commandFramework = CommandFramework.getInstance();

if (commandFramework.checkConfirmation(sender, command, method)) {
return true;
}

if (!this.commandFramework.isOptionEnabled(Option.CUSTOM_COOLDOWN_CHECKER) && commandFramework.getCooldownManager().hasCooldown(arguments, command, method)) {
if (commandFramework.getCooldownManager().hasCooldown(arguments, command, method)) {
return true;
}

if (method.getAnnotationsByType(Option.class).length > 0) {
OptionParser optionParser = new OptionParser(newArgs, method);

arguments.setParsedArguments(optionParser.parseOptions());
arguments.setParsedFlags(optionParser.parseFlags());
}

final Runnable invocation = () -> {
try {
final Object instance = entry.getValue().getValue();

method.invoke(instance, commandFramework.getParameterHandler().getParameterArray(method, arguments));
method.invoke(instance, parameterHandler.getParameterArray(method, arguments));
} catch (Exception exception) {
if (exception.getCause() instanceof CooldownException) {
return;
Expand Down Expand Up @@ -133,7 +142,7 @@ public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull org.bu
final Object instance = entry.getValue().getValue();
final String[] splitName = entry.getKey().name().split("\\.");
final String[] newArgs = Arrays.copyOfRange(args, splitName.length - 1, args.length);
final Object completer = method.invoke(instance, commandFramework.getParameterHandler().getParameterArray(method, new CommandArguments(sender, cmd, null, label, newArgs)));
final Object completer = method.invoke(instance, parameterHandler.getParameterArray(method, new CommandArguments(sender, cmd, null, label, newArgs)));

return (List<String>) completer;
} catch (Exception exception) {
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/me/despical/commandframework/annotations/Flag.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package me.despical.commandframework.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* @author Despical
* <p>
* Created at 20.09.2024
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Flag.FlagContainer.class)
public @interface Flag {

String[] value();

String prefix() default "--";

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface FlagContainer {

Flag[] value();
}
}
35 changes: 35 additions & 0 deletions src/main/java/me/despical/commandframework/annotations/Option.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package me.despical.commandframework.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* @author Despical
* <p>
* Created at 20.09.2024
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Option.OptionContainer.class)
public @interface Option {

String name();

String prefix() default "--";

String valueSeparator() default ",";

String keySeparator() default "=";

boolean allowSeparating() default true;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface OptionContainer {

Option[] value();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public boolean hasCooldown(CommandArguments arguments) {
}

public boolean hasCooldown(final CommandArguments arguments, final Command command, final Method method) {
if (commandFramework.isOptionEnabled(Option.CUSTOM_COOLDOWN_CHECKER)) return false;
if (method == null) return false;
if (!method.isAnnotationPresent(Cooldown.class)) return false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
* Created at 23.01.2024
*/
@ApiStatus.Internal
public final class CommandException extends RuntimeException {
public class CommandException extends RuntimeException {

public CommandException() {
super();
}

public CommandException(final String message) {
super(message);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package me.despical.commandframework.exceptions;

import org.jetbrains.annotations.ApiStatus;

/**
* @author Despical
* <p>
* Created at 18.07.2024
*/
@ApiStatus.Internal
public final class CooldownException extends RuntimeException {
public class CooldownException extends CommandException {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* @author Despical
* <p>
* Created at 20.09.2024
*/
@ApiStatus.Internal
package me.despical.commandframework.exceptions;

import org.jetbrains.annotations.ApiStatus;
102 changes: 102 additions & 0 deletions src/main/java/me/despical/commandframework/parser/OptionParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package me.despical.commandframework.parser;

import me.despical.commandframework.annotations.Flag;
import me.despical.commandframework.annotations.Option;

import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Pattern;

/**
* @author Despical
* <p>
* Created at 20.09.2024
*/
public class OptionParser {

private final Flag[] flags;
private final Option[] options;
private final Set<String> arguments;
private final Set<String> parsedFlags;
private final Map<String, List<String>> parsedOptions;

public OptionParser(String[] arguments, Method method) {
this.flags = method.getAnnotationsByType(Flag.class);
this.options = method.getAnnotationsByType(Option.class);
this.arguments = new HashSet<>(Arrays.asList(arguments));
this.parsedFlags = new HashSet<>();
this.parsedOptions = new HashMap<>();
}

public Map<String, List<String>> parseOptions() {
for (Option option : options) {
this.parseOption(option);
}

return this.parsedOptions;
}

public Set<String> parseFlags() {
for (Flag flag : flags) {
this.parseFlag(flag);
}

return this.parsedFlags;
}

private void parseOption(Option option) {
String prefix = option.prefix();
String keySeparator = Pattern.quote(option.keySeparator());
String valueSeparator = Pattern.quote(option.valueSeparator());
Iterator<String> iterator = arguments.iterator();

while (iterator.hasNext()) {
String argument = iterator.next();

if (!argument.startsWith(prefix)) {
continue;
}

if (option.allowSeparating() && !argument.contains(keySeparator)) {
continue;
}

String[] options = argument.substring(prefix.length()).split(keySeparator);

if (!option.allowSeparating()) {
String value = options.length <= 1 ? "" : options[1];
this.parsedOptions.put(option.name(), Collections.singletonList(value));

iterator.remove();
continue;
}

String[] values = options[1].split(valueSeparator);
this.parsedOptions.put(option.name(), Arrays.asList(values));

iterator.remove();
}
}

private void parseFlag(Flag flag) {
String prefix = flag.prefix();

outer:
for (String argument : this.arguments) {
if (!argument.startsWith(prefix)) {
continue;
}

String foundFlag = argument.substring(prefix.length());

for (String flagName : flag.value()) {
if (!flagName.equals(foundFlag)) {
continue;
}

this.parsedFlags.add(flagName);
continue outer;
}
}
}
}

0 comments on commit fe7007d

Please sign in to comment.