docs: async def send_message(self, event=None):
          """
          Sends a message. Does nothing if the client is not connected.
          """
          if not self.cl.is_connected():
              return
  
          # The user needs to configure a chat where the message should be sent.
          #
          # If the chat ID does not exist, it was not valid and the user must
          # configure one; hint them by changing the background to red.
          if not self.chat_id:
              self.chat.configure(bg='red')
              self.chat.focus()
              return
  
          # Get the message, clear the text field and focus it again
          text = self.message.get().strip()
          self.message.delete(0, tkinter.END)
          self.message.focus()
          if not text:
              return
  
          # NOTE: This part is optional but supports editing messages
          #       You can remove it if you find it too complicated.
          #
          # Check if the edit matches any text
          m = EDIT.match(text)
          if m:
              find = re.compile(m.group(1).lstrip())
              # Cannot reversed(enumerate(...)), use index
              for i in reversed(range(len(self.sent_text))):
                  msg_id, msg_text = self.sent_text[i]
                  if find.search(msg_text):
                      # Found text to replace, so replace it and edit
                      new = find.sub(m.group(2), msg_text)
                      self.sent_text[i] = (msg_id, new)
                      await self.cl.edit_message(self.chat_id, msg_id, new)
  
                      # Notify that a replacement was made
                      self.log.insert(tkinter.END, '(message edited: {} -> {})\n'
                                      .format(msg_text, new))
                      self.log.yview(tkinter.END)
                      return
  
          # Check if we want to delete the message
          m = DELETE.match(text)
          if m:
              try:
                  delete = self.message_ids.pop(-int(m.group(1)))
              except IndexError:
                  pass
              else:
                  await self.cl.delete_messages(self.chat_id, delete)
                  # Notify that a message was deleted
                  self.log.insert(tkinter.END, '(message deleted)\n')
                  self.log.yview(tkinter.END)
                  return
  
          # Check if we want to reply to some message
          reply_to = None
          m = REPLY.match(text)
          if m:
              text = m.group(2)
              try:
                  reply_to = self.message_ids[-int(m.group(1))]
              except IndexError:
                  pass
  
          # NOTE: This part is no longer optional. It sends the message.
          # Send the message text and get back the sent message object
          message = await self.cl.send_message(self.chat_id, text,
                                               reply_to=reply_to)
  
          # Save the sent message ID and text to allow edits
          self.sent_text.append((message.id, text))
  
          # Process the sent message as if it were an event
          await self.on_message(message)