Source code for curious.commands.help
# This file is part of curious.
#
# curious is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# curious is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with curious. If not, see <http://www.gnu.org/licenses/>.
"""
Home of the default help command.
.. currentmodule:: curious.commands.help
"""
import inspect
from curious.commands import Context
from curious.commands.exc import CommandsError
from curious.commands.utils import get_full_name, get_usage
[docs]async def _get_command_list(ctx: Context, command, *, include_root: bool = True):
"""
Recursively produces a command list for the command, using subcommands.
"""
try:
if not (await ctx.can_run(command))[0]:
return []
except CommandsError:
return []
# XXX: Don't add command names if they're subcommands.
if not command.cmd_subcommand and include_root:
l = [command.cmd_name]
else:
l = []
for subcommand in command.cmd_subcommands:
# don't do hidden subcommands
if getattr(subcommand, "cmd_hidden", False) is True:
continue
# only do subcommands that can be ran
try:
can_run, _ = await ctx.can_run(command)
except CommandsError:
can_run = False
if not can_run:
continue
if include_root:
l.append(get_full_name(subcommand))
else:
l.append(subcommand.cmd_name)
l.extend(await _get_command_list(ctx, subcommand))
return l
[docs]async def help_for_all(ctx: Context):
"""
Gets the content of help for all.
"""
# rows is a list of messages for a help row
rows = []
# row_num is the current number to put on a row
# this isn't incremented if we skip a row
row_num = 0
for plugin in ctx.manager.plugins.values():
commands = plugin._get_commands()
command_names = []
for command in commands:
# check for hidden annotation
if getattr(command, "cmd_hidden", False) is True:
continue
# don't add subcommands on their own
# they are detected automatically by the command list loader
if command.cmd_subcommand:
continue
names = await _get_command_list(ctx, command)
command_names.extend(names)
if not command_names:
continue
row_num += 1
# wrap the command names in backticks
# and join it all up with some pipes
names_joined = ' | '.join(f"`{c}`" for c in command_names)
plugin_name = getattr(plugin, "plugin_name", plugin.__class__.__name__)
rows.append(f"**{row_num}. {plugin_name}:** {names_joined}")
# add any uncategorized commands
if ctx.manager.commands:
command_names = []
for command in ctx.manager.commands.values():
if command.cmd_subcommand:
continue
names = await _get_command_list(ctx, command)
command_names.extend(names)
if command_names:
row_num += 1
names_joined = ' | '.join(f"`{c}`" for c in command_names)
rows.append(f"**{row_num}. Uncategorized:** {names_joined}")
if not rows:
return "**You cannot run any commands.**"
# add a preamble
preamble = "**Commands:**\nUse `help <command>` for more information about a command.\n\n"
rows_joined = '\n'.join(rows)
return f"{preamble}{rows_joined}"
[docs]async def help_for_one(ctx: Context, command):
"""
Gets the content of help for one command.
"""
# get the command from the manager
cfunc = ctx.manager.get_command(command)
if cfunc is None:
return f"No such command: **`{command}`**"
usage = get_usage(cfunc, invoked_as=command)
subcommands = await _get_command_list(ctx, cfunc, include_root=False)
subcommands_fmtted = " | ".join(f"`{x}`" for x in subcommands)
description = inspect.getdoc(cfunc)
if description is None:
description = "No description."
if subcommands:
return f"`{usage}`\n\n{description}\n\n**Subcommands:** {subcommands_fmtted}"
else:
return f"`{usage}`\n\n{description}"
[docs]async def help_command(ctx: Context, *, command: str = None):
"""
The default help command.
"""
if command is None:
# Let the ruling classes tremble at a Communistic revolution.
# The proletarians have nothing to lose but their chains. They have a world to win.
content = await help_for_all(ctx)
else:
# Evidence-based policy
content = await help_for_one(ctx, command)
await ctx.channel.messages.send(content)