diff --git a/src/main/java/co/aikar/commands/BaseCommand.java b/src/main/java/co/aikar/commands/BaseCommand.java index 34538696..194e1f37 100644 --- a/src/main/java/co/aikar/commands/BaseCommand.java +++ b/src/main/java/co/aikar/commands/BaseCommand.java @@ -365,7 +365,7 @@ public abstract class BaseCommand extends Command { if ("@players".equals(completion)) { return super.tabComplete(sender, commandLabel, args); } - List cmds = CommandCompletions.of(sender, completion, input); + List cmds = manager.getCommandCompletions().of(sender, completion, input); if (cmds.isEmpty()) { cmds = ImmutableList.of(input); } diff --git a/src/main/java/co/aikar/commands/BukkitCommandCompletions.java b/src/main/java/co/aikar/commands/BukkitCommandCompletions.java new file mode 100644 index 00000000..2b640f8e --- /dev/null +++ b/src/main/java/co/aikar/commands/BukkitCommandCompletions.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package co.aikar.commands; + +import org.bukkit.entity.EntityType; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class BukkitCommandCompletions extends CommandCompletions { + BukkitCommandCompletions() { + super(); + registerCompletion("mobs", (sender, completionConfig, input) -> { + final Stream normal = Stream.of(EntityType.values()) + .map(entityType -> CommandUtil.simplifyString(entityType.getName())); + return normal.collect(Collectors.toList()); + }); + } + +} diff --git a/src/main/java/co/aikar/commands/BukkitCommandContexts.java b/src/main/java/co/aikar/commands/BukkitCommandContexts.java index 8b3dceee..e24f73cf 100644 --- a/src/main/java/co/aikar/commands/BukkitCommandContexts.java +++ b/src/main/java/co/aikar/commands/BukkitCommandContexts.java @@ -33,8 +33,8 @@ import org.bukkit.entity.Player; public class BukkitCommandContexts extends CommandContexts { - BukkitCommandContexts(CommandManager manager) { - super(manager); + BukkitCommandContexts() { + super(); registerContext(OnlinePlayer.class, (c) -> { final String playercheck = c.popFirstArg(); diff --git a/src/main/java/co/aikar/commands/BukkitCommandManager.java b/src/main/java/co/aikar/commands/BukkitCommandManager.java index fa4398c3..ebce726a 100644 --- a/src/main/java/co/aikar/commands/BukkitCommandManager.java +++ b/src/main/java/co/aikar/commands/BukkitCommandManager.java @@ -25,6 +25,7 @@ package co.aikar.commands; import org.bukkit.Bukkit; import org.bukkit.command.Command; +import org.bukkit.command.CommandMap; import org.bukkit.plugin.Plugin; import java.util.Map; @@ -34,24 +35,36 @@ public class BukkitCommandManager implements CommandManager { @SuppressWarnings("WeakerAccess") protected final Plugin plugin; private CommandContexts contexts; + private CommandCompletions completions; public BukkitCommandManager(Plugin plugin) { this.plugin = plugin; - this.contexts = new CommandContexts(this); } @Override public CommandContexts getCommandContexts() { + if (this.contexts == null) { + this.contexts = new BukkitCommandContexts(); + } return contexts; } + @Override + public CommandCompletions getCommandCompletions() { + if (this.completions == null) { + this.completions = new BukkitCommandCompletions(); + } + return completions; + } + @Override public boolean register(BaseCommand command) { command.manager = this; final String plugin = this.plugin.getName().toLowerCase(); + final CommandMap commandMap = Bukkit.getServer().getCommandMap(); boolean allSuccess = true; for (Map.Entry entry : command.registeredCommands.entrySet()) { - if (!Bukkit.getServer().getCommandMap().register(entry.getKey().toLowerCase(), plugin, entry.getValue())) { + if (!commandMap.register(entry.getKey().toLowerCase(), plugin, entry.getValue())) { allSuccess = false; } } diff --git a/src/main/java/co/aikar/commands/CommandCompletions.java b/src/main/java/co/aikar/commands/CommandCompletions.java index aa3c472d..bf7a5347 100644 --- a/src/main/java/co/aikar/commands/CommandCompletions.java +++ b/src/main/java/co/aikar/commands/CommandCompletions.java @@ -28,47 +28,55 @@ import com.google.common.collect.Lists; import org.bukkit.command.CommandSender; import org.bukkit.entity.EntityType; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; -import java.util.stream.Stream; -public final class CommandCompletions { - private CommandCompletions() {} +@SuppressWarnings("WeakerAccess") +public class CommandCompletions { + private Map completionMap = new HashMap<>(); - private static final List EMPTY = ImmutableList.of(); - public static List of(CommandSender sender, String completion, String input) { + public CommandCompletions() { + registerCompletion("range", (sender, completionConfig, input) -> { + if (completionConfig == null) { + return ImmutableList.of(); + } + final String[] ranges = CommandPatterns.DASH.split(completionConfig); + int start; + int end; + if (ranges.length != 2) { + start = 0; + end = CommandUtil.parseInt(ranges[0], 0); + } else { + start = CommandUtil.parseInt(ranges[0], 0); + end = CommandUtil.parseInt(ranges[1], 0); + } + return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); + }); + registerCompletion("timeunits", (sender, completionConfig, input) -> ImmutableList.of("hours", "days", "weeks", "months", "minutes")); + } + + public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler handler) { + return this.completionMap.put("@" + id.toLowerCase(), handler); + } + + public List of(CommandSender sender, String completion, String input) { if (completion == null) { return ImmutableList.of(); } String[] complete = CommandPatterns.COLON.split(completion, 2); - switch (complete[0]) { - case "@range": - if (complete.length == 1) { - return ImmutableList.of(); - } - final String[] ranges = CommandPatterns.DASH.split(complete[1]); - int start; - int end; - if (ranges.length != 2) { - start = 0; - end = CommandUtil.parseInt(ranges[0], 0); - } else { - start = CommandUtil.parseInt(ranges[0], 0); - end = CommandUtil.parseInt(ranges[1], 0); - } - return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); - case "@timeunits": - return ImmutableList.of("hours", "days", "weeks", "months", "minutes"); - - case "@mobs": - final Stream normal = Stream.of(EntityType.values()) - .map(entityType -> CommandUtil.simplifyString(entityType.getName())); - return normal.collect(Collectors.toList()); - default: - return Lists.newArrayList(CommandPatterns.PIPE.split(completion)); + CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); + if (handler != null) { + return handler.getCompletions(sender, complete.length == 1 ? null : complete[1], input); } + return Lists.newArrayList(CommandPatterns.PIPE.split(completion)); + } + + public interface CommandCompletionHandler { + List getCompletions(CommandSender sender, String completionConfig, String input); } } diff --git a/src/main/java/co/aikar/commands/CommandContexts.java b/src/main/java/co/aikar/commands/CommandContexts.java index b124da9e..b3843546 100644 --- a/src/main/java/co/aikar/commands/CommandContexts.java +++ b/src/main/java/co/aikar/commands/CommandContexts.java @@ -25,29 +25,20 @@ package co.aikar.commands; import co.aikar.commands.annotation.Single; import co.aikar.commands.annotation.Split; -import co.aikar.commands.annotation.Optional; import co.aikar.commands.annotation.Values; import co.aikar.commands.contexts.ContextResolver; -import co.aikar.commands.contexts.OnlinePlayer; import co.aikar.commands.contexts.SenderAwareContextResolver; import com.google.common.collect.Maps; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.command.CommandSender; import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; import java.util.List; import java.util.Map; @SuppressWarnings("WeakerAccess") public class CommandContexts { - private final CommandManager manager; private final Map, ContextResolver> contextMap = Maps.newHashMap(); - CommandContexts(CommandManager manager) { - this.manager = manager; + CommandContexts() { registerContext(Integer.class, (c) -> { try { return CommandUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")).intValue(); diff --git a/src/main/java/co/aikar/commands/CommandExecutionContext.java b/src/main/java/co/aikar/commands/CommandExecutionContext.java index 3c0965d9..94ca1a38 100644 --- a/src/main/java/co/aikar/commands/CommandExecutionContext.java +++ b/src/main/java/co/aikar/commands/CommandExecutionContext.java @@ -37,7 +37,7 @@ import java.lang.reflect.Parameter; import java.util.List; import java.util.Map; -/*@Data*/ public class CommandExecutionContext { +public class CommandExecutionContext { private final RegisteredCommand cmd; private final Parameter param; private final CommandSender sender; diff --git a/src/main/java/co/aikar/commands/CommandManager.java b/src/main/java/co/aikar/commands/CommandManager.java index fe1917ea..5d93c714 100644 --- a/src/main/java/co/aikar/commands/CommandManager.java +++ b/src/main/java/co/aikar/commands/CommandManager.java @@ -26,11 +26,17 @@ package co.aikar.commands; public interface CommandManager { /** - * Gets the command contexts registered + * Gets the command contexts manager * @return Command Contexts */ CommandContexts getCommandContexts(); + /** + * Gets the command completions manager + * @return + */ + CommandCompletions getCommandCompletions(); + /** * Registers a command with ACF * diff --git a/src/main/java/co/aikar/commands/RegisteredCommand.java b/src/main/java/co/aikar/commands/RegisteredCommand.java index b5148ae7..9bb73c2b 100644 --- a/src/main/java/co/aikar/commands/RegisteredCommand.java +++ b/src/main/java/co/aikar/commands/RegisteredCommand.java @@ -151,7 +151,7 @@ public class RegisteredCommand { final String[] split = CommandPatterns.PIPE.split(values.value()); Set possible = Sets.newHashSet(); for (String s : split) { - List check = CommandCompletions.of(sender, s, arg); + List check = this.scope.manager.getCommandCompletions().of(sender, s, arg); if (!check.isEmpty()) { possible.addAll(check.stream().map(String::toLowerCase).collect(Collectors.toList())); } else {