Fix tabcompletion: use custom suggestion provider
It looks like we can't have custom argument types Checking for permission for each offered option Suggesting the argument's name as well #82 TODO: Handle annotations Remove test command
This commit is contained in:
parent
95a8e92b51
commit
f5406a8c0e
9 changed files with 119 additions and 76 deletions
|
@ -26,7 +26,7 @@ public class ChromaCommand extends ICommand2MC {
|
||||||
sender.sendMessage(ButtonPlugin.getCommand2MC().getCommandsText());
|
sender.sendMessage(ButtonPlugin.getCommand2MC().getCommandsText());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command2.Subcommand
|
@Command2.Subcommand //TODO: Remove
|
||||||
public void test(CommandSender sender, char test) {
|
public void test(CommandSender sender, char test) {
|
||||||
sender.sendMessage(test + "");
|
sender.sendMessage(test + "");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,17 @@ import buttondevteam.lib.architecture.Component;
|
||||||
import buttondevteam.lib.chat.Command2;
|
import buttondevteam.lib.chat.Command2;
|
||||||
import buttondevteam.lib.chat.Command2.Subcommand;
|
import buttondevteam.lib.chat.Command2.Subcommand;
|
||||||
import buttondevteam.lib.chat.CommandClass;
|
import buttondevteam.lib.chat.CommandClass;
|
||||||
|
import buttondevteam.lib.chat.CustomTabCompleteMethod;
|
||||||
import buttondevteam.lib.chat.ICommand2MC;
|
import buttondevteam.lib.chat.ICommand2MC;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@CommandClass(modOnly = true, helpText = {
|
@CommandClass(modOnly = true, helpText = {
|
||||||
"Component command",
|
"Component command",
|
||||||
|
@ -20,7 +24,8 @@ import java.util.Optional;
|
||||||
})
|
})
|
||||||
public class ComponentCommand extends ICommand2MC {
|
public class ComponentCommand extends ICommand2MC {
|
||||||
public ComponentCommand() {
|
public ComponentCommand() {
|
||||||
getManager().addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg), "Plugin not found!");
|
getManager().addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg), "Plugin not found!",
|
||||||
|
() -> Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(Plugin::getName)::iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subcommand(helpText = {
|
@Subcommand(helpText = {
|
||||||
|
@ -57,6 +62,11 @@ public class ComponentCommand extends ICommand2MC {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CustomTabCompleteMethod(param = "component", subcommand = {"enable", "disable"})
|
||||||
|
public Iterable<String> componentTabcomplete(Plugin plugin) {
|
||||||
|
return getPluginComponents(plugin).map(c -> c.getClass().getSimpleName())::iterator;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean enable_disable(CommandSender sender, Plugin plugin, String component, boolean enable, boolean permanent) {
|
private boolean enable_disable(CommandSender sender, Plugin plugin, String component, boolean enable, boolean permanent) {
|
||||||
try {
|
try {
|
||||||
val oc = getComponentOrError(plugin, component, sender);
|
val oc = getComponentOrError(plugin, component, sender);
|
||||||
|
@ -72,10 +82,13 @@ public class ComponentCommand extends ICommand2MC {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Stream<Component<? extends JavaPlugin>> getPluginComponents(Plugin plugin) {
|
||||||
|
return Component.getComponents().values().stream()
|
||||||
|
.filter(c -> plugin.getName().equals(c.getPlugin().getName()));
|
||||||
|
}
|
||||||
|
|
||||||
private Optional<Component<?>> getComponentOrError(Plugin plugin, String arg, CommandSender sender) {
|
private Optional<Component<?>> getComponentOrError(Plugin plugin, String arg, CommandSender sender) {
|
||||||
val oc = Component.getComponents().values().stream()
|
val oc = getPluginComponents(plugin).filter(c -> c.getClass().getSimpleName().equalsIgnoreCase(arg)).findAny();
|
||||||
.filter(c -> plugin.getName().equals(c.getPlugin().getName()))
|
|
||||||
.filter(c -> c.getClass().getSimpleName().equalsIgnoreCase(arg)).findAny();
|
|
||||||
if (!oc.isPresent())
|
if (!oc.isPresent())
|
||||||
sender.sendMessage("§cComponent not found!"); //^ Much simpler to solve in the new command system
|
sender.sendMessage("§cComponent not found!"); //^ Much simpler to solve in the new command system
|
||||||
return oc;
|
return oc;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import buttondevteam.lib.chat.ICommand2MC;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.HumanEntity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -19,7 +20,8 @@ public class MemberCommand extends ICommand2MC {
|
||||||
private final MemberComponent component;
|
private final MemberComponent component;
|
||||||
|
|
||||||
public MemberCommand(MemberComponent component) {
|
public MemberCommand(MemberComponent component) {
|
||||||
getManager().addParamConverter(OfflinePlayer.class, Bukkit::getOfflinePlayer, "Player not found!");
|
getManager().addParamConverter(OfflinePlayer.class, Bukkit::getOfflinePlayer, "Player not found!",
|
||||||
|
() -> Bukkit.getOnlinePlayers().stream().map(HumanEntity::getName)::iterator);
|
||||||
this.component = component;
|
this.component = component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package buttondevteam.core.component.towny;
|
||||||
|
|
||||||
import buttondevteam.lib.chat.Command2;
|
import buttondevteam.lib.chat.Command2;
|
||||||
import buttondevteam.lib.chat.CommandClass;
|
import buttondevteam.lib.chat.CommandClass;
|
||||||
|
import buttondevteam.lib.chat.CustomTabComplete;
|
||||||
import buttondevteam.lib.chat.ICommand2MC;
|
import buttondevteam.lib.chat.ICommand2MC;
|
||||||
import com.palmergames.bukkit.towny.TownySettings;
|
import com.palmergames.bukkit.towny.TownySettings;
|
||||||
import com.palmergames.bukkit.towny.TownyUniverse;
|
import com.palmergames.bukkit.towny.TownyUniverse;
|
||||||
|
@ -20,7 +21,7 @@ import java.util.stream.Stream;
|
||||||
})
|
})
|
||||||
public class RemoveResidentsCommand extends ICommand2MC {
|
public class RemoveResidentsCommand extends ICommand2MC {
|
||||||
@Command2.Subcommand
|
@Command2.Subcommand
|
||||||
public void def(CommandSender sender, @Command2.OptionalArg String remove) {
|
public void def(CommandSender sender, @Command2.OptionalArg @CustomTabComplete("remove") String remove) {
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(getPlugin(), () -> {
|
Bukkit.getScheduler().runTaskAsynchronously(getPlugin(), () -> {
|
||||||
sender.sendMessage("Starting...");
|
sender.sendMessage("Starting...");
|
||||||
var ds = TownyUniverse.getInstance().getDataSource();
|
var ds = TownyUniverse.getInstance().getDataSource();
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method name is the subcommand, use underlines (_) to add further subcommands.
|
* The method name is the subcommand, use underlines (_) to add further subcommands.
|
||||||
|
@ -110,10 +111,11 @@ public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Send
|
||||||
protected static class ParamConverter<T> {
|
protected static class ParamConverter<T> {
|
||||||
public final Function<String, T> converter;
|
public final Function<String, T> converter;
|
||||||
public final String errormsg;
|
public final String errormsg;
|
||||||
|
public final Supplier<Iterable<String>> allSupplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HashMap<String, SubcommandData<TC>> subcommands = new HashMap<>();
|
protected final HashMap<String, SubcommandData<TC>> subcommands = new HashMap<>();
|
||||||
private HashMap<Class<?>, ParamConverter<?>> paramConverters = new HashMap<>();
|
protected final HashMap<Class<?>, ParamConverter<?>> paramConverters = new HashMap<>();
|
||||||
|
|
||||||
private ArrayList<String> commandHelp = new ArrayList<>(); //Mainly needed by Discord
|
private ArrayList<String> commandHelp = new ArrayList<>(); //Mainly needed by Discord
|
||||||
|
|
||||||
|
@ -123,12 +125,14 @@ public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Send
|
||||||
* Adds a param converter that obtains a specific object from a string parameter.
|
* Adds a param converter that obtains a specific object from a string parameter.
|
||||||
* The converter may return null.
|
* The converter may return null.
|
||||||
*
|
*
|
||||||
|
* @param <T> The type of the result
|
||||||
* @param cl The class of the result object
|
* @param cl The class of the result object
|
||||||
* @param converter The converter to use
|
* @param converter The converter to use
|
||||||
* @param <T> The type of the result
|
* @param allSupplier The supplier of all possible values (ideally)
|
||||||
*/
|
*/
|
||||||
public <T> void addParamConverter(Class<T> cl, Function<String, T> converter, String errormsg) {
|
public <T> void addParamConverter(Class<T> cl, Function<String, T> converter, String errormsg,
|
||||||
paramConverters.put(cl, new ParamConverter<>(converter, errormsg));
|
Supplier<Iterable<String>> allSupplier) {
|
||||||
|
paramConverters.put(cl, new ParamConverter<>(converter, errormsg, allSupplier));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean handleCommand(TP sender, String commandline) {
|
public boolean handleCommand(TP sender, String commandline) {
|
||||||
|
|
|
@ -4,11 +4,12 @@ import buttondevteam.core.MainPlugin;
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
import buttondevteam.lib.TBMCCoreAPI;
|
||||||
import buttondevteam.lib.architecture.ButtonPlugin;
|
import buttondevteam.lib.architecture.ButtonPlugin;
|
||||||
import buttondevteam.lib.architecture.Component;
|
import buttondevteam.lib.architecture.Component;
|
||||||
import buttondevteam.lib.chat.commandargs.BetterStringArgumentType;
|
|
||||||
import com.mojang.brigadier.arguments.*;
|
import com.mojang.brigadier.arguments.*;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||||
import com.mojang.brigadier.tree.CommandNode;
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
|
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import me.lucko.commodore.Commodore;
|
import me.lucko.commodore.Commodore;
|
||||||
import me.lucko.commodore.CommodoreProvider;
|
import me.lucko.commodore.CommodoreProvider;
|
||||||
|
@ -20,7 +21,9 @@ import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
import org.bukkit.command.SimpleCommandMap;
|
import org.bukkit.command.SimpleCommandMap;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.server.TabCompleteEvent;
|
||||||
import org.bukkit.permissions.Permission;
|
import org.bukkit.permissions.Permission;
|
||||||
import org.bukkit.permissions.PermissionDefault;
|
import org.bukkit.permissions.PermissionDefault;
|
||||||
|
|
||||||
|
@ -31,6 +34,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implements Listener {
|
public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implements Listener {
|
||||||
/**
|
/**
|
||||||
|
@ -139,8 +143,8 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
|
||||||
* {@see super#addParamConverter}
|
* {@see super#addParamConverter}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> void addParamConverter(Class<T> cl, Function<String, T> converter, String errormsg) {
|
public <T> void addParamConverter(Class<T> cl, Function<String, T> converter, String errormsg, Supplier<Iterable<String>> allSupplier) {
|
||||||
super.addParamConverter(cl, converter, "§c" + errormsg);
|
super.addParamConverter(cl, converter, "§c" + errormsg, allSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterCommands(ButtonPlugin plugin) {
|
public void unregisterCommands(ButtonPlugin plugin) {
|
||||||
|
@ -158,6 +162,13 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
|
||||||
.map(comp -> component.getClass().getSimpleName().equals(comp.getClass().getSimpleName())).orElse(false));
|
.map(comp -> component.getClass().getSimpleName().equals(comp.getClass().getSimpleName())).orElse(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onTabComplete(TabCompleteEvent event) {
|
||||||
|
//System.out.println("Tabcomplete: " + event.getBuffer());
|
||||||
|
//System.out.println("First completion: " + event.getCompletions().stream().findFirst().orElse("no completions"));
|
||||||
|
event.getCompletions().clear();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean shouldRegisterOfficially = true;
|
private boolean shouldRegisterOfficially = true;
|
||||||
|
|
||||||
private void registerOfficially(ICommand2MC command, List<SubcommandData<ICommand2MC>> subcmds) {
|
private void registerOfficially(ICommand2MC command, List<SubcommandData<ICommand2MC>> subcmds) {
|
||||||
|
@ -202,6 +213,19 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
|
||||||
private static class TabcompleteHelper {
|
private static class TabcompleteHelper {
|
||||||
private static Commodore commodore;
|
private static Commodore commodore;
|
||||||
|
|
||||||
|
private static LiteralCommandNode<Object> appendSubcommand(String path, CommandNode<Object> parent,
|
||||||
|
SubcommandData<ICommand2MC> subcommand) {
|
||||||
|
var scmdBuilder = LiteralArgumentBuilder.literal(path);
|
||||||
|
if (subcommand != null)
|
||||||
|
scmdBuilder.requires(o -> {
|
||||||
|
var sender = commodore.getBukkitSender(o);
|
||||||
|
return ButtonPlugin.getCommand2MC().hasPermission(sender, subcommand.command, subcommand.method);
|
||||||
|
});
|
||||||
|
var scmd = scmdBuilder.build();
|
||||||
|
parent.addChild(scmd);
|
||||||
|
return scmd;
|
||||||
|
}
|
||||||
|
|
||||||
private static void registerTabcomplete(ICommand2MC command2MC, List<SubcommandData<ICommand2MC>> subcmds, Command bukkitCommand) {
|
private static void registerTabcomplete(ICommand2MC command2MC, List<SubcommandData<ICommand2MC>> subcmds, Command bukkitCommand) {
|
||||||
if (commodore == null)
|
if (commodore == null)
|
||||||
commodore = CommodoreProvider.getCommodore(MainPlugin.Instance); //Register all to the Core, it's easier
|
commodore = CommodoreProvider.getCommodore(MainPlugin.Instance); //Register all to the Core, it's easier
|
||||||
|
@ -209,18 +233,15 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
|
||||||
var maincmd = LiteralArgumentBuilder.literal(path[0]).build();
|
var maincmd = LiteralArgumentBuilder.literal(path[0]).build();
|
||||||
var cmd = maincmd;
|
var cmd = maincmd;
|
||||||
for (int i = 1; i < path.length; i++) {
|
for (int i = 1; i < path.length; i++) {
|
||||||
var subcmd = LiteralArgumentBuilder.literal(path[i]).build();
|
var scmd = subcmds.stream().filter(sd -> sd.method.getName().equals("def")).findAny().orElse(null);
|
||||||
cmd.addChild(subcmd);
|
cmd = appendSubcommand(path[i], cmd, scmd); //Add each part of the path as a child of the previous one
|
||||||
cmd = subcmd; //Add each part of the path as a child of the previous one
|
|
||||||
}
|
}
|
||||||
for (SubcommandData<ICommand2MC> subcmd : subcmds) {
|
for (SubcommandData<ICommand2MC> subcmd : subcmds) {
|
||||||
String[] subpath = ButtonPlugin.getCommand2MC().getCommandPath(subcmd.method.getName(), ' ').trim().split(" ");
|
String[] subpath = ButtonPlugin.getCommand2MC().getCommandPath(subcmd.method.getName(), ' ').trim().split(" ");
|
||||||
CommandNode<Object> scmd = cmd;
|
CommandNode<Object> scmd = cmd;
|
||||||
if (subpath[0].length() > 0) { //If the method is def, it will contain one empty string
|
if (subpath[0].length() > 0) { //If the method is def, it will contain one empty string
|
||||||
for (String s : subpath) {
|
for (String s : subpath) {
|
||||||
var subsubcmd = LiteralArgumentBuilder.literal(s).build();
|
scmd = appendSubcommand(s, scmd, subcmd); //Add method name part of the path (could_be_multiple())
|
||||||
scmd.addChild(subsubcmd);
|
|
||||||
scmd = subsubcmd; //Add method name part of the path (could_be_multiple())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Parameter[] parameters = subcmd.method.getParameters();
|
Parameter[] parameters = subcmd.method.getParameters();
|
||||||
|
@ -232,7 +253,7 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
|
||||||
if (parameter.isAnnotationPresent(TextArg.class))
|
if (parameter.isAnnotationPresent(TextArg.class))
|
||||||
type = StringArgumentType.greedyString();
|
type = StringArgumentType.greedyString();
|
||||||
else
|
else
|
||||||
type = BetterStringArgumentType.word();
|
type = StringArgumentType.word();
|
||||||
else if (ptype == int.class || ptype == Integer.class
|
else if (ptype == int.class || ptype == Integer.class
|
||||||
|| ptype == byte.class || ptype == Byte.class
|
|| ptype == byte.class || ptype == Byte.class
|
||||||
|| ptype == short.class || ptype == Short.class)
|
|| ptype == short.class || ptype == Short.class)
|
||||||
|
@ -244,12 +265,18 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
|
||||||
else if (ptype == double.class || ptype == Double.class)
|
else if (ptype == double.class || ptype == Double.class)
|
||||||
type = DoubleArgumentType.doubleArg();
|
type = DoubleArgumentType.doubleArg();
|
||||||
else if (ptype == char.class || ptype == Character.class)
|
else if (ptype == char.class || ptype == Character.class)
|
||||||
type = BetterStringArgumentType.word(1);
|
type = StringArgumentType.word();
|
||||||
else if (ptype == boolean.class || ptype == Boolean.class)
|
else if (ptype == boolean.class || ptype == Boolean.class)
|
||||||
type = BoolArgumentType.bool();
|
type = BoolArgumentType.bool();
|
||||||
else //TODO: Custom parameter types
|
else //TODO: Custom parameter types
|
||||||
type = BetterStringArgumentType.word();
|
type = StringArgumentType.word();
|
||||||
var arg = RequiredArgumentBuilder.argument(subcmd.parameters[i - 1], type).build();
|
val param = subcmd.parameters[i - 1];
|
||||||
|
var argb = RequiredArgumentBuilder.argument(param, type)
|
||||||
|
.suggests((SuggestionProvider<Object>) (context, builder) -> {
|
||||||
|
//TODO
|
||||||
|
return builder.suggest(param).buildFuture();
|
||||||
|
});
|
||||||
|
var arg = argb.build();
|
||||||
scmd.addChild(arg);
|
scmd.addChild(arg);
|
||||||
scmd = arg;
|
scmd = arg;
|
||||||
}
|
}
|
||||||
|
@ -263,7 +290,7 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
|
||||||
} catch (Exception e) { - Client log: Could not deserialize chroma:string
|
} catch (Exception e) { - Client log: Could not deserialize chroma:string
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}*/
|
}*/
|
||||||
commodore.register(bukkitCommand, maincmd);
|
commodore.register(maincmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package buttondevteam.lib.chat;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used if an argument should be completed with predefined strings.
|
||||||
|
*/
|
||||||
|
@Target(ElementType.PARAMETER)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface CustomTabComplete {
|
||||||
|
String[] value();
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package buttondevteam.lib.chat;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The method must return with {@link String}[] or {@link Iterable}<{@link String}> and may have the sender and preceding arguments as parameters.
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface CustomTabCompleteMethod {
|
||||||
|
/**
|
||||||
|
* The parameter's name where we want to give completion
|
||||||
|
*/
|
||||||
|
String param();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The subcommand(s) which have the parameter, by default the method's name
|
||||||
|
*/
|
||||||
|
String[] subcommand() default "";
|
||||||
|
}
|
|
@ -1,42 +0,0 @@
|
||||||
package buttondevteam.lib.chat.commandargs;
|
|
||||||
|
|
||||||
import com.mojang.brigadier.LiteralMessage;
|
|
||||||
import com.mojang.brigadier.StringReader;
|
|
||||||
import com.mojang.brigadier.arguments.ArgumentType;
|
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
||||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class BetterStringArgumentType implements ArgumentType<String> {
|
|
||||||
private final int len;
|
|
||||||
|
|
||||||
public static BetterStringArgumentType word() {
|
|
||||||
return new BetterStringArgumentType(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BetterStringArgumentType word(int maxlen) {
|
|
||||||
return new BetterStringArgumentType(maxlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String parse(StringReader reader) throws CommandSyntaxException {
|
|
||||||
if (len < 1)
|
|
||||||
return reader.readStringUntil(' ');
|
|
||||||
|
|
||||||
final int start = reader.getCursor();
|
|
||||||
if (reader.canRead(len + 1) && reader.peek(len) != ' ')
|
|
||||||
throw new SimpleCommandExceptionType(new LiteralMessage("String too long")).createWithContext(reader);
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
reader.skip();
|
|
||||||
return reader.getString().substring(start, reader.getCursor());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<String> getExamples() {
|
|
||||||
return StringArgumentType.StringType.SINGLE_WORD.getExamples();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue