diff options
Diffstat (limited to 'bzrlib/help.py')
-rw-r--r-- | bzrlib/help.py | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/bzrlib/help.py b/bzrlib/help.py new file mode 100644 index 0000000..1babcb6 --- /dev/null +++ b/bzrlib/help.py @@ -0,0 +1,167 @@ +# Copyright (C) 2005-2011 Canonical Ltd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from __future__ import absolute_import + +# TODO: Some way to get a list of external commands (defined by shell +# scripts) so that they can be included in the help listing as well. +# It should be enough to just list the plugin directory and look for +# executable files with reasonable names. + +# TODO: `help commands --all` should show hidden commands + +import sys + +from bzrlib import ( + commands as _mod_commands, + errors, + help_topics, + osutils, + plugin, + ui, + utextwrap, + ) + + +def help(topic=None, outfile=None): + """Write the help for the specific topic to outfile""" + if outfile is None: + outfile = ui.ui_factory.make_output_stream() + + indices = HelpIndices() + + alias = _mod_commands.get_alias(topic) + try: + topics = indices.search(topic) + shadowed_terms = [] + for index, topic_obj in topics[1:]: + shadowed_terms.append('%s%s' % (index.prefix, + topic_obj.get_help_topic())) + source = topics[0][1] + outfile.write(source.get_help_text(shadowed_terms)) + except errors.NoHelpTopic: + if alias is None: + raise + + if alias is not None: + outfile.write("'bzr %s' is an alias for 'bzr %s'.\n" % (topic, + " ".join(alias))) + + +def help_commands(outfile=None): + """List all commands""" + if outfile is None: + outfile = ui.ui_factory.make_output_stream() + outfile.write(_help_commands_to_text('commands')) + + +def _help_commands_to_text(topic): + """Generate the help text for the list of commands""" + out = [] + if topic == 'hidden-commands': + hidden = True + else: + hidden = False + names = list(_mod_commands.all_command_names()) + commands = ((n, _mod_commands.get_cmd_object(n)) for n in names) + shown_commands = [(n, o) for n, o in commands if o.hidden == hidden] + max_name = max(len(n) for n, o in shown_commands) + indent = ' ' * (max_name + 1) + width = osutils.terminal_width() + if width is None: + width = osutils.default_terminal_width + # we need one extra space for terminals that wrap on last char + width = width - 1 + + for cmd_name, cmd_object in sorted(shown_commands): + plugin_name = cmd_object.plugin_name() + if plugin_name is None: + plugin_name = '' + else: + plugin_name = ' [%s]' % plugin_name + + cmd_help = cmd_object.help() + if cmd_help: + firstline = cmd_help.split('\n', 1)[0] + else: + firstline = '' + helpstring = '%-*s %s%s' % (max_name, cmd_name, firstline, plugin_name) + lines = utextwrap.wrap( + helpstring, subsequent_indent=indent, + width=width, + break_long_words=False) + for line in lines: + out.append(line + '\n') + return ''.join(out) + + +help_topics.topic_registry.register("commands", + _help_commands_to_text, + "Basic help for all commands", + help_topics.SECT_HIDDEN) +help_topics.topic_registry.register("hidden-commands", + _help_commands_to_text, + "All hidden commands", + help_topics.SECT_HIDDEN) + + +class HelpIndices(object): + """Maintainer of help topics across multiple indices. + + It is currently separate to the HelpTopicRegistry because of its ordered + nature, but possibly we should instead structure it as a search within the + registry and add ordering and searching facilities to the registry. The + registry would probably need to be restructured to support that cleanly + which is why this has been implemented in parallel even though it does as a + result permit searching for help in indices which are not discoverable via + 'help topics'. + + Each index has a unique prefix string, such as "commands", and contains + help topics which can be listed or searched. + """ + + def __init__(self): + self.search_path = [ + help_topics.HelpTopicIndex(), + _mod_commands.HelpCommandIndex(), + plugin.PluginsHelpIndex(), + help_topics.ConfigOptionHelpIndex(), + ] + + def _check_prefix_uniqueness(self): + """Ensure that the index collection is able to differentiate safely.""" + prefixes = {} + for index in self.search_path: + prefixes.setdefault(index.prefix, []).append(index) + for prefix, indices in prefixes.items(): + if len(indices) > 1: + raise errors.DuplicateHelpPrefix(prefix) + + def search(self, topic): + """Search for topic across the help search path. + + :param topic: A string naming the help topic to search for. + :raises: NoHelpTopic if none of the indexs in search_path have topic. + :return: A list of HelpTopics which matched 'topic'. + """ + self._check_prefix_uniqueness() + result = [] + for index in self.search_path: + result.extend([(index, _topic) for _topic in index.get_topics(topic)]) + if not result: + raise errors.NoHelpTopic(topic) + else: + return result |