replace shlex

This commit is contained in:
Zomatree
2021-10-21 06:54:24 +01:00
parent 6e7979c7bb
commit 364d669eaa
+90 -10
View File
@@ -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)