mirror of
https://github.com/diamondburned/arikawa.git
synced 2025-07-23 13:20:51 +00:00
Compare commits
5 commits
4992f4ab20
...
de7d7f62a4
Author | SHA1 | Date | |
---|---|---|---|
|
de7d7f62a4 | ||
|
42724e0b91 | ||
|
af63bb2e66 | ||
|
ee9d6b0d4d | ||
|
0932e2903b |
|
@ -70,10 +70,9 @@ func (r ArgumentParts) Usage() string {
|
|||
}
|
||||
|
||||
// CustomParser has a CustomParse method, which would be passed in the full
|
||||
// message content with the prefix and command trimmed. This is used
|
||||
// for commands that require more advanced parsing than the default parser.
|
||||
//
|
||||
// Keep in mind that this does not trim arguments before it.
|
||||
// message content with the prefix, command, subcommand and space trimmed. This
|
||||
// is used for commands that require more advanced parsing than the default
|
||||
// parser.
|
||||
type CustomParser interface {
|
||||
CustomParse(arguments string) error
|
||||
}
|
||||
|
@ -101,8 +100,9 @@ type Argument struct {
|
|||
|
||||
// if nil, then manual
|
||||
fn argumentValueFn
|
||||
manual *reflect.Method
|
||||
custom *reflect.Method
|
||||
|
||||
manual func(ManualParser, []string) error
|
||||
custom func(CustomParser, string) error
|
||||
}
|
||||
|
||||
func (a *Argument) Type() reflect.Type {
|
||||
|
@ -132,9 +132,6 @@ func newArgument(t reflect.Type, variadic bool) (*Argument, error) {
|
|||
|
||||
// This shouldn't be variadic.
|
||||
if !variadic && typeI.Implements(typeICusP) {
|
||||
mt, _ := typeI.MethodByName("CustomParse")
|
||||
|
||||
// TODO: maybe ish?
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
@ -143,14 +140,12 @@ func newArgument(t reflect.Type, variadic bool) (*Argument, error) {
|
|||
String: fromUsager(t),
|
||||
rtype: t,
|
||||
pointer: ptr,
|
||||
custom: &mt,
|
||||
custom: CustomParser.CustomParse,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// This shouldn't be variadic either.
|
||||
if !variadic && typeI.Implements(typeIManP) {
|
||||
mt, _ := typeI.MethodByName("ParseContent")
|
||||
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
@ -159,7 +154,7 @@ func newArgument(t reflect.Type, variadic bool) (*Argument, error) {
|
|||
String: fromUsager(t),
|
||||
rtype: t,
|
||||
pointer: ptr,
|
||||
manual: &mt,
|
||||
manual: ManualParser.ParseContent,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ func (ctx *Context) callMessageCreate(mc *gateway.MessageCreateEvent, value refl
|
|||
// If the argument wants all arguments:
|
||||
case last.manual != nil:
|
||||
// Call the manual parse method:
|
||||
_, err = callWith(last.manual.Func, v, reflect.ValueOf(arguments))
|
||||
err = last.manual(v.Interface().(ManualParser), arguments)
|
||||
|
||||
// If the argument wants all arguments in string:
|
||||
case last.custom != nil:
|
||||
|
@ -261,32 +261,14 @@ func (ctx *Context) callMessageCreate(mc *gateway.MessageCreateEvent, value refl
|
|||
// have erroneous hanging quotes.
|
||||
parseErr = nil
|
||||
|
||||
// Manual string seeking is a must here. This is because the string
|
||||
// could contain multiple whitespaces, and the parser would not
|
||||
// count them.
|
||||
var seekTo = cmd.Command
|
||||
// We can't rely on the plumbing behavior.
|
||||
if sub.plumbed != nil {
|
||||
seekTo = sub.Command
|
||||
}
|
||||
content = trimPrefixStringAndSlice(content, sub.Command, sub.Aliases)
|
||||
|
||||
// Seek to the string.
|
||||
var i = strings.Index(content, seekTo)
|
||||
// Edge case if the subcommand is the same as the command.
|
||||
if cmd.Command == sub.Command {
|
||||
// Seek again past the command.
|
||||
i = strings.Index(content[i+len(seekTo):], seekTo)
|
||||
}
|
||||
|
||||
if i > -1 {
|
||||
// Seek past the substring.
|
||||
i += len(seekTo)
|
||||
|
||||
content = strings.TrimSpace(content[i:])
|
||||
if !sub.IsPlumbed() && cmd.Command != "" {
|
||||
content = trimPrefixStringAndSlice(content, cmd.Command, cmd.Aliases)
|
||||
}
|
||||
|
||||
// Call the method with the raw unparsed command:
|
||||
_, err = callWith(last.custom.Func, v, reflect.ValueOf(content))
|
||||
err = last.custom(v.Interface().(CustomParser), content)
|
||||
}
|
||||
|
||||
// Check the returned error:
|
||||
|
@ -367,20 +349,14 @@ func (ctx *Context) findCommand(parts []string) ([]string, *MethodContext, *Subc
|
|||
return nil, nil, nil, Break
|
||||
}
|
||||
|
||||
return nil, nil, nil, &ErrUnknownCommand{
|
||||
Parts: parts,
|
||||
Subcmd: s,
|
||||
}
|
||||
return nil, nil, nil, newErrUnknownCommand(s, parts)
|
||||
}
|
||||
|
||||
if ctx.SilentUnknown.Command {
|
||||
return nil, nil, nil, Break
|
||||
}
|
||||
|
||||
return nil, nil, nil, &ErrUnknownCommand{
|
||||
Parts: parts,
|
||||
Subcmd: ctx.Subcommand,
|
||||
}
|
||||
return nil, nil, nil, newErrUnknownCommand(ctx.Subcommand, parts)
|
||||
}
|
||||
|
||||
// searchStringAndSlice searches if str is equal to isString or any of the given
|
||||
|
@ -399,6 +375,22 @@ func searchStringAndSlice(str string, isString string, otherStrings []string) bo
|
|||
return false
|
||||
}
|
||||
|
||||
// trimPrefixStringAndSlice behaves similarly to searchStringAndSlice, but it
|
||||
// trims the prefix and the surrounding spaces after a match.
|
||||
func trimPrefixStringAndSlice(str string, prefix string, prefixes []string) string {
|
||||
if strings.HasPrefix(str, prefix) {
|
||||
return strings.TrimSpace(str[len(prefix):])
|
||||
}
|
||||
|
||||
for _, prefix := range prefixes {
|
||||
if strings.HasPrefix(str, prefix) {
|
||||
return strings.TrimSpace(str[len(prefix):])
|
||||
}
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
func errNoBreak(err error) error {
|
||||
if errors.Is(err, Break) {
|
||||
return nil
|
||||
|
|
22
bot/error.go
22
bot/error.go
|
@ -2,6 +2,7 @@ package bot
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -10,15 +11,28 @@ type ErrUnknownCommand struct {
|
|||
Subcmd *Subcommand
|
||||
}
|
||||
|
||||
func (err *ErrUnknownCommand) Error() string {
|
||||
if len(err.Parts) > 2 {
|
||||
err.Parts = err.Parts[:2]
|
||||
func newErrUnknownCommand(s *Subcommand, parts []string) error {
|
||||
if len(parts) > 2 {
|
||||
parts = parts[:2]
|
||||
}
|
||||
|
||||
return &ErrUnknownCommand{
|
||||
Parts: parts,
|
||||
Subcmd: s,
|
||||
}
|
||||
}
|
||||
|
||||
func (err *ErrUnknownCommand) Error() string {
|
||||
return UnknownCommandString(err)
|
||||
}
|
||||
|
||||
var UnknownCommandString = func(err *ErrUnknownCommand) string {
|
||||
return "unknown command: " + strings.Join(err.Parts, " ")
|
||||
// Subcommand check.
|
||||
if err.Subcmd.StructName == "" || len(err.Parts) < 2 {
|
||||
return "unknown command: " + err.Parts[0] + "."
|
||||
}
|
||||
|
||||
return fmt.Sprintf("unknown %s subcommand: %s.", err.Parts[0], err.Parts[1])
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
@ -110,6 +110,7 @@ type SpeakingData struct {
|
|||
Speaking SpeakingFlag `json:"speaking"`
|
||||
Delay int `json:"delay"`
|
||||
SSRC uint32 `json:"ssrc"`
|
||||
UserID discord.UserID `json:"user_id,omitempty"`
|
||||
}
|
||||
|
||||
// Speaking sends a Speaking operation (opcode 5) to the Gateway Gateway.
|
||||
|
|
Loading…
Reference in a new issue