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  }