mirror of
https://github.com/diamondburned/arikawa.git
synced 2025-07-13 00:35:36 +00:00
Bot: Added Usager, improved help
This commit is contained in:
parent
be12849668
commit
3ee307b788
|
@ -17,6 +17,12 @@ type Parser interface {
|
||||||
Parse(string) error
|
Parse(string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Usager is used in place of the automatically parsed struct name for Parser
|
||||||
|
// and other interfaces.
|
||||||
|
type Usager interface {
|
||||||
|
Usage() string
|
||||||
|
}
|
||||||
|
|
||||||
// ManualParser has a ParseContent(string) method. If the library sees
|
// ManualParser has a ParseContent(string) method. If the library sees
|
||||||
// this for an argument, it will send all of the arguments (including the
|
// this for an argument, it will send all of the arguments (including the
|
||||||
// command) into the method. If used, this should be the only argument followed
|
// command) into the method. If used, this should be the only argument followed
|
||||||
|
@ -145,7 +151,7 @@ func getArgumentValueFn(t reflect.Type) (*Argument, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Argument{
|
return &Argument{
|
||||||
String: t.String(),
|
String: fromUsager(typeI),
|
||||||
Type: typeI,
|
Type: typeI,
|
||||||
pointer: ptr,
|
pointer: ptr,
|
||||||
fn: avfn,
|
fn: avfn,
|
||||||
|
@ -219,3 +225,16 @@ func quickRet(v interface{}, err error, t reflect.Type) (reflect.Value, error) {
|
||||||
|
|
||||||
return rv.Convert(t), nil
|
return rv.Convert(t), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fromUsager(typeI reflect.Type) string {
|
||||||
|
if typeI.Implements(typeIUsager) {
|
||||||
|
mt, ok := typeI.MethodByName("Usage")
|
||||||
|
if !ok {
|
||||||
|
panic("BUG: type IUsager does not implement Usage")
|
||||||
|
}
|
||||||
|
vs := mt.Func.Call([]reflect.Value{reflect.New(typeI.Elem())})
|
||||||
|
return vs[0].String()
|
||||||
|
}
|
||||||
|
s := strings.Split(typeI.String(), ".")
|
||||||
|
return s[len(s)-1]
|
||||||
|
}
|
||||||
|
|
31
bot/ctx.go
31
bot/ctx.go
|
@ -361,38 +361,27 @@ func (ctx *Context) help(hideAdmin bool) string {
|
||||||
help.WriteString("\n---\n")
|
help.WriteString("\n---\n")
|
||||||
|
|
||||||
// Generate all commands
|
// Generate all commands
|
||||||
help.WriteString("__Commands__\n")
|
help.WriteString("__Commands__")
|
||||||
|
help.WriteString(ctx.Subcommand.Help(indent, hideAdmin))
|
||||||
for _, cmd := range ctx.Commands {
|
help.WriteByte('\n')
|
||||||
if cmd.Flag.Is(AdminOnly) && hideAdmin {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
help.WriteString(indent + cmd.Command)
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case len(cmd.Usage()) > 0:
|
|
||||||
help.WriteString(" " + strings.Join(cmd.Usage(), " "))
|
|
||||||
case cmd.Description != "":
|
|
||||||
help.WriteString(": " + cmd.Description)
|
|
||||||
}
|
|
||||||
|
|
||||||
help.WriteByte('\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
var subHelp = strings.Builder{}
|
var subHelp = strings.Builder{}
|
||||||
var subcommands = ctx.Subcommands()
|
var subcommands = ctx.Subcommands()
|
||||||
|
|
||||||
for _, sub := range subcommands {
|
for _, sub := range subcommands {
|
||||||
if help := sub.Help(indent, hideAdmin); help != "" {
|
if help := sub.Help(indent, hideAdmin); help != "" {
|
||||||
subHelp.WriteString(help)
|
for _, line := range strings.Split(help, "\n") {
|
||||||
|
subHelp.WriteString(indent)
|
||||||
|
subHelp.WriteString(line)
|
||||||
|
subHelp.WriteByte('\n')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sub := subHelp.String(); sub != "" {
|
if subHelp.Len() > 0 {
|
||||||
help.WriteString("---\n")
|
help.WriteString("---\n")
|
||||||
help.WriteString("__Subcommands__\n")
|
help.WriteString("__Subcommands__\n")
|
||||||
help.WriteString(sub)
|
help.WriteString(subHelp.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return help.String()
|
return help.String()
|
||||||
|
|
|
@ -55,6 +55,10 @@ func (e Emoji) URL() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Emoji) Usage() string {
|
||||||
|
return "emoji"
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Emoji) Parse(arg string) error {
|
func (e *Emoji) Parse(arg string) error {
|
||||||
// Check if Unicode emoji
|
// Check if Unicode emoji
|
||||||
if rate.StringIsEmojiOnly(arg) {
|
if rate.StringIsEmojiOnly(arg) {
|
||||||
|
|
62
bot/extras/arguments/link.go
Normal file
62
bot/extras/arguments/link.go
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package arguments
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/diamondburned/arikawa/discord"
|
||||||
|
)
|
||||||
|
|
||||||
|
// (empty) so it matches standard links
|
||||||
|
// | OR
|
||||||
|
// canary. matches canary MessageURL
|
||||||
|
// 3 `(\d+)` for guild ID, channel ID and message ID
|
||||||
|
var Regex = regexp.MustCompile(
|
||||||
|
`https://(|ptb\.|canary\.)discordapp\.com/channels/(\d+)/(\d+)/(\d+)`,
|
||||||
|
)
|
||||||
|
|
||||||
|
// MessageURL contains info from a MessageURL
|
||||||
|
type MessageURL struct {
|
||||||
|
GuildID discord.Snowflake
|
||||||
|
ChannelID discord.Snowflake
|
||||||
|
MessageID discord.Snowflake
|
||||||
|
}
|
||||||
|
|
||||||
|
func (url *MessageURL) Parse(arg string) error {
|
||||||
|
u := ParseMessageURL(arg)
|
||||||
|
if u == nil {
|
||||||
|
return errors.New("Invalid MessageURL format.")
|
||||||
|
}
|
||||||
|
*url = *u
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (url *MessageURL) Usage() string {
|
||||||
|
return "https\u200b://discordapp.com/channels/\\*/\\*/\\*"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseMessageURL parses the MessageURL into a smartlink
|
||||||
|
func ParseMessageURL(url string) *MessageURL {
|
||||||
|
ss := Regex.FindAllStringSubmatch(url, -1)
|
||||||
|
if ss == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ss) == 0 || len(ss[0]) != 5 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
gID, err1 := discord.ParseSnowflake(ss[0][2])
|
||||||
|
cID, err2 := discord.ParseSnowflake(ss[0][3])
|
||||||
|
mID, err3 := discord.ParseSnowflake(ss[0][4])
|
||||||
|
|
||||||
|
if err1 != nil || err2 != nil || err3 != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &MessageURL{
|
||||||
|
GuildID: gID,
|
||||||
|
ChannelID: cID,
|
||||||
|
MessageID: mID,
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,8 +18,7 @@ var (
|
||||||
type ChannelMention discord.Snowflake
|
type ChannelMention discord.Snowflake
|
||||||
|
|
||||||
func (m *ChannelMention) Parse(arg string) error {
|
func (m *ChannelMention) Parse(arg string) error {
|
||||||
return grabFirst(ChannelRegex, "channel mention",
|
return grabFirst(ChannelRegex, "channel mention", arg, (*discord.Snowflake)(m))
|
||||||
arg, (*discord.Snowflake)(m))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ChannelMention) Usage() string {
|
func (m *ChannelMention) Usage() string {
|
||||||
|
@ -39,8 +38,7 @@ func (m *ChannelMention) Mention() string {
|
||||||
type UserMention discord.Snowflake
|
type UserMention discord.Snowflake
|
||||||
|
|
||||||
func (m *UserMention) Parse(arg string) error {
|
func (m *UserMention) Parse(arg string) error {
|
||||||
return grabFirst(UserRegex, "user mention",
|
return grabFirst(UserRegex, "user mention", arg, (*discord.Snowflake)(m))
|
||||||
arg, (*discord.Snowflake)(m))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *UserMention) Usage() string {
|
func (m *UserMention) Usage() string {
|
||||||
|
@ -60,8 +58,7 @@ func (m *UserMention) Mention() string {
|
||||||
type RoleMention discord.Snowflake
|
type RoleMention discord.Snowflake
|
||||||
|
|
||||||
func (m *RoleMention) Parse(arg string) error {
|
func (m *RoleMention) Parse(arg string) error {
|
||||||
return grabFirst(RoleRegex, "role mention",
|
return grabFirst(RoleRegex, "role mention", arg, (*discord.Snowflake)(m))
|
||||||
arg, (*discord.Snowflake)(m))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *RoleMention) Usage() string {
|
func (m *RoleMention) Usage() string {
|
||||||
|
@ -78,9 +75,7 @@ func (m *RoleMention) Mention() string {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
func grabFirst(reg *regexp.Regexp,
|
func grabFirst(reg *regexp.Regexp, item, input string, output *discord.Snowflake) error {
|
||||||
item, input string, output *discord.Snowflake) error {
|
|
||||||
|
|
||||||
matches := reg.FindStringSubmatch(input)
|
matches := reg.FindStringSubmatch(input)
|
||||||
if len(matches) < 2 {
|
if len(matches) < 2 {
|
||||||
return errors.New("Invalid " + item)
|
return errors.New("Invalid " + item)
|
||||||
|
|
|
@ -23,6 +23,7 @@ var (
|
||||||
typeIManP = reflect.TypeOf((*ManualParser)(nil)).Elem()
|
typeIManP = reflect.TypeOf((*ManualParser)(nil)).Elem()
|
||||||
typeICusP = reflect.TypeOf((*CustomParser)(nil)).Elem()
|
typeICusP = reflect.TypeOf((*CustomParser)(nil)).Elem()
|
||||||
typeIParser = reflect.TypeOf((*Parser)(nil)).Elem()
|
typeIParser = reflect.TypeOf((*Parser)(nil)).Elem()
|
||||||
|
typeIUsager = reflect.TypeOf((*Usager)(nil)).Elem()
|
||||||
typeSetupFn = func() reflect.Type {
|
typeSetupFn = func() reflect.Type {
|
||||||
method, _ := reflect.TypeOf((*CanSetup)(nil)).
|
method, _ := reflect.TypeOf((*CanSetup)(nil)).
|
||||||
Elem().
|
Elem().
|
||||||
|
@ -182,14 +183,12 @@ func (sub *Subcommand) Help(indent string, hideAdmin bool) string {
|
||||||
var header string
|
var header string
|
||||||
|
|
||||||
if sub.Command != "" {
|
if sub.Command != "" {
|
||||||
header += indent + sub.Command
|
header += sub.Command
|
||||||
}
|
}
|
||||||
|
|
||||||
if sub.Description != "" {
|
if sub.Description != "" {
|
||||||
if header != "" {
|
if header != "" {
|
||||||
header += ": "
|
header += ": "
|
||||||
} else {
|
|
||||||
header += indent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
header += sub.Description
|
header += sub.Description
|
||||||
|
@ -200,21 +199,27 @@ func (sub *Subcommand) Help(indent string, hideAdmin bool) string {
|
||||||
// The commands part:
|
// The commands part:
|
||||||
var commands = ""
|
var commands = ""
|
||||||
|
|
||||||
for _, cmd := range sub.Commands {
|
for i, cmd := range sub.Commands {
|
||||||
if cmd.Flag.Is(AdminOnly) && hideAdmin {
|
if cmd.Flag.Is(AdminOnly) && hideAdmin {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
commands += indent + indent + sub.Command + " " + cmd.Command
|
if sub.Command != "" {
|
||||||
|
commands += indent + sub.Command + " " + cmd.Command
|
||||||
|
} else {
|
||||||
|
commands += indent + cmd.Command
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case len(cmd.Usage()) > 0:
|
case len(cmd.Usage()) > 0:
|
||||||
commands += " " + strings.Join(cmd.Usage(), " ")
|
commands += " **" + strings.Join(cmd.Usage(), " ") + "**"
|
||||||
case cmd.Description != "":
|
case cmd.Description != "":
|
||||||
commands += ": " + cmd.Description
|
commands += ": " + cmd.Description
|
||||||
}
|
}
|
||||||
|
|
||||||
commands += "\n"
|
if i != len(sub.Commands)-1 {
|
||||||
|
commands += "\n"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if commands == "" {
|
if commands == "" {
|
||||||
|
|
|
@ -148,9 +148,7 @@ func (s *State) MemberColor(guildID, userID discord.Snowflake) discord.Color {
|
||||||
|
|
||||||
////
|
////
|
||||||
|
|
||||||
func (s *State) Permissions(
|
func (s *State) Permissions(channelID, userID discord.Snowflake) (discord.Permissions, error) {
|
||||||
channelID, userID discord.Snowflake) (discord.Permissions, error) {
|
|
||||||
|
|
||||||
ch, err := s.Channel(channelID)
|
ch, err := s.Channel(channelID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.Wrap(err, "Failed to get channel")
|
return 0, errors.Wrap(err, "Failed to get channel")
|
||||||
|
|
Loading…
Reference in a new issue