Vesper Framework 
vesper is a slash command framework meant to be used by twilight
Note: The framework is new and might have some problems, all contributions are appreciated
This crate is independent from the twilight ecosystem
vesper is a command framework which uses slash commands, it mainly offers variable argument parsing.
Parsing is done with the Parse trait, so users can implement the parsing of their own types.
Argument parsing is done in a named way, this means the argument name shown on discord gets parsed into the arguments named the same way in the handler function.
The framework itself doesn't spawn any tasks by itself, so you might want to wrap it in an Arc and call
tokio::spawn before calling the .process method.
Usage example
use Arc;
use StreamExt;
use ;
use Client;
use Event;
use Intents;
use ;
use Id;
use ;
use *;
async
async
async
Usage guide
Creating commands
Every command is an async function, having always as the first parameter a &mut SlashContext<T>
Non mutable references can also be used, but the framework will convert them to mutable under the hood.
The framework supports chat, message and user commands, let's take a look at each of them
Chat command
// or #[command]
async
User command
async
Message command
async
As you can see, the only difference between them is the usage of #[command({chat, user, message}) and the fact that only
chat commands can take arguments.
The command macro defaults to a chat command, so if none of {chat, user, message} specifiers is used, the macro
will treat it as a chat command, so #[command] is equivalent to #[command(chat)].
If a non-chat command takes arguments in it's handler, the framework will allow it, but it won't send them to discord.
The framework also provides a #[only_guilds] attribute which will mark the command to only be available on guilds and
an #[nsfw] for nsfw commands.
The same command used before as an example could be marked only for guilds/nsfw the following way:
// This command is now marked as nsfw
async
// This command is now only marked as only available inside of guilds
async
// This command is now marked as nsfw and only available inside guilds
async
Using localizations
The framework allows localizations in commands and its arguments, to do this we have #[localized_names] and #[localized_descriptions]
attributes, these attributes accept a comma separated list of items. Let's take a look at them:
Locales must be valid, to see them, refer to Discord locales reference
async
Using functions to provide localizations
Localizations can also be set by using a closure or function pointer, for this we have the #[localized_names_fn] and
#[localized_descriptions_fn].
These functions must have the following signature:
fn
To use a closure directly, the attribute has to be used like #[localized_{names/descriptions}_fn = |f, c| ...]
To use a function pointer, the attribute accepts both #[localized_{names/descriptions}_fn = myfn] and
#[localized_{names/descriptions}_fn(myfn)]
Command functions
Command functions must include a description attribute, which will be seen in discord when the user tries to use the command.
The #[command] macro also allows to rename the command by passing the name of the command to the attribute like
#[command({chat, user, message}, name = "Command name here")]. If the name is not provided, the command will use the
function name.
If using the short form of #[command] while creating a chat command, the rename can be passed directly like
#[command("Command name")], that is equivalent to #[command(chat, name = "Command name")]
Command arguments
Command arguments are very similar to command functions, they also need a #[description] attribute that will be seen
in discord by the user when filling up the command argument.
As shown in the example, a #[rename] attribute can also be used, this will change the name of the argument seen in
discord. If the attribute is not used, the argument will have the same name as in the function.
Arguments can also be marked with a #[skip] attribute. Arguments marked as #[skip] don't allow#[description]
nor#[rename] attributes and won't be seen in discord when using the command, but they will be parsed by the framework. This can
be useful for extracting data that has nothing to do with the command input from the interaction. Let's take a look
at an example:
async
Important: All command functions must have as the first parameter a &mut SlashContext<T>
Setting choices as command arguments
Choices are a very useful feature of slash commands, allowing the developer to set some choices from which the user has to choose.
vesper allows doing this in an easy way, to allow this, a derive macro is provided by the framework. This macro is
named the same way as Parse trait and can only be used in enums to define the options. Renaming is also allowed here
by using the #[parse(rename)] attribute and allows to change the option name seen in discord.
async
Autocompleting commands
Autocomplete user input is made easy with vesper, just use the autocomplete macro provided by the framework.
Here, take a look at this example. We'll use as the base an empty command like this
async
As you may have noticed, we added an autocomplete attribute to the argument arg. The input specified on it must
point to a function marked with the #[autocomplete] attribute like this one:
async
Autocompleting functions must have an AutocompleteContext<T> as the sole parameter, it allows you to access to the
data stored at the framework while also allowing you to access the raw interaction, the framework's http client and the
user input, if exists.
Permissions
To specify required permissions to run a command, just use the #[required_permissions] attribute when declaring
a command, or the .required_permissions method when declaring a command group.
The attribute accepts as input a comma separated list of
twilight's permissions. Let's take
a look at what it would look like to create a command needing MANAGE_CHANNELS and MANAGE_MESSAGES permissions:
async
Command Groups
vesper supports both SubCommands and SubCommandGroups by default.
To give examples, let's say we have created the following command:
async
With this we can now create both subcommands and subcommand groups
Creating subcommands
To create a subcommand you need to create a group, then you can add all the subcommands.
async
Creating subcommand groups
Subcommand groups are very similar to subcommands, they are created almost the same way, but instead of using
.add_command directly, we have to use .group before to register a group.
async
Hooks
There are three hooks available, before, after and error_handler.
Before
The before hook is triggered before the command and has to return a bool indicating if the command should be executed or not.
async
After
The after hook is triggered after the command execution, and it provides the result of the command.
async
Specific error handling
Commands can have specific error handlers. When an error handler is set to a command, if the command (or any of its checks)
fails, the error handler will be called, and the after hook will receive None as the third argument. However, in case
the command execution finishes without raising errors, the after hook will receive the result of the command.
Let's take a look at a simple implementation:
async
async
Since the command will always fail because a bot cannot ban itself, the error handler will be called everytime the command
executes, thus passing None to the after hook if set.
Checks
Checks are pretty similar to the Before hook, but unlike it, they are not global. Instead, they need to be assigned
to each command.
Let's take a look on how to use it:
Let's create some checks like this:
async
async
Then we can assign them to our command using the check attribute, which accepts a comma separated list of checks:
async
Using custom return types
The framework allows the user to specify what types to return from command/checks execution. The framework definition is like this:
Where D is the type of the data held by the framework and T and E are the return types of a command in form of
Result<T, E>, however, specifying custom types is optional, and the framework provides a DefaultCommandResult and
DefaultError for those who don't want to have a custom error.
The types of the after, error_handler and check hook arguments change accordingly to the generics specified in
the framework, so their signatures could be interpreted like this:
After hook:
async fn
Error handler hook:
async fn
Command checks:
async fn
Note that those are not the real signatures, since the functions return Boxed futures.
Modals
Since version 0.8.0, the framework provides a derive macro to make modals as easy as possible. Let's take a look at an example:
use *;
async
Here the ´Modal´ derive macro derives the modal trait which allows us to create them, then we can modify how it will be
shown to the user using the #[modal(..)} attributes. To see the full list of allowed attributes, take a look at the
macro declaration.
Currently, only String and Option<String> fields are allowed.
Bulk Commands Overwrite
If you'd like to use Discord's Bulk Overwrite Global Application Commands enpoint, perhaps in tandem with a commands lockfile, you'll want to use Framework#twilight_commands.
Note This requires the
bulkfeature.