Rewrite message command methods to use entities

Since the Telegram-API considers "/foo-bar" to be a command entity
"/foo", we had choose a behaviour for the
CommandArguments() method.
The specification (https://core.telegram.org/bots#commands) mandates a
space after the command name, so we decided to skip the first character
following the command entity.
However, Telegram clients render "/foo-bar" as if "/foo" was the command
and "-bar" additional text, so this alternative should be remembered.
pull/125/head
Henner 8 years ago
parent 9dda67c714
commit 5f5f94047c
  1. 50
      types.go

@ -173,21 +173,23 @@ func (m *Message) Time() time.Time {
return time.Unix(int64(m.Date), 0) return time.Unix(int64(m.Date), 0)
} }
// IsCommand returns true if message starts with '/'. // IsCommand returns true if message starts with a "bot_command" entity.
func (m *Message) IsCommand() bool { func (m *Message) IsCommand() bool {
return m.Text != "" && m.Text[0] == '/' if m.Entities == nil || len(*m.Entities) == 0 {
return false
}
entity := (*m.Entities)[0]
return entity.Offset == 0 && entity.Type == "bot_command"
} }
// Command checks if the message was a command and if it was, returns the // Command checks if the message was a command and if it was, returns the
// command. If the Message was not a command, it returns an empty string. // command. If the Message was not a command, it returns an empty string.
// //
// If the command contains the at bot syntax, it removes the bot name. // If the command contains the at name syntax, it is removed. Use
// CommandWithAt() if you do not want that.
func (m *Message) Command() string { func (m *Message) Command() string {
if !m.IsCommand() { command := m.CommandWithAt()
return ""
}
command := strings.SplitN(m.Text, " ", 2)[0][1:]
if i := strings.Index(command, "@"); i != -1 { if i := strings.Index(command, "@"); i != -1 {
command = command[:i] command = command[:i]
@ -196,20 +198,42 @@ func (m *Message) Command() string {
return command return command
} }
// CommandWithAt checks if the message was a command and if it was, returns the
// command. If the Message was not a command, it returns an empty string.
//
// If the command contains the at name syntax, it is not removed. Use Command()
// if you want that.
func (m *Message) CommandWithAt() string {
if !m.IsCommand() {
return ""
}
// IsCommand() checks that the message begins with a bot_command entity
entity := (*m.Entities)[0]
return m.Text[1:entity.Length]
}
// CommandArguments checks if the message was a command and if it was, // CommandArguments checks if the message was a command and if it was,
// returns all text after the command name. If the Message was not a // returns all text after the command name. If the Message was not a
// command, it returns an empty string. // command, it returns an empty string.
//
// Note: The first character after the command name is omitted:
// - "/foo bar baz" yields "bar baz", not " bar baz"
// - "/foo-bar baz" yields "bar baz", too
// Even though the latter is not a command conforming to the spec, the API
// marks "/foo" as command entity.
func (m *Message) CommandArguments() string { func (m *Message) CommandArguments() string {
if !m.IsCommand() { if !m.IsCommand() {
return "" return ""
} }
split := strings.SplitN(m.Text, " ", 2) // IsCommand() checks that the message begins with a bot_command entity
if len(split) != 2 { entity := (*m.Entities)[0]
return "" if len(m.Text) == entity.Length {
return "" // The command makes up the whole message
} else {
return m.Text[entity.Length+1:]
} }
return split[1]
} }
// MessageEntity contains information about data in a Message. // MessageEntity contains information about data in a Message.