Attribute Macro command

Source
#[command]
Expand description

This macro transforms plain functions into poise bot commands.

Documentation comments are used as help text. The first line is a single-line description, displayed in listings of your bot’s commands (i.e. ~help). Following paragraphs are detailed explanations, for example for command-specific help (i.e. ~help command_name). Escape newlines with \

§Macro arguments

#[poise::command] accepts a number of arguments to configure the command:

§Command types

  • prefix_command: Generate a prefix command
  • slash_command: Generate a slash command
  • context_menu_command: Generate a context menu command

§Meta properties

  • subcommands: List of subcommands subcommands("foo", "bar", "baz")
  • name_localized: Adds localized name of the parameter name_localized("locale", "new_name") (slash-only)
  • description_localized: Adds localized description of the parameter description_localized("locale", "Description") (slash-only)
  • rename: Choose an alternative command name instead of the function name
    • Useful if your command name is a Rust keyword, like move
  • aliases: Command name aliases (only applies to prefix commands)
  • category: Category of this command which affects placement in the help command
  • custom_data: Arbitrary expression that will be boxed and stored in Command::custom_data
  • identifying_name: Optionally, a unique identifier for this command for your personal usage
  • install_context: Installation contexts where this command is available (slash-only)
  • interaction_context: Interaction contexts where this command is available (slash-only)

§Checks

  • required_permissions: Permissions which the command caller needs to have
  • required_bot_permissions: Permissions which the bot is known to need
  • default_member_permissions: Like required_permissions, but checked server-side (slash only)
    • Due to being checked server-side, users without the required permissions are prevented from executing the command in the first place, which is a better experience
    • However, default_member_permissions has no effect on subcommands, which always inherit their permissions from the top-level command
    • Also, guild owners can freely change the required permissions for any bot command for their guild
  • owners_only: Restricts command callers to a configurable list of owners (see FrameworkOptions)
  • guild_only: Restricts command callers to only run on a guild
  • dm_only: Restricts command callers to only run on a DM
  • nsfw_only: Restricts command callers to only run on a NSFW channel
  • subcommand_required: Requires a subcommand to be specified (prefix only)
  • check: Path to a function which is invoked for every invocation. If the function returns false, the command is not executed (can be used multiple times)
  • hide_in_help: Hide this command in help menus
  • help_text_fn: Path to a string-returning function which is used for command help text instead of documentation comments
    • Useful if you have many commands with very similar help messages: you can abstract the common parts into a function

§Edit tracking (prefix only)

  • track_edits: Shorthand for invoke_on_edit, track_deletion, and reuse_response (prefix only)
  • invoke_on_edit: Reruns the command if an existing invocation message is edited (prefix only)
  • track_deletion: Deletes the bot response to a command if the command message is deleted (prefix only)
  • reuse_response: After the first response, post subsequent responses as edits to the initial message (prefix only)

§Cooldown

  • manual_cooldowns: Allows overriding the framework’s built-in cooldowns tracking without affecting other commands.
  • global_cooldown: Minimum duration in seconds between invocations, globally
  • user_cooldown: Minimum duration in seconds between invocations, per user
  • guild_cooldown: Minimum duration in seconds between invocations, per guild
  • channel_cooldown: Minimum duration in seconds between invocations, per channel
  • member_cooldown: Minimum duration in seconds between invocations, per guild member

§Other

  • on_error: Error handling function
  • broadcast_typing: Trigger a typing indicator while command runs (prefix only)
  • discard_spare_arguments: Don’t throw an error if the user supplies too many arguments (prefix only)
  • ephemeral: Make bot responses ephemeral if possible (slash only)
    • Only poise’s functions, like poise::send_reply, respect this preference

§Function parameters

Context is the first parameter of all command functions. It’s an enum over either PrefixContext or SlashContext, which contain a variety of context data each. Context provides some utility methods to access data present in both PrefixContext and SlashContext, like author() or created_at().

All following parameters are inputs to the command. You can use all types that implement poise::PopArgument, serenity::ArgumentConvert or std::str::FromStr. You can also wrap types in Option or Vec to make them optional or variadic. In addition, there are multiple attributes you can use on parameters:

§Meta properties

  • #[description = ""]: Sets description of the parameter (slash-only)
  • #[description_localized("locale", "Description")]: Adds localized description of the parameter (slash-only)
  • #[name_localized("locale", "new_name")]: Adds localized name of the parameter (slash-only)
  • #[autocomplete = "callback()"]: Sets the autocomplete callback (slash-only)
  • #[rename = "new_name"]: Changes the user-facing name of the parameter (slash-only)

§Input filter (slash only)

  • #[channel_types("", "")]: For channel parameters, restricts allowed channel types (slash-only)
  • #[min = 0]: Minimum value for this number parameter (slash-only)
  • #[max = 0]: Maximum value for this number parameter (slash-only)
  • #[min_length = 0]: Minimum length for this string parameter (slash-only)
  • #[max_length = 1]: Maximum length for this string parameter (slash-only)

§Parser settings (prefix only)

  • #[rest]: Use the entire rest of the message for this parameter (prefix-only)
  • #[lazy]: Can be used on Option and Vec parameters and is equivalent to regular expressions’ laziness (prefix-only)
  • #[flag]: Can be used on a bool parameter to set the bool to true if the user typed the parameter name literally (prefix-only)
    • For example with async fn my_command(ctx: Context<'_>, #[flag] my_flag: bool), ~my_command would set my_flag to false, and ~my_command my_flag would set my_flag to true

§Help text

Documentation comments are used as command help text. The first paragraph is the command description (Command::description) and all following paragraphs are the multiline help text (Command::help_text).

In the multiline help text, put \ at the end of a line to escape the newline.

Example:

/// This is the description of my cool command, it can span multiple
/// lines if you need to
///
/// Here in the following paragraphs, you can give information on how \
/// to use the command that will be shown in your command's help.
///
/// You could also put example invocations here:
/// `~coolcommand test`
#[poise::command(slash_command)]
pub async fn coolcommand(ctx: Context<'_>, s: String) -> Result<(), Error> { ... }

results in

poise::Command {
    description: Some("This is the description of my cool command, it can span multiple lines if you need to".into()),
    help_text: Some("Here in the following paragraphs, you can give information on how to use the command that will be shown in your command's help.\n\nYou could also put example invocations here:\n`~coolcommand test`".into()),
    ...
}

§Internals

Internally, this attribute macro generates a function with a single poise::Command return type, which contains all data about this command. For example, it transforms a function of this form:

/// This is a command
#[poise::command(slash_command, prefix_command)]
async fn my_command(ctx: Context<'_>) -> Result<(), Error> {
    // code
}

into something like

fn my_command() -> poise::Command<Data, Error> {
    async fn inner(ctx: Context<'_>) -> Result<(), Error> {
        // code
    }

    poise::Command {
        name: "my_command",
        description: "This is a command",
        prefix_action: Some(|ctx| Box::pin(async move {
            inner(ctx.into()).await
        })),
        slash_action: Some(|ctx| Box::pin(async move {
            inner(ctx.into()).await
        })),
        context_menu_action: None,
        // ...
    }
}

If you’re curious, you can use cargo expand to see the exact desugaring