Unfinished changes

aliases
Jef Roosens 2020-09-15 15:13:22 +02:00
parent 32ab8538a4
commit 2a9323b5f5
4 changed files with 101 additions and 14 deletions

View File

@ -5,13 +5,14 @@ from __future__ import annotations
# Built-in imports # Built-in imports
import re import re
import asyncio import asyncio
import shlex
# Typing imports # Typing imports
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
# Built-in imports # Built-in imports
from typing import Union from typing import Union, List, Tuple
class Simple: class Simple:
@ -53,6 +54,14 @@ class Simple:
return self return self
@property
def client(self):
"""
Returns the Frank client instance.
"""
return self._obj._client
class SimpleCommand(Simple): class SimpleCommand(Simple):
""" """
@ -72,15 +81,48 @@ class SimpleCommand(Simple):
self.cmd = cmd self.cmd = cmd
self.help_str = help_str self.help_str = help_str
def match(self, message: str) -> bool: def match(self, message: str) -> Tuple[bool, List[str]]:
""" """
Returns wether the command matches the given message. Returns wether the command matches the given message. If the arguments
can't be parsed (e.g. unmatched quotes), it will return False as well.
Args: Args:
message: message to check message: message to check
""" """
return self.cmd == message.split(" ")[0] return self._match_full(message.split(" "))
def _match_full(self, parts: List[str]) -> Tuple[bool, List[str]]:
"""
Returns wether the message matches the full command.
Args:
parts: parts of the message
"""
# Can't match without 3 or more parts
if len(parts) < 3:
return False, None
# Return False if it doesn't match
if not all(
(
parts[0] == self.client.PREFIX,
parts[1] in self._obj.PREFIX,
parts[2] == self.cmd,
)
):
return False, None
# Parse the output, and return True with the parsed items if it works,
# otherwise return False
try:
parsed = shlex.split(" ".join(parts[3:]))
return True, parsed
except ValueError:
return False, None
class RegularCommand(SimpleCommand): class RegularCommand(SimpleCommand):
@ -99,14 +141,43 @@ class RegularCommand(SimpleCommand):
super().__init__(self, func, cmd, help_str) super().__init__(self, func, cmd, help_str)
self.alias = alias self.alias = alias
# This only matters for aliases
self.requires_prefix = requires_prefix self.requires_prefix = requires_prefix
def match(self, message: str) -> bool: # TODO: make this return the right value
# This just makes it a bit easier to use in the function def match(self, message: str) -> Tuple[bool, List[str]]:
module = self._obj """
client = module._client Returns wether the message matches the current command.
"""
words = [word for word in message.split(" ") if word] parts = message.split(" ")
# If the alias doesn't match, return the full match, otherwise return
# alias
matches, parts = self._match_alias(parts)
if matches:
return matches, parts
return self._match_full(parts)
# TODO: make this return the right value
def _match_alias(self, parts: List[str]) -> Tuple[bool, List[str]]:
"""
Returns wether the message matches an alias.
"""
# Return False if there's only one part but a prefix is required
if self.requires_prefix and len(parts) == 1:
return False
# Match with prefix
if self.requires_prefix:
return parts[0] == self.client.PREFIX and parts[1] in self.alias
# Match without prefix
return parts[0] in self.alias
class RegexCommand(SimpleCommand): class RegexCommand(SimpleCommand):
@ -115,7 +186,7 @@ class RegexCommand(SimpleCommand):
prefix. prefix.
""" """
def match(self, prefix: str) -> bool: def match(self, message: str) -> Tuple[str, List[str]]:
""" """
Returns wether the regex pattern matches the given prefix. Returns wether the regex pattern matches the given prefix.
@ -124,7 +195,20 @@ class RegexCommand(SimpleCommand):
prefix prefix
""" """
return bool(re.fullmatch(self.cmd, prefix)) parts = message.split(" ")
matches = bool(re.fullmatch(self.cmd, parts[0]))
# If it doesn't match, just return False, don't parse the rest
if not matches:
return False, None
try:
parsed = shlex.split(" ".join(parts))
return True, parsed
except ValueError:
return False, None
class Daemon(Simple): class Daemon(Simple):

View File

@ -49,5 +49,6 @@ class ModuleMeta:
@cached_property @cached_property
def default(self) -> Default: def default(self) -> Default:
return next( return next(
iter(self._filter_attrs(lambda val: isinstance(val, Default))), None iter(self._filter_attrs(lambda val: isinstance(val, Default))),
None,
) )

View File

@ -118,7 +118,9 @@ class Module(ModuleMeta):
) )
else: else:
await func(cmd=cmd[1:], author=author, channel=channel, mid=mid) await func(
cmd=cmd[1:], author=author, channel=channel, mid=mid
)
elif self.default: elif self.default:
await self.default(author=author, channel=channel, mid=mid) await self.default(author=author, channel=channel, mid=mid)

View File

@ -1,5 +1,5 @@
[tool.black] [tool.black]
line-length = 80 line-length = 79
target-version = ['py38'] target-version = ['py38']
include = '\.pyi?$' include = '\.pyi?$'
exclude = ''' exclude = '''