From 364d669eaafbb465faabe6c17ba086803a240808 Mon Sep 17 00:00:00 2001 From: Zomatree Date: Thu, 21 Oct 2021 06:54:24 +0100 Subject: [PATCH] replace shlex --- revolt/ext/commands/mixin.py | 100 +++++++++++++++++++++++++++++++---- 1 file changed, 90 insertions(+), 10 deletions(-) diff --git a/revolt/ext/commands/mixin.py b/revolt/ext/commands/mixin.py index ab178e7..bb93258 100755 --- a/revolt/ext/commands/mixin.py +++ b/revolt/ext/commands/mixin.py @@ -1,9 +1,7 @@ from __future__ import annotations -from typing import Any, Callable, Union, TYPE_CHECKING -from abc import ABC +from typing import Any, Callable, Union import revolt -from shlex import shlex from .context import Context from .command import Command @@ -33,6 +31,10 @@ class CommandsMeta(type): return self class CommandsMixin(metaclass=CommandsMeta): + """Main class that adds commands, this class should be subclassed along with `revolt.Client`.""" + + __slots__ = ("_commands", "all_commands") + _commands: list[Command] dispatch: Callable[..., None] @@ -52,22 +54,100 @@ class CommandsMixin(metaclass=CommandsMeta): return list(set(self.all_commands.values())) async def get_prefix(self, message: revolt.Message) -> Union[str, list[str]]: + """Overwrite this function to set the prefix used for commands, this function is called for every message. + + Parameters + ----------- + message: :class:`Message` + The message that was sent + + Returns + -------- + Union[:class:`str`, list[:class:`str`]] + The prefix(s) for the commands + """ raise NotImplementedError def get_command(self, name: str) -> Command: + """Gets a command. + + Parameters + ----------- + name: :class:`str` + The name or alias of the command + + Returns + -------- + :class:`Command` + The command with the name + """ return self.all_commands[name] def add_command(self, name: str, command: Command): + """Adds a command, this is typically only used for dynamic commands, you should use the `commands.command` decorator for most usecases. + + Parameters + ----------- + name: :class:`str` + The name or alias of the command + command: :class:`Command` + The command to be added + """ self.all_commands[name] = command def split_content(self, content: str) -> list[str]: - lex = shlex(content, posix=True) - lex.commenters = "" - lex.whitespace_split = True + """Splits a string into seperate parameters, overwrite this function to change how arguments are split. - return list(lex) + Parameters + ----------- + content: :class:`str` + The content of the message - async def process_commands(self, message: revolt.Message): + Returns + -------- + list[:class:`str`] + The arguments from the content + """ + args = [] + + temp: list[str] = [] + quoted = False + quote_char = "" + + for char in content: + if char == " " and not quoted: + args.append("".join(temp)) + temp = [] + + elif char in ["\"", "'"] and not quoted: + quoted = True + quote_char = char + + elif char == quote_char and quoted: + quoted = False + args.append("".join(temp)) + + else: + temp.append(char) + + return args + + def get_context(self, message: revolt.Message) -> type[Context]: + return Context + + async def process_commands(self, message: revolt.Message) -> Any: + """Processes commands, if you overwrite `Client.on_message` you should manually call this function inside the event. + + Parameters + ----------- + message: :class:`Message` + The message to process commands on + + Returns + -------- + Any + The return of the command, if any + """ content = message.content if not isinstance(content, str): @@ -95,10 +175,10 @@ class CommandsMixin(metaclass=CommandsMeta): except KeyError: return self.dispatch("command_error", Context(None, command_name, message), CommandNotFound(command_name)) - context = Context(command, command_name, message) + context = self.get_context(message)(command, command_name, message) try: - await context.invoke(args) + return await context.invoke(args) except Exception as e: self.dispatch("command_error", context, e)