Skip to content

Commit

Permalink
add slash command subcommands (no subcommand groups)
Browse files Browse the repository at this point in the history
  • Loading branch information
starshine-sys committed Sep 19, 2021
1 parent 7b7c8d4 commit bd860c0
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 3 deletions.
2 changes: 2 additions & 0 deletions bcr.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ type Router struct {
cmds map[string]*Command
cmdMu sync.RWMutex

slashGroups []*Group

// maps + mutexes
reactions map[reactionKey]reactionInfo
reactionMu sync.RWMutex
Expand Down
2 changes: 1 addition & 1 deletion ctx_args_slash.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type SlashCommandOption struct {

// Option returns an option by name, or an empty option if it's not found.
func (ctx *SlashContext) Option(name string) (option SlashCommandOption) {
for _, o := range ctx.Event.Data.Options {
for _, o := range ctx.CommandOptions {
if strings.EqualFold(o.Name, name) {
return SlashCommandOption{
ctx: ctx,
Expand Down
26 changes: 24 additions & 2 deletions execute_slash.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (r *Router) InteractionCreate(ic *gateway.InteractionCreateEvent) {

// ExecuteSlash executes slash commands. Only one layer for now, so no subcommands, sorry :(
func (r *Router) ExecuteSlash(ctx *SlashContext) (err error) {
err = r.executeSlash(ctx, r.cmds, &r.cmdMu)
err = r.executeSlash(true, ctx, r.cmds, &r.cmdMu)
if err == errCommandRun {
return nil
}
Expand All @@ -43,7 +43,29 @@ func errCommand(err error) error {
return err
}

func (r *Router) executeSlash(ctx *SlashContext, cmds map[string]*Command, mu *sync.RWMutex) (err error) {
func (r *Router) executeSlash(isTopLevel bool, ctx *SlashContext, cmds map[string]*Command, mu *sync.RWMutex) (err error) {
// first, check subcommands
if len(ctx.CommandOptions) > 0 && isTopLevel {
for _, g := range r.slashGroups {
if strings.EqualFold(g.Name, ctx.CommandName) {
nctx := &SlashContext{}
*nctx = *ctx
nctx.CommandName = ctx.CommandOptions[0].Name
nctx.CommandOptions = ctx.CommandOptions[0].Options

// convert subcommands slice to a map
m := map[string]*Command{}
for _, cmd := range g.Subcommands {
m[strings.ToLower(cmd.Name)] = cmd
}
var nmu sync.RWMutex // this doesn't matter so we just create a new one

return r.executeSlash(false, nctx, m, &nmu)
}
}
}

// else, we try top-level commands (or skip to this immediately if it isn't the top level)
mu.RLock()
cmd, ok := cmds[ctx.CommandName]
if !ok || cmd.SlashCommand == nil {
Expand Down
65 changes: 65 additions & 0 deletions group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package bcr

import (
"strings"

"github.com/diamondburned/arikawa/v3/discord"
)

// Group is used for creating slash subcommands.
// No, we can't use the normal system,
// because a command with subcommands can't *itself* be invoked as a command.
// Also, no subcommand groups because those make everything more complicated
// and shouldn't be needed at this scale. Might change in the future, who knows!
type Group struct {
Name string
Description string
Subcommands []*Command
}

// Add adds a subcommand to the group.
func (g *Group) Add(cmd *Command) *Group {
g.Subcommands = append(g.Subcommands, cmd)
return g
}

// Command returns the group as a discord.Command.
func (g Group) Command() discord.Command {
c := discord.Command{
Name: strings.ToLower(g.Name),
Description: g.Description,
}

for _, cmd := range g.Subcommands {
if cmd.SlashCommand == nil {
continue
}

options := []discord.CommandOption(nil)
if cmd.Options != nil {
options = *cmd.Options
}

c.Options = append(c.Options, discord.CommandOption{
Type: discord.SubcommandOption,
Name: strings.ToLower(cmd.Name),
Description: cmd.Summary,
Options: options,
})
}

return c
}

// AddGroup adds a slash command group. Will panic if the group's name already exists as a slash command!
func (r *Router) AddGroup(g *Group) {
r.cmdMu.RLock()
defer r.cmdMu.RUnlock()
for _, cmd := range r.cmds {
if strings.EqualFold(cmd.Name, g.Name) && cmd.Options != nil && cmd.SlashCommand != nil {
panic("slash command with name " + g.Name + "already exists!")
}
}

r.slashGroups = append(r.slashGroups, g)
}
3 changes: 3 additions & 0 deletions slash.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ func (r *Router) SyncCommands(guildIDs ...discord.GuildID) (err error) {
Options: *cmd.Options,
})
}
for _, g := range r.slashGroups {
slashCmds = append(slashCmds, g.Command())
}

if len(guildIDs) > 0 {
return r.syncCommandsIn(slashCmds, guildIDs)
Expand Down

0 comments on commit bd860c0

Please sign in to comment.