Tab Completion - LilBroCodes/commander GitHub Wiki
Tab completion is a powerful feature of Commander that helps players discover and use your commands more easily. This page explains how tab completion works in Commander and how to customize it for your commands.
Commander provides automatic tab completion for your command structure. When you create a CommanderCommand
with tab completion enabled, Commander will:
- Automatically complete subcommand names
- Provide parameter suggestions based on parameter types
- Show custom suggestions for parameters when provided
Tab completion is enabled when you create a CommanderCommand
by setting the tabComplete
parameter to true
:
// Create the command with tab completion enabled
CommanderCommand command = new CommanderCommand(rootNode, true);
command.register(plugin, "mycommand");
When a player starts typing a command and presses the Tab key, Commander processes the request as follows:
- For the first argument, Commander suggests available subcommands
- For subsequent arguments, Commander delegates to the appropriate subcommand node
- For
CommandActionNode
parameters, Commander provides suggestions based on the parameter type and any custom suggestion provider
You can provide custom tab completion suggestions for parameters by supplying a suggestion provider when creating a TypedParameter
.
// Parameter with static suggestions
TypedParameter colorParam = new TypedParameter(
"color",
ParameterType.STRING,
() -> List.of("red", "green", "blue", "yellow")
);
// Parameter with dynamic suggestions (online players)
TypedParameter playerParam = new TypedParameter(
"player",
ParameterType.STRING,
() -> {
// Return a list of online player names
return Bukkit.getOnlinePlayers().stream()
.map(Player::getName)
.collect(Collectors.toList());
}
);
While the suggestion provider doesn't have access to the command sender or current arguments, you can create context-aware suggestions by using class fields or other mechanisms.
public class MyPlugin extends JavaPlugin {
private final Map<String, List<String>> contextualSuggestions = new HashMap<>();
@Override
public void onEnable() {
// Initialize suggestions
contextualSuggestions.put("world", List.of("overworld", "nether", "end"));
contextualSuggestions.put("gamemode", List.of("survival", "creative", "adventure", "spectator"));
// Create command with contextual suggestions
List<TypedParameter> parameters = List.of(
new TypedParameter("type", ParameterType.STRING, () -> {
return List.of("world", "gamemode");
}),
new TypedParameter("value", ParameterType.STRING, () -> {
// This is a simplification - in a real implementation,
// you would need to track the current command context
String currentType = getCurrentType();
return contextualSuggestions.getOrDefault(currentType, List.of());
})
);
// Create and register command
// ...
}
private String getCurrentType() {
// In a real implementation, you would track the current command context
// This is just a placeholder
return "world";
}
}
By default, Commander doesn't provide suggestions. You can provide custom suggestions if needed, but Commander won't on it's own. There is one exception for this - for boolean type parameters, Commander automatically adds the "true" and "false" suggestion if you don't provide any.
Commander automatically provides tab completion for the built-in help command:
- When the player types
/mycommand h
and presses Tab, Commander will suggesthelp
- When the player types
/mycommand help
and presses Tab, Commander will suggesttree
- Keep suggestion lists reasonably sized
- Avoid expensive operations in suggestion providers
- Cache suggestions when appropriate
- Provide meaningful suggestions that help players understand what's expected
- Use consistent suggestion patterns across your plugin
- Consider providing examples in your command descriptions
- Test tab completion for all your commands
- Verify that suggestions are appropriate for each parameter
- Check that suggestions update correctly as the player types
// Define parameters with suggestions
List<TypedParameter> parameters = List.of(
new TypedParameter("player", ParameterType.STRING, () -> {
return Bukkit.getOnlinePlayers().stream()
.map(Player::getName)
.collect(Collectors.toList());
}),
new TypedParameter("item", ParameterType.STRING, () -> {
return Arrays.stream(Material.values())
.filter(Material::isItem)
.map(Material::name)
.map(String::toLowerCase)
.collect(Collectors.toList());
}),
new TypedParameter("amount", ParameterType.INT, () -> {
return List.of("1", "8", "16", "32", "64");
})
);
// Create the command
CommandActionNode giveCommand = new CommandActionNode(
"give",
"Give items to a player",
"MyPlugin",
parameters,
(sender, args) -> {
// Command logic
}
);
// Define a map of regions and their teleport points
Map<String, List<String>> regionTeleports = new HashMap<>();
regionTeleports.put("spawn", List.of("hub", "shop", "pvp"));
regionTeleports.put("mines", List.of("coal", "iron", "gold", "diamond"));
regionTeleports.put("dungeons", List.of("easy", "medium", "hard", "boss"));
// Track the current region selection for each player
Map<UUID, String> playerRegionSelections = new HashMap<>();
// Define parameters with contextual suggestions
List<TypedParameter> parameters = List.of(
new TypedParameter("region", ParameterType.STRING, () -> {
return new ArrayList<>(regionTeleports.keySet());
}),
new TypedParameter("location", ParameterType.STRING, () -> {
// This is simplified - in a real implementation,
// you would need to track the current command context per player
String currentRegion = getCurrentRegion();
return regionTeleports.getOrDefault(currentRegion, List.of());
})
);
// Create the command
CommandActionNode teleportCommand = new CommandActionNode(
"teleport",
"Teleport to a location",
"MyPlugin",
parameters,
(sender, args) -> {
if (sender instanceof Player player) {
String region = (String) args.get(0);
String location = (String) args.get(1);
// Update the player's region selection for future tab completion
playerRegionSelections.put(player.getUniqueId(), region);
// Teleport logic
player.sendMessage("Teleporting to " + location + " in " + region);
}
}
);
// Helper method to get the current region
private String getCurrentRegion() {
// In a real implementation, you would get this from the player's context
return "spawn";
}
Now that you understand tab completion, check out these pages for more information:
- Advanced Usage - Discover advanced features and techniques