44from .errors import MissingListenedComponentParameters , WrongType
55from .slash .tools import ParseMethod , cache_data , format_name , handle_options , handle_thing
66from .slash .http import create_global_command , create_guild_command , delete_global_command , delete_guild_command , delete_guild_commands , edit_global_command , edit_guild_command , get_command , get_command_permissions , get_global_commands , get_guild_commands , delete_global_commands , get_id , update_command_permissions
7- from .slash .types import AdditionalType , CommandType , ContextCommand , MessageCommand , OptionType , SlashCommand , SlashOption , SubSlashCommandGroup , UserCommand
7+ from .slash .types import AdditionalType , CommandType , ContextCommand , MessageCommand , OptionType , SlashCommand , SlashOption , SlashSubcommand , UserCommand
88from .tools import MISSING , _or , get_index , setup_logger
99from .http import jsonifyMessage , BetterRoute , send_files
1010from .receive import Interaction , Message , PressedButton , SelectedMenu , SlashedContext , WebhookMessage , SlashedCommand , SlashedSubCommand , getMessage
@@ -102,7 +102,7 @@ def __init__(self, client, parse_method = ParseMethod.AUTO, auto_sync=True, dele
102102
103103 self ._discord : com .Bot = client
104104 self .commands : Dict [(str , SlashCommand )] = {}
105- self .subcommands : Dict [(str , Dict [(str , Union [dict , SubSlashCommandGroup ])])] = {}
105+ self .subcommands : Dict [(str , Dict [(str , Union [dict , SlashSubcommand ])])] = {}
106106 self .context_commands : Dict [str , ContextCommand ] = {"message" : {}, "user" : {}}
107107 if discord .__version__ .startswith ("2" ):
108108 self ._discord .add_listener (self ._on_response , "on_socket_raw_receive" )
@@ -295,36 +295,48 @@ async def sync_commands(self, delete_unused=False):
295295 }
296296 own_guild_ids = [x .id for x in self ._discord .guilds ]
297297
298+
298299 #region gather commands
299300 commands = self .commands
300- for x in self .subcommands :
301- for y in self .subcommands [x ]:
302- sub = self .subcommands [x ][y ]
301+ for _base in self .subcommands :
302+ # get first base
303+ for _sub in self .subcommands [_base ]:
304+ # get second base/command
305+ sub = self .subcommands [_base ][_sub ]
306+ # when command has subcommand groups
303307 if type (sub ) is dict :
304- for z in self .subcommands [x ][y ]:
305- group = self .subcommands [x ][y ][z ]
306- if commands .get (group .base_names [0 ]) is not None :
307- index = get_index (commands [group .base_names [0 ]].options , group .base_names [1 ], lambda x : getattr (x , "name" ))
308+ for _group in self .subcommands [_base ][_sub ]:
309+ # the subcommand group
310+ group = self .subcommands [_base ][_sub ][_group ]
311+ # if there's already a base command
312+ if commands .get (_base ) is not None :
313+ # Check if base already has an option with the subs name
314+ index = get_index (commands [_base ].options , _sub , lambda x : getattr (x , "name" ))
315+ # if first base_name already exists
308316 if index > - 1 :
309- _ops = commands [group .base_names [0 ]].options [index ].options
310- _ops .append (group .to_option ())
311- commands [group .base_names [0 ]].options [index ].options = _ops
317+ # add to sub options
318+ base_ops = commands [_base ].options
319+ base_ops [index ].options += [group .to_option ()]
320+ commands [_base ].options = base_ops
321+ # if not exists
312322 else :
313- _ops = commands [ group . base_names [ 0 ]]. options
314- _ops . append ( SlashOption (OptionType .SUB_COMMAND_GROUP , group . base_names [ 1 ] , options = [group .to_option ()]))
315- commands [ group . base_names [ 0 ]]. options = _ops
323+ # create sub option + group option
324+ commands [ _base ]. options += [ SlashOption (OptionType .SUB_COMMAND_GROUP , _sub , options = [group .to_option ()])]
325+ # if no base command
316326 else :
317- commands [group .base_names [0 ]] = SlashCommand (None , group .base_names [0 ], MISSING , [
318- SlashOption (OptionType .SUB_COMMAND_GROUP , group .base_names [1 ], options = [group .to_option ()])
327+ # create base0 command together with base1 option and groupcommand option
328+ commands [_base ] = SlashCommand (None , _base , MISSING , [
329+ SlashOption (OptionType .SUB_COMMAND_GROUP , _sub , options = [group .to_option ()])
319330 ],
320- guild_ids = group .guild_ids , default_permission = group .default_permission , guild_permissions = group .guild_permission )
331+ guild_ids = group .guild_ids , default_permission = group .default_permission , guild_permissions = group .guild_permissions )
332+ # if is basic subcommand
321333 else :
322- if commands .get (sub .base_names [0 ]) is not None :
323- _ops = commands [sub .base_names [0 ]].options
324- _ops .append (sub .to_option ())
325- commands [sub .base_names [0 ]].options = _ops
334+ # If base exists
335+ if commands .get (_base ) is not None :
336+ commands [_base ].options += [sub .to_option ()]
326337 else :
327- commands [sub .base_names [0 ]] = SlashCommand (None , sub .base_names [0 ], options = [sub .to_dict ()], guild_ids = sub .guild_ids , default_permission = sub .default_permission , guild_permissions = sub .guild_permissions )
338+ # create base0 command with name option
339+ commands [_base ] = SlashCommand (None , _base , options = [sub .to_dict ()], guild_ids = sub .guild_ids , default_permission = sub .default_permission , guild_permissions = sub .guild_permissions )
328340 #endregion
329341
330342 async def guild_stuff (command , guild_ids ):
@@ -639,21 +651,31 @@ def _set_command(self, old_name, command: SlashCommand):
639651 else :
640652 del self .context_commands ["user" ][old_name ]
641653 self .context_commands ["user" ][command .name ] = command
642- def _add_to_cache (self , base : SlashCommand ):
654+ def _add_to_cache (self , base : Union [ SlashCommand , SlashSubcommand ] ):
643655 if base .command_type is CommandType .Slash :
656+ # basic slash command
644657 if type (base ) in [SlashCommand , CogCommand ]:
645658 self .commands [base .name ] = base
659+ # subcommand or subgroup
646660 else :
661+ # when subcommands is missing base
647662 if self .subcommands .get (base .base_names [0 ]) is None :
648663 self .subcommands [base .base_names [0 ]] = {}
664+ # subgroup
649665 if len (base .base_names ) > 1 :
666+ # if cache is missing second base_name
650667 if self .subcommands [base .base_names [0 ]].get (base .base_names [1 ]) is None :
651668 self .subcommands [base .base_names [0 ]][base .base_names [1 ]] = {}
669+ # add to internal cache
652670 self .subcommands [base .base_names [0 ]][base .base_names [1 ]][base .name ] = base
671+ # subcommand
653672 else :
673+ # add to cache
654674 self .subcommands [base .base_names [0 ]][base .name ] = base
675+ # context user command
655676 elif base .command_type == CommandType .User :
656677 self .context_commands ["user" ][base .name ] = base
678+ # context message command
657679 elif base .command_type == CommandType .Message :
658680 self .context_commands ["message" ][base .name ] = base
659681
@@ -712,21 +734,21 @@ def add_command(self, name, callback=None, description=MISSING, options=[], guil
712734 If ``api`` is True, this function will return a promise
713735 """
714736 command = SlashCommand (callback , name , description , options , guild_ids = guild_ids , default_permission = default_permission , guild_permissions = guild_permissions )
715- self .commands [ format_name ( name )] = command
737+ self ._add_to_cache ( command )
716738 if api is True :
717739 if self .ready is False :
718740 raise Exception ("Slashcommands are not ready yet" )
719741 return self .create_command (command )
720- def command (self , name , description = MISSING , options = [], guild_ids = MISSING , default_permission = True , guild_permissions = MISSING ):
742+ def command (self , name = MISSING , description = MISSING , options = [], guild_ids = MISSING , default_permission = True , guild_permissions = MISSING ):
721743 """A decorator for a slash command
722744
723745 command in discord:
724746 ``/name [options]``
725747
726748 Parameters
727749 ----------
728- name: :class:`str`
729- 1-32 characters long name
750+ name: :class:`str`, optional
751+ 1-32 characters long name; default MISSING
730752 .. note::
731753
732754 The name will be corrected automaticaly (spaces will be replaced with "-" and the name will be lowercased)
@@ -794,7 +816,7 @@ def wrapper(callback):
794816 """
795817 self .add_command (name , callback , description , options , guild_ids , default_permission , guild_permissions )
796818 return wrapper
797- def subcommand (self , base_names , name , description = MISSING , options = [], guild_ids = MISSING , default_permission = True , guild_permissions = MISSING ):
819+ def subcommand (self , base_names , name = MISSING , description = MISSING , options = [], guild_ids = MISSING , default_permission = True , guild_permissions = MISSING ):
798820 """A decorator for a subcommand group
799821
800822 command in discord
@@ -805,8 +827,8 @@ def subcommand(self, base_names, name, description=MISSING, options=[], guild_id
805827 base_names: List[:class:`str`] | :class:`str`
806828 The names of the parent bases, currently limited to 2
807829 If you want to make a subcommand (``/base name``), you have to use a str instead of a list
808- name: :class:`str`
809- 1-32 characters long name
830+ name: :class:`str`, optional
831+ 1-32 characters long name; default MISSING
810832 .. note::
811833
812834 The name will be corrected automaticaly (spaces will be replaced with "-" and the name will be lowercased)
@@ -893,22 +915,19 @@ def wrapper(callback):
893915 if sub is not None and self .subcommands [base ].get (sub ) is None :
894916 self .subcommands [base ][sub ] = {}
895917
896- command = SubSlashCommandGroup (callback , base_names , name , description , options = options , guild_ids = guild_ids , default_permission = default_permission , guild_permissions = guild_permissions )
897- if sub is not None :
898- self .subcommands [base ][sub ][format_name (name )] = command
899- else :
900- self .subcommands [base ][format_name (name )] = command
918+ command = SlashSubcommand (callback , base_names , name , description , options = options , guild_ids = guild_ids , default_permission = default_permission , guild_permissions = guild_permissions )
919+ self ._add_to_cache (command )
901920
902921 return wrapper
903- def user_command (self , name , guild_ids = MISSING , default_permission = True , guild_permissions = MISSING ):
922+ def user_command (self , name = MISSING , guild_ids = MISSING , default_permission = True , guild_permissions = MISSING ):
904923 """Decorator for user context commands in discord.
905924 ``Right-click username`` -> ``apps`` -> ``commands is displayed here``
906925
907926
908927 Parameters
909928 ----------
910- name: :class:`str`
911- The name of the command
929+ name: :class:`str`, optional
930+ The name of the command; default MISSING
912931 guild_ids: List[:class:`str` | :class:`int`]
913932 A list of guilds where the command can be used
914933 default_permission: :class:`bool`, optional
@@ -946,15 +965,15 @@ async def call(ctx, message):
946965 def wraper (callback ):
947966 self .context_commands ["user" ][format_name (name )] = UserCommand (callback , name , guild_ids , default_permission , guild_permissions )
948967 return wraper
949- def message_command (self , name , guild_ids = MISSING , default_permission = True , guild_permissions = MISSING ):
968+ def message_command (self , name = MISSING , guild_ids = MISSING , default_permission = True , guild_permissions = MISSING ):
950969 """Decorator for message context commands in discord.
951970 ``Right-click message`` -> ``apps`` -> ``commands is displayed here``
952971
953972
954973 Parameters
955974 ----------
956- name: :class:`str`
957- The name of the command
975+ name: :class:`str`, optional
976+ The name of the command; default MISSING
958977 guild_ids: List[:class:`str` | :class:`int`]
959978 A list of guilds where the command can be used
960979 default_permission: :class:`bool`, optional
0 commit comments