Declarative slash commands¶
Declarative commands must be declared with Kotlin, but the command itself may be in any language.
Declarative commands allow you full control over the declaration, implement at least one of them:
GlobalApplicationCommandProvider(for everyone at once)GuildApplicationCommandProvider(on each guild)
You can then use the slashCommand method on the manager, give it the command name, the command method,
and then configure your command.
Tip
You are free to skip registration of any command/subcommand/group, for example,
if the guild in GuildApplicationCommandManager isn't a guild you want the command to appear in.
Example
@Command
class SlashPing : GlobalApplicationCommandProvider {
suspend fun onSlashPing(event: GuildSlashEvent) {
event.deferReply(true).queue()
val ping = event.jda.getRestPing().await()
event.hook.editOriginal("Pong! $ping ms").await()
}
override fun declareGlobalApplicationCommands(manager: GlobalApplicationCommandManager) {
// Default scope is global, guild-only (GUILD_NO_DM)
manager.slashCommand("ping", function = ::onSlashPing) {
description = "Pong!"
}
}
}
Subcommands¶
As top-level commands cannot be made alongside subcommands, the top-level function must be null.
You can then add a subcommand by using subcommand, where each subcommand is its own function.
Example
@Command
class SlashTag : GlobalApplicationCommandProvider {
fun onSlashTagCreate(event: GuildSlashEvent) {
// ...
}
fun onSlashTagDelete(event: GuildSlashEvent) {
// ...
}
override fun declareGlobalApplicationCommands(manager: GlobalApplicationCommandManager) {
// Pass a null function as this is not a top-level command
manager.slashCommand("tag", function = null) {
description = "Manage tags"
subcommand("create", ::onSlashTagCreate) {
description = "Creates a tag"
}
subcommand("delete", ::onSlashTagDelete) {
description = "Deletes a tag"
}
}
}
}
Info
You can still create both subcommands, and subcommand groups containg subcommands.
Adding options¶
Options can be added with a parameter and declaring it using option in your command builder,
where the declaredName is the name of your parameter, the block will let you change the description, choices, etc.
All supported types are documented under SlashParameterResolver, and other types can be added.
Example
@Command
class SlashSay : GlobalApplicationCommandProvider {
suspend fun onSlashSay(event: GuildSlashEvent, content: String) {
event.reply(content).await()
}
override fun declareGlobalApplicationCommands(manager: GlobalApplicationCommandManager) {
manager.slashCommand("say", function = ::onSlashSay) {
description = "Says something"
option("content") {
description = "What to say"
}
}
}
}
Tip
You can override the option name by setting optionName in the option declaration:
option("content", optionName = "sentence") {
...
}
Using choices¶
There are two ways of setting choices for an option.
With the builder property¶
A choices property is available for you to give a list of choices to be used.
This one is useful if the choices may differ from other similar options.
Example
@Command
class SlashConvert : GlobalApplicationCommandProvider {
suspend fun onSlashConvert(event: GuildSlashEvent, time: Long, from: TimeUnit, to: TimeUnit) {
event.reply("${to.convert(time, from)} ${to.name.lowercase()}").await()
}
override fun declareGlobalApplicationCommands(manager: GlobalApplicationCommandManager) {
manager.slashCommand("convert", function = ::onSlashConvert) {
description = "Convert time to another unit"
option("time") {
description = "The time to convert"
}
option("from") {
description = "The unit to convert from"
choices = listOf(TimeUnit.SECONDS, TimeUnit.MINUTES, TimeUnit.HOURS, TimeUnit.DAYS)
// The Resolvers class helps us by providing resolvers for any enum type.
// We're just using the helper method to change an enum value to a more natural name.
.map { Choice(Resolvers.toHumanName(it), it.name) }
}
option("to") {
description = "The unit to convert to"
choices = listOf(TimeUnit.SECONDS, TimeUnit.MINUTES, TimeUnit.HOURS, TimeUnit.DAYS)
// The Resolvers class helps us by providing resolvers for any enum type.
// We're just using the helper method to change an enum value to a more natural name.
.map { Choice(Resolvers.toHumanName(it), it.name) }
}
}
}
}
With choices predefined by the resolver¶
This one is useful if the choices are the same for all parameters of the same type.
After implementing SlashParameterResolver.getPredefinedChoices, you can enable them on your option with usePredefinedChoices = true.
Using the predefined choices
@Command
class SlashConvertSimplified : GlobalApplicationCommandProvider {
suspend fun onSlashConvertSimplified(event: GuildSlashEvent, time: Long, from: TimeUnit, to: TimeUnit) {
event.reply("${to.convert(time, from)} ${to.name.lowercase()}").await()
}
override fun declareGlobalApplicationCommands(manager: GlobalApplicationCommandManager) {
manager.slashCommand("convert", function = ::onSlashConvertSimplified) {
description = "Convert time to another unit"
option("time") {
description = "The time to convert"
}
option("from") {
description = "The unit to convert from"
usePredefinedChoices = true
}
option("to") {
description = "The unit to convert to"
usePredefinedChoices = true
}
}
}
}
Using autocomplete¶
Learn how to create an autocomplete handler here
Enabling autocompletion for an option is done by referencing an existing handler:
- (recommended) Reference autocomplete handlers by their function with
autocompleteByFunction - Reference named autocomplete handlers with
autocompleteByName
Example
Using the autocomplete handler we made in "Creating autocomplete handlers":
@Command
class SlashWord : GlobalApplicationCommandProvider {
suspend fun onSlashWord(event: GuildSlashEvent, word: String) {
event.reply_("Your word was $word", ephemeral = true).await()
}
override fun declareGlobalApplicationCommands(manager: GlobalApplicationCommandManager) {
manager.slashCommand("word", function = ::onSlashWord) {
description = "Autocompletes a word"
option("word") {
description = "The word"
// Use an existing autocomplete declaration
autocompleteByFunction(SlashWordAutocomplete::onWordAutocomplete)
}
}
}
}
Generated values¶
Generated values are a command parameter that gets their values computed by the given block everytime the command run.
Contrary to the annotated commands, no checks are required, as this is tied to the currently built command.
Example
@Command
class SlashCreateTime : GlobalApplicationCommandProvider {
suspend fun onSlashCreateTime(event: GuildSlashEvent, timestamp: Instant) {
event.reply("I was created on ${TimeFormat.DATE_TIME_SHORT.format(timestamp)}").await()
}
override fun declareGlobalApplicationCommands(manager: GlobalApplicationCommandManager) {
manager.slashCommand("create_time", function = ::onSlashCreateTime) {
description = "Shows the creation time of this command"
// Create a snapshot of the instant the command was created
val now = Instant.now()
generatedOption("timestamp") {
// Give back the instant snapshot, as this will be called every time the command is run
return@generatedOption now
}
}
}
}
Rate limiting¶
This lets you reject application commands if the user tries to use them too often, see "Using rate limiters in commands".