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