Slash commands example: parse options into a map (#1129)

* implement code resolutions

removes parseMap from the API and requires user inclusion

* optimize map initialization

* add note for parseOptionsToMap capacity

* feat(examples/slash_commands): removed parseOptionsToMap

* feat(examples/slash_commands): cosmetic changes

* fix(examples/slash_commands): typo

* fix(examples/slash_commands): another typo

Co-authored-by: nitroflap <fe.lap.prog@gmail.com>
This commit is contained in:
SwitchUpCB 2022-04-04 11:20:02 -05:00 committed by GitHub
parent 7e3d187823
commit 0c27cedbcb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -158,14 +158,14 @@ var (
// will cause the registration of the command to fail // will cause the registration of the command to fail
{ {
Name: "scmd-grp", Name: "subcommand-group",
Description: "Subcommands group", Description: "Subcommands group",
Options: []*discordgo.ApplicationCommandOption{ Options: []*discordgo.ApplicationCommandOption{
// Also, subcommand groups aren't capable of // Also, subcommand groups aren't capable of
// containing options, by the name of them, you can see // containing options, by the name of them, you can see
// they can only contain subcommands // they can only contain subcommands
{ {
Name: "nst-subcmd", Name: "nested-subcommand",
Description: "Nested subcommand", Description: "Nested subcommand",
Type: discordgo.ApplicationCommandOptionSubCommand, Type: discordgo.ApplicationCommandOptionSubCommand,
}, },
@ -178,7 +178,7 @@ var (
// Read the intro of slash-commands docs on Discord dev portal // Read the intro of slash-commands docs on Discord dev portal
// to get more information // to get more information
{ {
Name: "subcmd", Name: "subcommand",
Description: "Top-level subcommand", Description: "Top-level subcommand",
Type: discordgo.ApplicationCommandOptionSubCommand, Type: discordgo.ApplicationCommandOptionSubCommand,
}, },
@ -211,6 +211,7 @@ var (
Description: "Followup messages", Description: "Followup messages",
}, },
} }
commandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){ commandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){
"basic-command": func(s *discordgo.Session, i *discordgo.InteractionCreate) { "basic-command": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
@ -254,37 +255,62 @@ var (
} }
}, },
"options": func(s *discordgo.Session, i *discordgo.InteractionCreate) { "options": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
margs := []interface{}{ // Access options in the order provided by the user.
// Here we need to convert raw interface{} value to wanted type. options := i.ApplicationCommandData().Options
// Also, as you can see, here is used utility functions to convert the value
// to particular type. Yeah, you can use just switch type, // Or convert the slice into a map
// but this is much simpler optionMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(options))
i.ApplicationCommandData().Options[0].StringValue(), for _, opt := range options {
i.ApplicationCommandData().Options[1].IntValue(), optionMap[opt.Name] = opt
i.ApplicationCommandData().Options[2].FloatValue(),
i.ApplicationCommandData().Options[3].BoolValue(),
} }
msgformat :=
` Now you just learned how to use command options. Take a look to the value of which you've just entered: // This example stores the provided arguments in an []interface{}
> string_option: %s // which will be used to format the bot's response
> integer_option: %d margs := make([]interface{}, 0, len(options))
> number_option: %f msgformat := "You learned how to use command options! " +
> bool_option: %v "Take a look at the value(s) you entered:\n"
`
if len(i.ApplicationCommandData().Options) >= 5 { // Get the value from the option map.
margs = append(margs, i.ApplicationCommandData().Options[4].ChannelValue(nil).ID) // When the option exists, ok = true
if option, ok := optionMap["string-option"]; ok {
// Option values must be type asserted from interface{}.
// Discordgo provides utility functions to make this simple.
margs = append(margs, option.StringValue())
msgformat += "> string-option: %s\n"
}
if opt, ok := optionMap["integer-option"]; ok {
margs = append(margs, opt.IntValue())
msgformat += "> integer-option: %d\n"
}
if opt, ok := optionMap["number-option"]; ok {
margs = append(margs, opt.FloatValue())
msgformat += "> number-option: %f\n"
}
if opt, ok := optionMap["bool-option"]; ok {
margs = append(margs, opt.BoolValue())
msgformat += "> bool-option: %v\n"
}
if opt, ok := optionMap["channel-option"]; ok {
margs = append(margs, opt.ChannelValue(nil).ID)
msgformat += "> channel-option: <#%s>\n" msgformat += "> channel-option: <#%s>\n"
} }
if len(i.ApplicationCommandData().Options) >= 6 {
margs = append(margs, i.ApplicationCommandData().Options[5].UserValue(nil).ID) if opt, ok := optionMap["user-option"]; ok {
margs = append(margs, opt.UserValue(nil).ID)
msgformat += "> user-option: <@%s>\n" msgformat += "> user-option: <@%s>\n"
} }
if len(i.ApplicationCommandData().Options) >= 7 {
margs = append(margs, i.ApplicationCommandData().Options[6].RoleValue(nil, "").ID) if opt, ok := optionMap["role-option"]; ok {
margs = append(margs, opt.RoleValue(nil, "").ID)
msgformat += "> role-option: <@&%s>\n" msgformat += "> role-option: <@&%s>\n"
} }
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
// Ignore type for now, we'll discuss them in "responses" part // Ignore type for now, they will be discussed in "responses"
Type: discordgo.InteractionResponseChannelMessageWithSource, Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{ Data: &discordgo.InteractionResponseData{
Content: fmt.Sprintf( Content: fmt.Sprintf(
@ -295,27 +321,25 @@ var (
}) })
}, },
"subcommands": func(s *discordgo.Session, i *discordgo.InteractionCreate) { "subcommands": func(s *discordgo.Session, i *discordgo.InteractionCreate) {
options := i.ApplicationCommandData().Options
content := "" content := ""
// As you can see, the name of subcommand (nested, top-level) or subcommand group // As you can see, names of subcommands (nested, top-level)
// is provided through arguments. // and subcommand groups are provided through the arguments.
switch i.ApplicationCommandData().Options[0].Name { switch options[0].Name {
case "subcmd": case "subcommand":
content = content = "The top-level subcommand is executed. Now try to execute the nested one."
"The top-level subcommand is executed. Now try to execute the nested one." case "subcommand-group":
default: options = options[0].Options
if i.ApplicationCommandData().Options[0].Name != "scmd-grp" { switch options[0].Name {
return case "nested-subcommand":
}
switch i.ApplicationCommandData().Options[0].Options[0].Name {
case "nst-subcmd":
content = "Nice, now you know how to execute nested commands too" content = "Nice, now you know how to execute nested commands too"
default: default:
// I added this in the case something might go wrong content = "Oops, something went wrong.\n" +
content = "Oops, something gone wrong.\n" +
"Hol' up, you aren't supposed to see this message." "Hol' up, you aren't supposed to see this message."
} }
} }
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource, Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{ Data: &discordgo.InteractionResponseData{
@ -476,5 +500,5 @@ func main() {
} }
} }
log.Println("Gracefully shutdowning") log.Println("Gracefully shutting down.")
} }