diff --git a/redbot/cogs/admin/admin.py b/redbot/cogs/admin/admin.py index 648bb948d..2b5c45e44 100644 --- a/redbot/cogs/admin/admin.py +++ b/redbot/cogs/admin/admin.py @@ -157,13 +157,12 @@ class Admin: else: await self.complain(ctx, USER_HIERARCHY_ISSUE) - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() @checks.admin_or_permissions(manage_roles=True) async def editrole(self, ctx: commands.Context): """Edits roles settings""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @editrole.command(name="colour", aliases=["color"]) async def editrole_colour( diff --git a/redbot/cogs/alias/alias.py b/redbot/cogs/alias/alias.py index fe99ce4c1..7df6a6cda 100644 --- a/redbot/cogs/alias/alias.py +++ b/redbot/cogs/alias/alias.py @@ -170,20 +170,18 @@ class Alias: new_message.content = "{}{} {}".format(prefix, alias.command, args) await self.bot.process_commands(new_message) - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() async def alias(self, ctx: commands.Context): """Manage per-server aliases for commands""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass - @alias.group(name="global") + @alias.group(name="global", autohelp=True) async def global_(self, ctx: commands.Context): """ Manage global aliases. """ - if ctx.invoked_subcommand is None or isinstance(ctx.invoked_subcommand, commands.Group): - await ctx.send_help() + pass @checks.mod_or_permissions(manage_guild=True) @alias.command(name="add") diff --git a/redbot/cogs/audio/audio.py b/redbot/cogs/audio/audio.py index e760d056f..9401ccbb8 100644 --- a/redbot/cogs/audio/audio.py +++ b/redbot/cogs/audio/audio.py @@ -163,12 +163,11 @@ class Audio: await message_channel.send(embed=embed) await player.skip() - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() async def audioset(self, ctx): """Music configuration options.""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @audioset.command() @checks.admin_or_permissions(manage_roles=True) @@ -631,12 +630,11 @@ class Audio: await player.play() await ctx.send(embed=embed) - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() async def playlist(self, ctx): """Playlist configuration options.""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @playlist.command(name="append") async def _playlist_append(self, ctx, playlist_name, *url): @@ -1593,13 +1591,12 @@ class Audio: embed.set_footer(text="Nothing playing.") await ctx.send(embed=embed) - @commands.group(aliases=["llset"]) + @commands.group(aliases=["llset"], autohelp=True) @commands.guild_only() @checks.is_owner() async def llsetup(self, ctx): """Lavalink server configuration options.""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @llsetup.command() async def external(self, ctx): diff --git a/redbot/cogs/bank/bank.py b/redbot/cogs/bank/bank.py index c272982c1..13e5616f0 100644 --- a/redbot/cogs/bank/bank.py +++ b/redbot/cogs/bank/bank.py @@ -58,7 +58,7 @@ class Bank: # SECTION commands - @commands.group() + @commands.group(autohelp=True) @checks.guildowner_or_permissions(administrator=True) async def bankset(self, ctx: commands.Context): """Base command for bank settings""" @@ -69,7 +69,6 @@ class Bank: default_balance = await bank._conf.default_balance() else: if not ctx.guild: - await ctx.send_help() return bank_name = await bank._conf.guild(ctx.guild).bank_name() currency_name = await bank._conf.guild(ctx.guild).currency() @@ -79,7 +78,6 @@ class Bank: "Bank settings:\n\nBank name: {}\nCurrency: {}\nDefault balance: {}" ).format(bank_name, currency_name, default_balance) await ctx.send(box(settings)) - await ctx.send_help() @bankset.command(name="toggleglobal") @checks.is_owner() diff --git a/redbot/cogs/cleanup/cleanup.py b/redbot/cogs/cleanup/cleanup.py index 2b486ac9b..b202409e8 100644 --- a/redbot/cogs/cleanup/cleanup.py +++ b/redbot/cogs/cleanup/cleanup.py @@ -92,12 +92,11 @@ class Cleanup: before = message return to_delete - @commands.group() + @commands.group(autohelp=True) @checks.mod_or_permissions(manage_messages=True) async def cleanup(self, ctx: commands.Context): """Deletes messages.""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @cleanup.command() @commands.guild_only() diff --git a/redbot/cogs/customcom/customcom.py b/redbot/cogs/customcom/customcom.py index 81c914636..e8dc6baba 100644 --- a/redbot/cogs/customcom/customcom.py +++ b/redbot/cogs/customcom/customcom.py @@ -141,14 +141,13 @@ class CustomCommands: self.config.register_guild(commands={}) self.commandobj = CommandObj(config=self.config, bot=self.bot) - @commands.group(aliases=["cc"], no_pm=True) + @commands.group(aliases=["cc"], autohelp=True) @commands.guild_only() async def customcom(self, ctx: commands.Context): """Custom commands management""" - if not ctx.invoked_subcommand: - await ctx.send_help() + pass - @customcom.group(name="add") + @customcom.group(name="add", autohelp=True) @checks.mod_or_permissions(administrator=True) async def cc_add(self, ctx: commands.Context): """ @@ -166,8 +165,7 @@ class CustomCommands: {server} message.guild """ - if not ctx.invoked_subcommand or isinstance(ctx.invoked_subcommand, commands.Group): - await ctx.send_help() + pass @cc_add.command(name="random") @checks.mod_or_permissions(administrator=True) diff --git a/redbot/cogs/downloader/downloader.py b/redbot/cogs/downloader/downloader.py index f9707c863..87b69be4c 100644 --- a/redbot/cogs/downloader/downloader.py +++ b/redbot/cogs/downloader/downloader.py @@ -204,14 +204,13 @@ class Downloader: ) ) - @commands.group() + @commands.group(autohelp=True) @checks.is_owner() async def repo(self, ctx): """ Command group for managing Downloader repos. """ - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @repo.command(name="add") async def _repo_add(self, ctx, name: str, repo_url: str, branch: str = None): @@ -273,14 +272,13 @@ class Downloader: msg = _("Information on {}:\n{}").format(repo_name.name, repo_name.description or "") await ctx.send(box(msg)) - @commands.group() + @commands.group(autohelp=True) @checks.is_owner() async def cog(self, ctx): """ Command group for managing installable Cogs. """ - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @cog.command(name="install") async def _cog_install(self, ctx, repo_name: Repo, cog_name: str): diff --git a/redbot/cogs/economy/economy.py b/redbot/cogs/economy/economy.py index 2f299456d..c31b1aa1d 100644 --- a/redbot/cogs/economy/economy.py +++ b/redbot/cogs/economy/economy.py @@ -137,11 +137,10 @@ class Economy: self.config.register_role(**self.default_role_settings) self.slot_register = defaultdict(dict) - @commands.group(name="bank") + @commands.group(name="bank", autohelp=True) async def _bank(self, ctx: commands.Context): """Bank operations""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @_bank.command() async def balance(self, ctx: commands.Context, user: discord.Member = None): @@ -439,14 +438,13 @@ class Economy: ) ) - @commands.group() + @commands.group(autohelp=True) @guild_only_check() @check_global_setting_admin() async def economyset(self, ctx: commands.Context): """Changes economy module settings""" guild = ctx.guild if ctx.invoked_subcommand is None: - await ctx.send_help() if await bank.is_global(): slot_min = await self.config.SLOT_MIN() slot_max = await self.config.SLOT_MAX() diff --git a/redbot/cogs/filter/filter.py b/redbot/cogs/filter/filter.py index d87848252..4061c101f 100644 --- a/redbot/cogs/filter/filter.py +++ b/redbot/cogs/filter/filter.py @@ -39,7 +39,7 @@ class Filter: except RuntimeError: pass - @commands.group(name="filter") + @commands.group(name="filter", autohelp=True) @commands.guild_only() @checks.mod_or_permissions(manage_messages=True) async def _filter(self, ctx: commands.Context): @@ -49,7 +49,6 @@ class Filter: Using this command with no subcommands will send the list of the server's filtered words.""" if ctx.invoked_subcommand is None: - await ctx.send_help() server = ctx.guild author = ctx.author word_list = await self.settings.guild(server).filter() diff --git a/redbot/cogs/image/image.py b/redbot/cogs/image/image.py index b837d0612..617ed4f14 100644 --- a/redbot/cogs/image/image.py +++ b/redbot/cogs/image/image.py @@ -26,14 +26,13 @@ class Image: def __unload(self): self.session.close() - @commands.group(name="imgur") + @commands.group(name="imgur", autohelp=True) async def _imgur(self, ctx): """Retrieves pictures from imgur Make sure to set the client ID using [p]imgurcreds""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @_imgur.command(name="search") async def imgur_search(self, ctx, *, term: str): diff --git a/redbot/cogs/mod/mod.py b/redbot/cogs/mod/mod.py index 9735a7c18..52291c9a3 100644 --- a/redbot/cogs/mod/mod.py +++ b/redbot/cogs/mod/mod.py @@ -161,14 +161,12 @@ class Mod: except RuntimeError: pass - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() @checks.guildowner_or_permissions(administrator=True) async def modset(self, ctx: commands.Context): """Manages server administration settings.""" if ctx.invoked_subcommand is None: - guild = ctx.guild - await ctx.send_help() # Display current settings delete_repeats = await self.settings.guild(guild).delete_repeats() @@ -834,13 +832,12 @@ class Mod: _("I cannot do that, I lack the '{}' permission.").format("Manage Nicknames") ) - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() @checks.mod_or_permissions(manage_channel=True) async def mute(self, ctx: commands.Context): """Mutes user in the channel/server""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @mute.command(name="voice") @commands.guild_only() @@ -1001,15 +998,14 @@ class Mod: await self.settings.member(user).perms_cache.set(perms_cache) return True, None - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() @checks.mod_or_permissions(manage_channel=True) async def unmute(self, ctx: commands.Context): """Unmutes user in the channel/server Defaults to channel""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @unmute.command(name="voice") @commands.guild_only() @@ -1168,7 +1164,7 @@ class Mod: await self.settings.member(user).perms_cache.set(perms_cache) return True, None - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() @checks.admin_or_permissions(manage_channels=True) async def ignore(self, ctx: commands.Context): @@ -1201,13 +1197,12 @@ class Mod: else: await ctx.send(_("This server is already being ignored.")) - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() @checks.admin_or_permissions(manage_channels=True) async def unignore(self, ctx: commands.Context): """Removes servers/channels from ignorelist""" if ctx.invoked_subcommand is None: - await ctx.send_help() await ctx.send(await self.count_ignored()) @unignore.command(name="channel") diff --git a/redbot/cogs/modlog/modlog.py b/redbot/cogs/modlog/modlog.py index a647353b1..418ae451a 100644 --- a/redbot/cogs/modlog/modlog.py +++ b/redbot/cogs/modlog/modlog.py @@ -15,12 +15,11 @@ class ModLog: def __init__(self, bot: Red): self.bot = bot - @commands.group() + @commands.group(autohelp=True) @checks.guildowner_or_permissions(administrator=True) async def modlogset(self, ctx: commands.Context): """Settings for the mod log""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @modlogset.command() @commands.guild_only() diff --git a/redbot/cogs/permissions/permissions.py b/redbot/cogs/permissions/permissions.py index 534586a85..66fc729d1 100644 --- a/redbot/cogs/permissions/permissions.py +++ b/redbot/cogs/permissions/permissions.py @@ -125,13 +125,12 @@ class Permissions: # async def admin_model(self, ctx: commands.Context) -> bool: # async def mod_model(self, ctx: commands.Context) -> bool: - @commands.group(aliases=["p"]) + @commands.group(aliases=["p"], autohelp=True) async def permissions(self, ctx: commands.Context): """ Permission management tools """ - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @permissions.command() async def explain(self, ctx: commands.Context): diff --git a/redbot/cogs/reports/reports.py b/redbot/cogs/reports/reports.py index 9f0c8b68c..77f20a898 100644 --- a/redbot/cogs/reports/reports.py +++ b/redbot/cogs/reports/reports.py @@ -56,7 +56,7 @@ class Reports: @checks.admin_or_permissions(manage_guild=True) @commands.guild_only() - @commands.group(name="reportset") + @commands.group(name="reportset", autohelp=True) async def reportset(self, ctx: commands.Context): """ settings for reports diff --git a/redbot/cogs/streams/streams.py b/redbot/cogs/streams/streams.py index 612cebca8..f0a18d50b 100644 --- a/redbot/cogs/streams/streams.py +++ b/redbot/cogs/streams/streams.py @@ -130,18 +130,16 @@ class Streams: else: await ctx.send(embed=embed) - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() @checks.mod() async def streamalert(self, ctx: commands.Context): - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass - @streamalert.group(name="twitch") + @streamalert.group(name="twitch", autohelp=True) async def _twitch(self, ctx: commands.Context): """Twitch stream alerts""" - if ctx.invoked_subcommand is None or ctx.invoked_subcommand == self._twitch: - await ctx.send_help() + pass @_twitch.command(name="channel") async def twitch_alert_channel(self, ctx: commands.Context, channel_name: str): @@ -291,11 +289,10 @@ class Streams: await self.add_or_remove_community(ctx, community) - @commands.group() + @commands.group(autohelp=True) @checks.mod() async def streamset(self, ctx: commands.Context): - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @streamset.command() @checks.is_owner() @@ -331,12 +328,11 @@ class Streams: await self.db.tokens.set_raw("YoutubeStream", value=key) await ctx.send(_("Youtube key set.")) - @streamset.group() + @streamset.group(autohelp=True) @commands.guild_only() async def mention(self, ctx: commands.Context): """Sets mentions for stream alerts.""" - if ctx.invoked_subcommand is None or ctx.invoked_subcommand == self.mention: - await ctx.send_help() + pass @mention.command(aliases=["everyone"]) @commands.guild_only() diff --git a/redbot/cogs/trivia/trivia.py b/redbot/cogs/trivia/trivia.py index 5a2e54046..b78beaa9c 100644 --- a/redbot/cogs/trivia/trivia.py +++ b/redbot/cogs/trivia/trivia.py @@ -41,13 +41,12 @@ class Trivia: self.conf.register_member(wins=0, games=0, total_score=0) - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() @checks.mod_or_permissions(administrator=True) async def triviaset(self, ctx: commands.Context): """Manage trivia settings.""" if ctx.invoked_subcommand is None: - await ctx.send_help() settings = self.conf.guild(ctx.guild) settings_dict = await settings.all() msg = box( @@ -252,7 +251,7 @@ class Trivia: return await ctx.send(msg) - @trivia.group(name="leaderboard", aliases=["lboard"]) + @trivia.group(name="leaderboard", aliases=["lboard"], autohelp=False) async def trivia_leaderboard(self, ctx: commands.Context): """Leaderboard for trivia. diff --git a/redbot/cogs/warnings/warnings.py b/redbot/cogs/warnings/warnings.py index 975e02c0c..e29ac57fd 100644 --- a/redbot/cogs/warnings/warnings.py +++ b/redbot/cogs/warnings/warnings.py @@ -41,13 +41,12 @@ class Warnings: except RuntimeError: pass - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() @checks.guildowner_or_permissions(administrator=True) async def warningset(self, ctx: commands.Context): """Warning settings""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @warningset.command() @commands.guild_only() @@ -59,13 +58,12 @@ class Warnings: _("Custom reasons have been {}.").format(_("enabled") if allowed else _("disabled")) ) - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() @checks.guildowner_or_permissions(administrator=True) async def warnaction(self, ctx: commands.Context): """Action management""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @warnaction.command(name="add") @commands.guild_only() @@ -136,13 +134,12 @@ class Warnings: else: await ctx.send(_("No action named {} exists!").format(action_name)) - @commands.group() + @commands.group(autohelp=True) @commands.guild_only() @checks.guildowner_or_permissions(administrator=True) async def warnreason(self, ctx: commands.Context): """Add reasons for warnings""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @warnreason.command(name="add") @commands.guild_only() diff --git a/redbot/core/commands/commands.py b/redbot/core/commands/commands.py index 7fd13a3d4..92bc6ff67 100644 --- a/redbot/core/commands/commands.py +++ b/redbot/core/commands/commands.py @@ -97,7 +97,27 @@ class Group(Command, commands.Group): in. """ - pass + def __init__(self, *args, **kwargs): + self.autohelp = kwargs.pop("autohelp", False) + super().__init__(*args, **kwargs) + + async def invoke(self, ctx): + + view = ctx.view + previous = view.index + view.skip_ws() + trigger = view.get_word() + if trigger: + ctx.subcommand_passed = trigger + ctx.invoked_subcommand = self.all_commands.get(trigger, None) + view.index = previous + view.previous = previous + + if ctx.invoked_subcommand is None or self == ctx.invoked_subcommand: + if self.autohelp and not self.invoke_without_command: + await ctx.send_help() + + await super().invoke(ctx) # decorators diff --git a/redbot/core/core_commands.py b/redbot/core/core_commands.py index 49919e50e..374ebe621 100644 --- a/redbot/core/core_commands.py +++ b/redbot/core/core_commands.py @@ -321,7 +321,7 @@ class Core(CoreLogic): return fmt.format(d=days, h=hours, m=minutes, s=seconds) - @commands.group() + @commands.group(autohelp=True) async def embedset(self, ctx: commands.Context): """ Commands for toggling embeds on or off. @@ -341,7 +341,6 @@ class Core(CoreLogic): user_setting = await self.bot.db.user(ctx.author).embeds() text += "User setting: {}".format(user_setting) await ctx.send(box(text)) - await ctx.send_help() @embedset.command(name="global") @checks.is_owner() @@ -528,7 +527,7 @@ class Core(CoreLogic): formed = self._get_package_strings(not_found, fmt, ("was", "were")) await ctx.send(formed) - @commands.group() + @commands.command() @checks.is_owner() async def unload(self, ctx, *, cog_name: str): """Unloads packages""" @@ -599,7 +598,7 @@ class Core(CoreLogic): pass await ctx.bot.shutdown(restart=True) - @commands.group(name="set") + @commands.group(name="set", autohelp=True) async def _set(self, ctx): """Changes Red's settings""" if ctx.invoked_subcommand is None: @@ -625,7 +624,6 @@ class Core(CoreLogic): f"Locale: {locale}" ) await ctx.send(box(settings)) - await ctx.send_help() @_set.command() @checks.guildowner() @@ -983,12 +981,11 @@ class Core(CoreLogic): ctx.bot.disable_sentry() await ctx.send(_("Done. Sentry logging is now disabled.")) - @commands.group() + @commands.group(autohelp=True) @checks.is_owner() async def helpset(self, ctx: commands.Context): """Manage settings for the help command.""" - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @helpset.command(name="pagecharlimit") async def helpset_pagecharlimt(self, ctx: commands.Context, limit: int): @@ -1269,14 +1266,13 @@ class Core(CoreLogic): else: await ctx.send(_("Message delivered to {}").format(destination)) - @commands.group() + @commands.group(autohelp=True) @checks.is_owner() async def whitelist(self, ctx): """ Whitelist management commands. """ - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @whitelist.command(name="add") async def whitelist_add(self, ctx, user: discord.User): @@ -1328,14 +1324,13 @@ class Core(CoreLogic): await ctx.bot.db.whitelist.set([]) await ctx.send(_("Whitelist has been cleared.")) - @commands.group() + @commands.group(autohelp=True) @checks.is_owner() async def blacklist(self, ctx): """ blacklist management commands. """ - if ctx.invoked_subcommand is None: - await ctx.send_help() + pass @blacklist.command(name="add") async def blacklist_add(self, ctx, user: discord.User):