github.com/starshine-sys/bcr@v0.21.0/help.go (about) 1 package bcr 2 3 import ( 4 "flag" 5 "fmt" 6 "strings" 7 8 "github.com/diamondburned/arikawa/v3/discord" 9 "github.com/spf13/pflag" 10 "github.com/starshine-sys/snowflake/v2" 11 ) 12 13 func (ctx *Context) tryHelp() error { 14 // if there's no args return nil 15 if len(ctx.Args) == 0 { 16 return nil 17 } 18 19 // if the first argument isn't "help" or "usage" return nil 20 if strings.ToLower(ctx.Args[0]) != "help" && strings.ToLower(ctx.Args[0]) != "usage" { 21 return nil 22 } 23 24 // execute the help command 25 err := ctx.Help(ctx.FullCommandPath) 26 if err != nil { 27 return err 28 } 29 return errCommandRun 30 } 31 32 // Help sends a help embed for the command 33 func (ctx *Context) Help(path []string) (err error) { 34 // recurse into subcommands 35 cmds := ctx.Router.cmds 36 var cmd *Command 37 for i, n := range path { 38 var ok bool 39 40 // we tried recursing, but the map is nil, so the command wasn't found 41 if cmds == nil { 42 _, err = ctx.Send(fmt.Sprintf(":x: Command ``%v`` not found.", EscapeBackticks(strings.Join(path, " ")))) 43 return err 44 } 45 46 // the command name wasn't found 47 if cmd, ok = cmds[n]; !ok { 48 _, err = ctx.Send(fmt.Sprintf(":x: Command ``%v`` not found.", EscapeBackticks(strings.Join(path, " ")))) 49 return err 50 } 51 52 // we've not reached the end of the loop, so try recursing 53 if i != len(path)-1 { 54 cmds = cmd.subCmds 55 } 56 } 57 58 if cmd == nil { 59 _, err = ctx.Send(fmt.Sprintf(":x: Command ``%v`` not found.", EscapeBackticks(strings.Join(path, " ")))) 60 return err 61 } 62 63 var fs *pflag.FlagSet 64 if cmd.Flags != nil { 65 fs = cmd.Flags(pflag.NewFlagSet("", pflag.ContinueOnError)) 66 } 67 68 fields := make([]discord.EmbedField, 0) 69 70 if cmd.Description != "" { 71 fields = append(fields, discord.EmbedField{ 72 Name: "Description", 73 Value: cmd.Description, 74 }) 75 } 76 77 // get full names for path 78 var title []string 79 c := ctx.Router.GetCommand(path[0]) 80 title = append(title, c.Name) 81 if len(path) > 1 { 82 for _, p := range path[1:] { 83 c = c.GetCommand(p) 84 title = append(title, c.Name) 85 } 86 } 87 88 usage := strings.Join(title, " ") 89 flagDesc := "" 90 91 if fs != nil { 92 usage += " " 93 fs.VisitAll(func(f *pflag.Flag) { 94 s := fmt.Sprintf("-%v", f.Shorthand) 95 if f.Value.Type() != "bool" { 96 s += " " + f.Value.Type() 97 } 98 99 usage += " [" + s + "]" 100 }) 101 102 fs.VisitAll(func(f *pflag.Flag) { 103 flagDesc += fmt.Sprintf("`-%v, --%v`: %v\n", f.Shorthand, f.Name, f.Usage) 104 }) 105 106 flagDesc += "\n\nSquare brackets (`[]`) denote that an argument is **optional**.\nTo input an argument with spaces, wrap it in quotes (`\"\"`); to add quotes, escape them with a backslash (`\\`)." 107 } else if cmd.stdFlags != nil { 108 _, sfs := cmd.stdFlags(ctx, flag.NewFlagSet("", flag.ContinueOnError)) 109 110 sfs.VisitAll(func(f *flag.Flag) { 111 s := fmt.Sprintf(" [-%v]", f.Name) 112 113 usage += s 114 flagDesc += fmt.Sprintf("`-%v`: %v\n", f.Name, f.Usage) 115 }) 116 117 flagDesc += "\n\nSquare brackets (`[]`) denote that an argument is **optional**.\nTo input an argument with spaces, wrap it in quotes (`\"\"`); to add quotes, escape them with a backslash (`\\`)." 118 } 119 120 if cmd.Usage != "" { 121 usage += " " + cmd.Usage 122 } 123 124 fields = append(fields, discord.EmbedField{ 125 Name: "Usage", 126 Value: "`" + strings.TrimSpace(usage) + "`", 127 }) 128 129 if flagDesc != "" { 130 fields = append(fields, discord.EmbedField{ 131 Name: "Flags", 132 Value: flagDesc, 133 }) 134 } 135 136 if cmd.GuildPermissions != 0 || cmd.Permissions != 0 || cmd.CustomPermissions != nil { 137 s := []string{} 138 139 if cmd.GuildPermissions != 0 { 140 s = append(s, "**Server:** "+strings.Join(PermStrings(cmd.GuildPermissions), ", ")) 141 } 142 143 if cmd.Permissions != 0 { 144 s = append(s, "**Channel:** "+strings.Join(PermStrings(cmd.Permissions), ", ")) 145 } 146 147 if cmd.CustomPermissions != nil { 148 s = append(s, cmd.CustomPermissions.String()) 149 } 150 151 fields = append(fields, discord.EmbedField{ 152 Name: "Required permissions", 153 Value: strings.Join(s, "\n"), 154 }) 155 } 156 157 if len(cmd.Aliases) != 0 { 158 fields = append(fields, discord.EmbedField{ 159 Name: "Aliases", 160 Value: fmt.Sprintf("`%v`", strings.Join(cmd.Aliases, ", ")), 161 }) 162 } 163 if cmd.subCmds != nil { 164 // deduplicate subcommands 165 sf := make([]snowflake.Snowflake, 0) 166 subCmds := make([]*Command, 0) 167 for _, c := range cmd.subCmds { 168 if !snowflakeInSlice(c.id, sf) { 169 sf = append(sf, c.id) 170 subCmds = append(subCmds, c) 171 } 172 } 173 174 var b strings.Builder 175 var i int 176 for _, v := range subCmds { 177 i++ 178 // if this is the last command, add a *special* list thingy 179 if i == len(subCmds) { 180 b.WriteString("`└─ ") 181 } else { 182 b.WriteString("`├─ ") 183 } 184 b.WriteString(v.Name) 185 b.WriteString("`") 186 if i != len(subCmds) { 187 b.WriteString("\n") 188 } 189 } 190 fields = append(fields, discord.EmbedField{ 191 Name: "Subcommand(s)", 192 Value: b.String(), 193 }) 194 } 195 196 _, err = ctx.Send("", discord.Embed{ 197 Title: "`" + strings.ToUpper(strings.Join(title, " ")) + "`", 198 Description: DefaultValue(cmd.Summary, "No summary provided"), 199 Fields: fields, 200 Color: ctx.Router.EmbedColor, 201 }) 202 return err 203 }