docs/application_command.md
<!--
# @title Application Commands
-->
# Application Commands
## What is an application command?
> Application commands are commands that an application can register to Discord. They provide users a first-class way of interacting directly with your application that feels deeply integrated into Discord.
From: [Discord API docs](https://discord.com/developers/docs/interactions/application-commands#application-commands)
## How do I register an application command?
Write to your script:
- {Discorb::ApplicationCommand::Handler.slash}, {Discorb::ApplicationCommand::Handler.slash_group} for slash commands,
- {Discorb::ApplicationCommand::Handler.user_command} for user menu commands,
- {Discorb::ApplicationCommand::Handler.message_command} for message menu commands.
And then run `discorb setup` to register your application commands.
{file:docs/cli/setup.md Learn more about `discorb setup`}.
### Note
To register a global command, it will take 1 hour to be registered.
Guild commands will be registered immediately.
### Register Slash Commands
This example registers a slash command that says "Hello, world!" when the user types `/hello`.
```ruby
require "discorb"
client = Discorb::Client.new
client.slash("hello", "Greet for you") do |interaction|
interaction.post("Hello World!", ephemeral: true)
end
client.run(ENV["DISCORD_BOT_TOKEN"])
```
{Discorb::ApplicationCommand::Handler#slash} takes 5 arguments:
| Argument | Description |
| -------------- | -------------------------------------------------------- |
| `command_name` | The name of the command. |
| `description` | The description of the command. |
| `options` | A hash of options. |
| `guild_ids` | The ID of the guild to register the command in. |
| `block` | A block that will be called when the command is invoked. |
Block will be called with a {Discorb::Interaction} object and specified options.
#### Register options
You can set hash to `options` argument.
In `options`, hash should be like this:
```ruby
{
"name" => {
type: :string,
required: true,
description: "The description of the command."
}
}
```
| Key | Type | Description |
| ------------------------ | ---------------------------------------- | ------------------------------------------------------------------------------------- |
| `:name_localizations` | `Hash{Symbol => String}` | Localizations of option name. |
| `:description` | `String` | Description of the option. |
| `:required` | `Boolean(true\|false)` | Whether the argument is required. `optional` will be used if not specified. |
| `:optional` | `Boolean(true\|false)` | Whether the argument is optional. `required` will be used if not specified. |
| `:type` | `Object` | Type of the option. |
| `:choices` | `Hash{String => String, Integer, Float}` | Choice of the option. |
| `:choices_localizations` | `Hash{String => Hash{Symbol => String}}` | Localization of the choice. Key must be the name of a choice. (See below for example) |
| `:default` | `Object` | Default value of the option. |
| `:channel_types` | `Array<Class<Discorb::Channel>>` | Type of the channel option. |
| `:autocomplete` | `Proc` | Autocomplete function. |
| `:range` | `Range` | Range of the option. Only valid for numeric options. (`:int`, `:float`) |
| `:length` | `Range` | Range of length of the option. Only valid for `:string`. |
`choices` should be unspecified if you don't want to use it.
`choices` example:
```ruby
{
"vocaloid" => {
required: true,
description: "The vocaloid which you like.",
type: :string,
choices: {
"Hatsune Miku" => "miku",
"Kagamine Rin" => "rin",
"Kagamine Len" => "len",
"Megurine Luka" => "luka",
"MEIKO" => "meiko",
"KAITO" => "kaito",
}
}
}
# Note: This aritcle is written in 8/31.
```
The key will be displayed in the user menu, and the value will be used as the argument.
In `type`, You must use one of the following:
| Name | Description | Aliases |
| ---------- | ----------------- | --------- |
| `:string` | String argument. | `:str` |
| `:integer` | Integer argument. | `:int` |
| `:float` | Float argument. | None |
| `:boolean` | Boolean argument. | `:bool` |
| `:user` | User argument. | `:member` |
| `:channel` | Channel argument. | None |
| `:role` | Role argument. | None |
The block will receive the options as arguments.
```ruby
client.slash("hello", "Bot greets", {
"name" => {
type: :string,
description: "Name"
}
}) do |interaction, name|
interaction.post("Hello, #{name}!", ephemeral: true)
end
```
#### Group Slash Commands
To register a group of slash commands, use {Discorb::ApplicationCommand::Handler#slash_group}.
```ruby
group = client.slash_group("settings", "Set settings of bot.")
group.slash("message_expand", "Whether bot should expand message.", {
"enabled" => {
type: :boolean,
description: "Whether bot should expand message."
}
}) do |interaction, enabled|
# ...
end
group.slash("level", "Whether level system is enabled.", {
"enabled" => {
type: :boolean,
description: "Whether level system is enabled."
}
}) do |interaction, enabled|
# ...
end
```
Since v0.5.1, You can use block for register commands.
```ruby
client.slash_group("settings", "Set settings of bot.") do |group|
group.slash("message_expand", "Whether bot should expand message.", {
"enabled" => {
type: :boolean,
description: "Whether bot should expand message."
}
}) do |interaction, enabled|
# ...
end
group.slash("bump_alert", "Whether level system is enabled.", {
"enabled" => {
type: :boolean,
description: "Whether level system is enabled."
}
}) do |interaction, enabled|
# ...
end
end
```
You can make subcommand group by using {Discorb::ApplicationCommand::Command::GroupCommand#group}.
```ruby
group = client.slash_group("permission", "Set/Get command permissions.")
group_user = group.group("user", "Set/Get user's command permissions.")
group_user.slash("set", "Set user's command permissions.", {
"user_id" => {
type: :user,
description: "The user."
},
"value" => {
type: :boolean,
description: "Whether the user can use the command."
}
}) do |interaction, user|
# ...
end
group_user.slash("get", "Set user's command permissions.", {
"user_id" => {
type: :user,
description: "The user."
},
}) do |interaction, user|
# ...
end
group_user = group.group("user", "Set/Get user's command permissions.")
group_user.slash("set", "Set user's command permissions.", {
"user_id" => {
type: :user,
description: "The user."
},
"value" => {
type: :boolean,
description: "Whether the user can use the command."
}
}) do |interaction, user|
# ...
end
group_user.slash("get", "Set user's command permissions.", {
"user_id" => {
type: :user,
description: "The user."
},
}) do |interaction, user|
# ...
end
group_role = group.group("role", "Set/Get role's command permissions.")
group_role.slash("set", "Set role's command permissions.", {
"role_id" => {
type: :role,
description: "The role."
},
"value" => {
type: :boolean,
description: "Whether the role can use the command."
}
}) do |interaction, role|
# ...
end
group_role.slash("get", "Set role's command permissions.", {
"role_id" => {
type: :role,
description: "The role."
},
}) do |interaction, role|
# ...
end
```
Same as above, you can use block for register commands since v0.5.1.
#### Use Auto Completing
Since v0.11.0, you can use auto-completion by setting Proc to `:autocomplete` in options.
The proc will be called with interaction object and the argument.
The proc should return a hash of the autocomplete result.
```ruby
client.slash("hello2", "Greet for you", {
"target" => {
type: :string,
description: "Person to greet",
autocomplete: ->(interaction, target) {
{
"You" => interaction.target.to_s
}
},
},
}) do |interaction, target|
interaction.post("Hello, #{target}!")
end
```
In the above example, `You` will be displayed in the user menu.
Due to the limitation of Discord API, the proc must return the result in less than 3 second.
### Register User Context Menu Command
```ruby
client.user_command("hello") do |interaction, user|
interaction.post("Hello, #{user.name}!")
end
```
{Discorb::ApplicationCommand::Handler.user_command} takes 3 arguments:
| Parameter | Description |
| -------------- | -------------------------------------------------------- |
| `command_name` | The name of the command. |
| `guild_ids` | The ID of the guild to register the command in. |
| `block` | A block that will be called when the command is invoked. |
`block` will be called with two arguments:
| Parameter | Description |
| ------------- | ----------------------- |
| `interaction` | The interaction object. |
| `user` | The user object. |
### Register Message Context Menu Command
```ruby
client.message_command("Bookmark") do |interaction, message|
# ...
end
```
{Discorb::ApplicationCommand::Handler.message_command} takes 3 arguments:
| Parameter | Description |
| -------------- | -------------------------------------------------------- |
| `command_name` | The name of the command. |
| `guild_ids` | The ID of the guild to register the command in. |
| `block` | A block that will be called when the command is invoked. |
`block` will be called with two arguments:
| Parameter | Description |
| ------------- | ----------------------- |
| `interaction` | The interaction object. |
| `message` | The message object. |
### Localizing command
You can localize commands with passing parameters, or setting Hash to name.
Also, you can change the text by checking `interaction.locale` and `interaction.guild_locale`.
Command name localize example:
```ruby
localizations = {
localized: {
text: {
en: "Hello, %s!",
ja: "%sさん、こんにちは!",
},
},
}
client.slash({
default: "greet",
ja: "挨拶",
}, {
default: "Bot greets. Cute OwO",
ja: "Botが挨拶します。かわいいね",
}, {
"name" => {
name_localizations: {
ja: "名前",
},
description: {
default: "The name to greet.",
ja: "挨拶する人の名前。",
},
type: :string,
optional: true,
},
}) do |interaction, name|
interaction.post(
(localizations[:localized][:text][interaction.locale] || localizations[:localized][:text][:en]) % [name || interaction.target.to_s_user],
ephemeral: true,
)
end
```
Option localize example:
```ruby
{
"vocaloid" => {
name_localizations: {
ja: "ボカロ",
},
required: true,
description: "The vocaloid which you like.",
description_localizations: {
ja: "好きなボカロ。",
},
type: :string,
choices: {
"Hatsune Miku" => "miku",
"Kagamine Rin" => "rin",
"Kagamine Len" => "len",
"Megurine Luka" => "luka",
"MEIKO" => "meiko",
"KAITO" => "kaito",
},
choice_localizations: {
"Hatsune Miku" => {
ja: "初音ミク",
},
"Kagamine Rin" => {
ja: "鏡音リン",
},
"Kagamine Len" => {
ja: "鏡音レン",
},
"Megurine Luka" => {
ja: "巡音ルカ",
},
"MEIKO" => {
ja: "MEIKO",
},
"KAITO" => {
ja: "KAITO",
},
}
}
}
```