-
-
Notifications
You must be signed in to change notification settings - Fork 0
Tab Completion
command-lib integrates with Paper async completion through CommandTabCompleteManager, which listens to AsyncTabCompleteEvent.
If the manager is created with:
new CommandManager(this, true);the built-in async completion listener is registered automatically.
The framework includes built-in completions for:
PlayerbooleanDuration- enums
EnchantmentItemStack
If a handler argument has a type-based completer, it is used automatically unless a method-level @TabComplete overrides that position.
@TabComplete accepts a space-separated declaration string. Each token maps to one argument position.
Supported token forms:
-
@idfor a completer registered by id -
literal1|literal2|literal3for inline literal values -
*to skip a position
Example:
@SubCommand("gamemode")
@TabComplete("@players survival|creative|adventure|spectator")
public void gamemode(CommandSender sender, Player target, GameMode mode) {
}manager.registerTabCompleter("@warps", sender -> List.of("spawn", "shop", "pvp"));Then reference it:
@SubCommand("teleport")
@TabComplete("@warps")
public void teleport(Player player, String warpName) {
}manager.registerTabCompleter(Warp.class, (sender, argument) ->
warpService.listNames()
);This applies automatically to any Warp parameter.
Larger plugins often use both type-based and id-based completion:
commandManager.registerTabCompleter(Profile.class, (sender, argument) ->
profileService.findAllNames());
commandManager.registerTabCompleter("@kits", sender ->
kitService.listIds());And then consumes that in a command:
@SubCommand("give")
@TabComplete("* @kits")
public void giveExecutor(
CommandSender sender,
@Name("player") Player target,
@Name("kit") String kitId,
@Optional @Name("amount") Integer amount
) {
}That is a strong real-world example of mixing:
- automatic player completion
- skipped first argument via
* - explicit id-based completion for the next argument
@SubCommand("visibility")
@TabComplete("public|private")
public void visibility(CommandSender sender, String visibility) {
}Use * when you want to leave one argument position to its existing type-based behavior or with no suggestions:
@SubCommand("mail send")
@TabComplete("* @message-presets")
public void send(CommandSender sender, Player target, String preset) {
}The framework also suggests matching subcommand fragments based on the current input. This works for simple and multi-word subcommands.
Example subcommands:
teleportteleport heredelete
Typing /warp te will suggest matching subcommand segments.
Tab completion respects:
- command-level permission
- handler-level permission
If the sender cannot execute the handler, its completions are not exposed.
- tab completion support depends on Paper async command completion events
- the command must be registered through
CommandManager - completer output is returned as raw string suggestions
- custom managers are useful for larger projects with role-aware or config-aware completion behavior