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
|
// CustomParser has a CustomParse method, which would be passed in the full
|
||||||
// message content with the prefix and command trimmed. This is used
|
// message content with the prefix, command, subcommand and space trimmed. This
|
||||||
// for commands that require more advanced parsing than the default parser.
|
// is used for commands that require more advanced parsing than the default
|
||||||
//
|
// parser.
|
||||||
// Keep in mind that this does not trim arguments before it.
|
|
||||||
type CustomParser interface {
|
type CustomParser interface {
|
||||||
CustomParse(arguments string) error
|
CustomParse(arguments string) error
|
||||||
}
|
}
|
||||||
|
@ -100,9 +99,10 @@ type Argument struct {
|
||||||
pointer bool
|
pointer bool
|
||||||
|
|
||||||
// if nil, then manual
|
// if nil, then manual
|
||||||
fn argumentValueFn
|
fn argumentValueFn
|
||||||
manual *reflect.Method
|
|
||||||
custom *reflect.Method
|
manual func(ManualParser, []string) error
|
||||||
|
custom func(CustomParser, string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Argument) Type() reflect.Type {
|
func (a *Argument) Type() reflect.Type {
|
||||||
|
@ -132,9 +132,6 @@ func newArgument(t reflect.Type, variadic bool) (*Argument, error) {
|
||||||
|
|
||||||
// This shouldn't be variadic.
|
// This shouldn't be variadic.
|
||||||
if !variadic && typeI.Implements(typeICusP) {
|
if !variadic && typeI.Implements(typeICusP) {
|
||||||
mt, _ := typeI.MethodByName("CustomParse")
|
|
||||||
|
|
||||||
// TODO: maybe ish?
|
|
||||||
if t.Kind() == reflect.Ptr {
|
if t.Kind() == reflect.Ptr {
|
||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
}
|
}
|
||||||
|
@ -143,14 +140,12 @@ func newArgument(t reflect.Type, variadic bool) (*Argument, error) {
|
||||||
String: fromUsager(t),
|
String: fromUsager(t),
|
||||||
rtype: t,
|
rtype: t,
|
||||||
pointer: ptr,
|
pointer: ptr,
|
||||||
custom: &mt,
|
custom: CustomParser.CustomParse,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// This shouldn't be variadic either.
|
// This shouldn't be variadic either.
|
||||||
if !variadic && typeI.Implements(typeIManP) {
|
if !variadic && typeI.Implements(typeIManP) {
|
||||||
mt, _ := typeI.MethodByName("ParseContent")
|
|
||||||
|
|
||||||
if t.Kind() == reflect.Ptr {
|
if t.Kind() == reflect.Ptr {
|
||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
}
|
}
|
||||||
|
@ -159,7 +154,7 @@ func newArgument(t reflect.Type, variadic bool) (*Argument, error) {
|
||||||
String: fromUsager(t),
|
String: fromUsager(t),
|
||||||
rtype: t,
|
rtype: t,
|
||||||
pointer: ptr,
|
pointer: ptr,
|
||||||
manual: &mt,
|
manual: ManualParser.ParseContent,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -253,7 +253,7 @@ func (ctx *Context) callMessageCreate(mc *gateway.MessageCreateEvent, value refl
|
||||||
// If the argument wants all arguments:
|
// If the argument wants all arguments:
|
||||||
case last.manual != nil:
|
case last.manual != nil:
|
||||||
// Call the manual parse method:
|
// 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:
|
// If the argument wants all arguments in string:
|
||||||
case last.custom != nil:
|
case last.custom != nil:
|
||||||
|
@ -261,32 +261,14 @@ func (ctx *Context) callMessageCreate(mc *gateway.MessageCreateEvent, value refl
|
||||||
// have erroneous hanging quotes.
|
// have erroneous hanging quotes.
|
||||||
parseErr = nil
|
parseErr = nil
|
||||||
|
|
||||||
// Manual string seeking is a must here. This is because the string
|
content = trimPrefixStringAndSlice(content, sub.Command, sub.Aliases)
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seek to the string.
|
if !sub.IsPlumbed() && cmd.Command != "" {
|
||||||
var i = strings.Index(content, seekTo)
|
content = trimPrefixStringAndSlice(content, cmd.Command, cmd.Aliases)
|
||||||
// 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:])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the method with the raw unparsed command:
|
// 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:
|
// 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, Break
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, nil, &ErrUnknownCommand{
|
return nil, nil, nil, newErrUnknownCommand(s, parts)
|
||||||
Parts: parts,
|
|
||||||
Subcmd: s,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.SilentUnknown.Command {
|
if ctx.SilentUnknown.Command {
|
||||||
return nil, nil, nil, Break
|
return nil, nil, nil, Break
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, nil, &ErrUnknownCommand{
|
return nil, nil, nil, newErrUnknownCommand(ctx.Subcommand, parts)
|
||||||
Parts: parts,
|
|
||||||
Subcmd: ctx.Subcommand,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// searchStringAndSlice searches if str is equal to isString or any of the given
|
// 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
|
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 {
|
func errNoBreak(err error) error {
|
||||||
if errors.Is(err, Break) {
|
if errors.Is(err, Break) {
|
||||||
return nil
|
return nil
|
||||||
|
|
22
bot/error.go
22
bot/error.go
|
@ -2,6 +2,7 @@ package bot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,15 +11,28 @@ type ErrUnknownCommand struct {
|
||||||
Subcmd *Subcommand
|
Subcmd *Subcommand
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err *ErrUnknownCommand) Error() string {
|
func newErrUnknownCommand(s *Subcommand, parts []string) error {
|
||||||
if len(err.Parts) > 2 {
|
if len(parts) > 2 {
|
||||||
err.Parts = err.Parts[:2]
|
parts = parts[:2]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return &ErrUnknownCommand{
|
||||||
|
Parts: parts,
|
||||||
|
Subcmd: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *ErrUnknownCommand) Error() string {
|
||||||
return UnknownCommandString(err)
|
return UnknownCommandString(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var UnknownCommandString = func(err *ErrUnknownCommand) string {
|
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 (
|
var (
|
||||||
|
|
|
@ -107,9 +107,10 @@ const (
|
||||||
// OPCode 5
|
// OPCode 5
|
||||||
// https://discord.com/developers/docs/topics/voice-connections#speaking-example-speaking-payload
|
// https://discord.com/developers/docs/topics/voice-connections#speaking-example-speaking-payload
|
||||||
type SpeakingData struct {
|
type SpeakingData struct {
|
||||||
Speaking SpeakingFlag `json:"speaking"`
|
Speaking SpeakingFlag `json:"speaking"`
|
||||||
Delay int `json:"delay"`
|
Delay int `json:"delay"`
|
||||||
SSRC uint32 `json:"ssrc"`
|
SSRC uint32 `json:"ssrc"`
|
||||||
|
UserID discord.UserID `json:"user_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Speaking sends a Speaking operation (opcode 5) to the Gateway Gateway.
|
// Speaking sends a Speaking operation (opcode 5) to the Gateway Gateway.
|
||||||
|
|
Loading…
Reference in a new issue