Skip to content

Commit 48120e6

Browse files
committed
Implemented subcommand
1 parent 9ff3964 commit 48120e6

File tree

4 files changed

+42
-6
lines changed

4 files changed

+42
-6
lines changed

dico_command/bot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ async def execute_handler(self, message: dico.Message):
5555
context = Context.from_message(message, prefix_result, cmd, name)
5656
try:
5757
try:
58-
args, kwargs = smart_split(ipt[1] if len(ipt) > 1 else "", cmd.args_data)
58+
args, kwargs = smart_split(ipt[1] if len(ipt) > 1 else "", cmd.args_data, subcommand=bool(cmd.subcommands))
5959
except Exception as ex:
6060
raise InvalidArgument from ex
6161
self.logger.debug(f"Command {name} executed.")

dico_command/command.py

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import typing
22
from .context import Context
3-
from .exception import CheckFailed
4-
from .utils import read_function, is_coro
3+
from .exception import CheckFailed, InvalidArgument
4+
from .utils import read_function, is_coro, smart_split
55

66

77
class Command:
@@ -14,12 +14,20 @@ def __init__(self,
1414
self.name = name
1515
self.checks = checks or []
1616
self.aliases = aliases or []
17+
self.subcommands = {}
1718

1819
self.args_data = read_function(self.func)
1920
if hasattr(func, "_checks"):
2021
self.checks.extend(func._checks)
2122
self.addon = None
2223

24+
def subcommand(self, *args, **kwargs):
25+
def wrap(coro):
26+
cmd = command(*args, **kwargs)(coro)
27+
self.subcommands[cmd.name] = cmd
28+
return cmd
29+
return wrap
30+
2331
def register_addon(self, addon):
2432
self.addon = addon
2533

@@ -30,8 +38,33 @@ async def evaluate_checks(self, ctx: Context):
3038
async def invoke(self, ctx: Context, *args, **kwargs):
3139
if not await self.evaluate_checks(ctx):
3240
raise CheckFailed
33-
init_args = (ctx,) if self.addon is None else (self.addon, ctx)
34-
return await self.func(*init_args, *args, **kwargs)
41+
tgt = self.func
42+
args = [*args]
43+
subcommand_invoking = False
44+
subcommand_name = None
45+
subcommand = None
46+
if self.subcommands:
47+
if args and args[0] in self.subcommands:
48+
subcommand = self.subcommands[args[0]]
49+
tgt = subcommand.invoke
50+
del args[0]
51+
subcommand_invoking = True
52+
elif kwargs and [*kwargs.values()][0] in self.subcommands:
53+
subcommand = kwargs.pop([*kwargs.keys()][0])
54+
tgt = subcommand.invoke
55+
subcommand_invoking = True
56+
elif kwargs or args:
57+
raise InvalidArgument("unknown subcommand or invalid argument passed.")
58+
elif (args or kwargs) and not self.args_data:
59+
raise InvalidArgument("invalid argument data.")
60+
if subcommand_invoking:
61+
ctx.subcommand_name = subcommand_name
62+
msg = ctx.content
63+
ipt = msg.split(maxsplit=1)
64+
ipt = ipt[1].split(maxsplit=1) if len(ipt) > 1 else []
65+
args, kwargs = smart_split(ipt[1] if len(ipt) > 1 else "", subcommand.args_data, subcommand=bool(subcommand.subcommands))
66+
init_args = (ctx,) if self.addon is None or subcommand_invoking else (self.addon, ctx)
67+
return await tgt(*init_args, *args, **kwargs)
3568

3669

3770
def command(name: typing.Optional[str] = None, *, aliases: typing.Optional[typing.List[str]] = None):

dico_command/context.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ def __init__(self, client, resp, prefix, command, name_used, **kwargs):
99
self.prefix = prefix
1010
self.command = command
1111
self.name_used = name_used
12+
self.subcommand_name = None
1213

1314
@classmethod
1415
def from_message(cls, message: Message, prefix, command, name_used):

dico_command/utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ def read_function(func):
2222
return ret
2323

2424

25-
def smart_split(ipt: str, args_data: dict, splitter: str = " ") -> typing.Tuple[list, dict]:
25+
def smart_split(ipt: str, args_data: dict, splitter: str = " ", subcommand: bool = False) -> typing.Tuple[list, dict]:
2626
if len(args_data) == 0:
27+
if subcommand and ipt:
28+
return [*ipt.split(splitter)], {}
2729
return [], {}
2830
raw_split = ipt.split(splitter)
2931
# TODO: handle "..."

0 commit comments

Comments
 (0)