Source code for dob.clickux.bunchy_group

# This file exists within 'dob':
#
#   https://github.com/hotoffthehamster/dob
#
# Copyright © 2018-2020 Landon Bouma. All rights reserved.
#
# 'dob' 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 3  of the License,  or  (at your option)  any   later    version.
#
# 'dob' 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 can find the GNU General Public License reprinted in the file titled 'LICENSE',
# or visit <http://www.gnu.org/licenses/>.

"""Click Group wrapper adds plugin support."""

from collections import OrderedDict

import click_hotoffthehamster as click
from click_hotoffthehamster._compat import term_len

__all__ = (
    'ClickBunchyGroup',
)


[docs]class ClickBunchyGroup(click.Group): def __init__(self, *args, help_weight=10, **kwargs): super(ClickBunchyGroup, self).__init__(*args, **kwargs) self.group_bunchies = {None: OrderedDict()} self.order_sortkeys = {None: 0} self.help_weight = help_weight
[docs] def add_command(self, cmd, name=None): self.group_bunchies[None][cmd.name] = None return super(ClickBunchyGroup, self).add_command(cmd, name)
[docs] def add_to_bunch(self, cmd, bunchy_name, sort_key=0): self.bunchies_regroup(cmd, bunchy_name) self.sortkeys_update(cmd, bunchy_name, sort_key)
[docs] def bunchies_regroup(self, cmd, bunchy_name): self.group_bunchies.setdefault(bunchy_name, OrderedDict()) self.group_bunchies[bunchy_name][cmd.name] = None del self.group_bunchies[None][cmd.name]
[docs] def sortkeys_update(self, cmd, bunchy_name, sort_key): self.order_sortkeys[bunchy_name] = sort_key
# SYNC_ME: (lb): This is nasty... # Override Click's MultiCommand implementation.
[docs] def format_commands(self, ctx, formatter): # Avoid list mutation when iterating and call list_commands now, so that # the plugins are sourced. (I.e., if a plugin calls add_to_bunch, it edits # group_bunchies, which should not (cannot) happen while under iteration.) _ignored = self.list_commands(ctx) # noqa: F841 local var ... never used for tup in sorted(self.order_sortkeys.items(), key=lambda tup: tup[1]): commands, col_max = self.format_commands_fetch(ctx, tup[0]) section_header = callable(tup[0]) and tup[0]() or tup[0] self.format_commands_write( commands, ctx, formatter, section_header, col_min=col_max )
# Override Click's MultiCommand implementation.
[docs] def format_commands_fetch(self, ctx, bunchy_name): commands = [] col_max = 0 _commands = super(ClickBunchyGroup, self).format_commands_fetch(ctx) for subcommand, cmd in _commands: # GROUP-BUNCH: (lb): A little wonky. Seems least disruptive to code, though, # i.e., this is a lazy approach to solving group command bunching. if subcommand in self._commands: aliases = '|'.join(sorted(self._commands[subcommand])) subcommand = '{0} ({1})'.format(subcommand, aliases) col_max = max(col_max, term_len(subcommand)) # Note that this width does not account for color (ANSI codes). if cmd.name not in self.group_bunchies[bunchy_name].keys(): continue commands.append((subcommand, cmd)) # Sort commands in each group by help_weight, then name. sorted_commands = sorted(commands, key=lambda tup: tup[1].name) sorted_commands = sorted(sorted_commands, key=lambda tup: tup[1].help_weight) return sorted_commands, col_max