diff --git a/src/main/java/org/mvplugins/multiverse/core/command/MVCommandCompletionFilters.java b/src/main/java/org/mvplugins/multiverse/core/command/MVCommandCompletionFilters.java new file mode 100644 index 000000000..82194b9d8 --- /dev/null +++ b/src/main/java/org/mvplugins/multiverse/core/command/MVCommandCompletionFilters.java @@ -0,0 +1,60 @@ +package org.mvplugins.multiverse.core.command; + +import co.aikar.commands.CommandCompletionContext; +import co.aikar.commands.CommandCompletionFilter; +import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Locale; + +/** + * Utility filters for command completion matching. + * + * @since 5.7 + */ +@ApiStatus.AvailableSince("5.7") +public final class MVCommandCompletionFilters { + + /** + * Matches namespaced keys (for example, {@code minecraft:stone}) using namespace-aware checks. + *

+ * This filter accepts completions that: + *

+ * + * @since 5.7 + */ + @ApiStatus.AvailableSince("5.7") + public static final CommandCompletionFilter NAMESPACED_KEY = (context, completion) -> { + String[] split = completion.split(":", 2); + if (split.length < 2) { + return ApacheCommonsLangUtil.startsWithIgnoreCase(completion, context.getInput()); + } + String lowerCase = context.getInput().toLowerCase(Locale.ROOT); + return ApacheCommonsLangUtil.startsWithIgnoreCase(completion, context.getInput()) + || split[0].toLowerCase(Locale.ROOT).startsWith(lowerCase) + || split[1].toLowerCase(Locale.ROOT).contains(lowerCase); + }; + + /** + * Gets the namespaced-key completion filter with a generic type-safe signature. + * Use this method instead of {@link MVCommandCompletionFilters#NAMESPACED_KEY} + * to avoid raw type unchecked warnings. + * + * @param completion context type + * @return the namespaced key filter + * + * @since 5.7 + */ + @ApiStatus.AvailableSince("5.7") + public static CommandCompletionFilter namespacedKey() { + return NAMESPACED_KEY; + } + + private MVCommandCompletionFilters() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/src/main/java/org/mvplugins/multiverse/core/command/MVCommandCompletions.java b/src/main/java/org/mvplugins/multiverse/core/command/MVCommandCompletions.java index ae4ffcfb0..9c1b222c8 100644 --- a/src/main/java/org/mvplugins/multiverse/core/command/MVCommandCompletions.java +++ b/src/main/java/org/mvplugins/multiverse/core/command/MVCommandCompletions.java @@ -11,6 +11,7 @@ import java.util.stream.Collectors; import co.aikar.commands.BukkitCommandCompletionContext; +import co.aikar.commands.CommandCompletionFilter; import co.aikar.commands.CommandIssuer; import co.aikar.commands.PaperCommandCompletions; import co.aikar.commands.RegisteredCommand; @@ -89,27 +90,27 @@ public class MVCommandCompletions extends PaperCommandCompletions { this.generatorProvider = generatorProvider; this.potentialWorldFinder = potentialWorldFinder; - registerAsyncCompletion("anchornames", this::suggestAnchorNames); + registerAsyncCompletion("anchornames", this::suggestAnchorNames, CommandCompletionFilter.contains()); registerAsyncCompletion("commands", this::suggestCommands); registerAsyncCompletion("destinations", this::suggestDestinations); registerStaticCompletion("difficulties", suggestEnums(Difficulty.class)); registerStaticCompletion("environments", List.of("normal", "nether", "the_end")); // Don't tab complete the "custom" environment registerAsyncCompletion("flags", this::suggestFlags); registerStaticCompletion("gamemodes", suggestEnums(GameMode.class)); - registerStaticCompletion("gamerules", this::suggestGamerules); + registerStaticCompletion("gamerules", this::suggestGamerules, MVCommandCompletionFilters.namespacedKey()); registerAsyncCompletion("gamerulesvalues", this::suggestGamerulesValues); - registerAsyncCompletion("generatorplugins", this::suggestGeneratorPlugins); - registerStaticCompletion("materials", suggestEnums(Material.class)); - registerStaticCompletion("mvconfigs", config.getStringPropertyHandle().getAllPropertyNames()); + registerAsyncCompletion("generatorplugins", this::suggestGeneratorPlugins, CommandCompletionFilter.contains()); + registerStaticCompletion("materials", suggestEnums(Material.class), CommandCompletionFilter.contains()); + registerStaticCompletion("mvconfigs", config.getStringPropertyHandle().getAllPropertyNames(), CommandCompletionFilter.contains()); registerAsyncCompletion("mvconfigvalues", this::suggestMVConfigValues); - registerAsyncCompletion("mvworlds", this::suggestMVWorlds); - registerAsyncCompletion("mvworldmetakey", this::suggestMVWorldMetaKey); - registerAsyncCompletion("mvworldpropsname", this::suggestMVWorldPropsName); + registerAsyncCompletion("mvworlds", this::suggestMVWorlds, MVCommandCompletionFilters.namespacedKey()); + registerAsyncCompletion("mvworldmetakey", this::suggestMVWorldMetaKey, CommandCompletionFilter.contains()); + registerAsyncCompletion("mvworldpropsname", this::suggestMVWorldPropsName, CommandCompletionFilter.contains()); registerAsyncCompletion("mvworldpropsvalue", this::suggestMVWorldPropsValue); - registerCompletion("playersarray", this::suggestPlayersArray); // getting online players cannot be async + registerCompletion("playersarray", this::suggestPlayersArray, CommandCompletionFilter.contains()); // getting online players cannot be async registerStaticCompletion("propsmodifyaction", suggestEnums(PropertyModifyAction.class)); registerStaticCompletion("spawncategories", suggestEnums(SpawnCategory.class)); - registerAsyncCompletion("spawncategorypropsname", this::suggestSpawnCategoryPropsName); + registerAsyncCompletion("spawncategorypropsname", this::suggestSpawnCategoryPropsName, CommandCompletionFilter.contains()); registerAsyncCompletion("spawncategorypropsvalue", this::suggestSpawnCategoryPropsValue); setDefaultCompletion("destinations", DestinationInstance.class);