Skip to content

Commit

Permalink
Remove hidden commands and options from completion results
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicholas Wiles committed Sep 12, 2018
1 parent 5843e8b commit 1b0f5a7
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 18 deletions.
33 changes: 22 additions & 11 deletions click/_bashcomplete.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def resolve_ctx(cli, prog_name, args):
:param args: full list of args
:return: the final context/command parsed
"""
ctx = cli.make_context(prog_name, args, resilient_parsing=True, ignore_default_values=True)
ctx = cli.make_context(prog_name, args, resilient_parsing=True)
args = ctx.protected_args + ctx.args
while args:
if isinstance(ctx.command, MultiCommand):
Expand Down Expand Up @@ -176,7 +176,7 @@ def get_user_autocompletions(ctx, args, incomplete, cmd_param):
if isinstance(cmd_param.type, Choice):
# Choices don't support descriptions.
results = [(c, None)
for c in cmd_param.type.choices if c.startswith(incomplete)]
for c in cmd_param.type.choices if str(c).startswith(incomplete)]
elif cmd_param.autocompletion is not None:
dynamic_completions = cmd_param.autocompletion(ctx=ctx,
args=args,
Expand All @@ -186,20 +186,32 @@ def get_user_autocompletions(ctx, args, incomplete, cmd_param):
return results


def get_visible_commands_starting_with(ctx, starts_with):
"""
:param ctx: context associated with the parsed command
:starts_with: string that visible commands must start with.
:return: all visible (not hidden) commands that start with starts_with.
"""
for c in ctx.command.list_commands(ctx):
if c.startswith(starts_with):
command = ctx.command.get_command(ctx, c)
if not command.hidden:
yield command


def add_subcommand_completions(ctx, incomplete, completions_out):
# Add subcommand completions.
if isinstance(ctx.command, MultiCommand):
completions_out.extend(
[(c, ctx.command.get_command(ctx, c).get_short_help_str()) for c in ctx.command.list_commands(ctx) if c.startswith(incomplete)])
[(c.name, c.get_short_help_str()) for c in get_visible_commands_starting_with(ctx, incomplete)])

# Walk up the context list and add any other completion possibilities from chained commands
while ctx.parent is not None:
ctx = ctx.parent
if isinstance(ctx.command, MultiCommand) and ctx.command.chain:
remaining_commands = sorted(
set(ctx.command.list_commands(ctx)) - set(ctx.protected_args))
completions_out.extend(
[(c, ctx.command.get_command(ctx, c).get_short_help_str()) for c in remaining_commands if c.startswith(incomplete)])
remaining_commands = [c for c in get_visible_commands_starting_with(ctx, incomplete)
if c.name not in ctx.protected_args]
completions_out.extend([(c.name, c.get_short_help_str()) for c in remaining_commands])


def get_choices(cli, prog_name, args, incomplete):
Expand Down Expand Up @@ -229,11 +241,10 @@ def get_choices(cli, prog_name, args, incomplete):
if start_of_option(incomplete):
# completions for partial options
for param in ctx.command.params:
if isinstance(param, Option):
if isinstance(param, Option) and not param.hidden:
param_opts = [param_opt for param_opt in param.opts +
param.secondary_opts if param_opt not in all_args or param.multiple]
completions.extend(
[(o, param.help) for o in param_opts if o.startswith(incomplete)])
completions.extend([(o, param.help) for o in param_opts if o.startswith(incomplete)])
return completions
# completion for option values from user supplied values
for param in ctx.command.params:
Expand Down Expand Up @@ -274,4 +285,4 @@ def bashcomplete(cli, prog_name, complete_var, complete_instr):
return True
elif complete_instr == 'complete' or complete_instr == 'complete_zsh':
return do_complete(cli, prog_name, complete_instr == 'complete_zsh')
return False
return False
8 changes: 1 addition & 7 deletions click/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def __init__(self, command, parent=None, info_name=None, obj=None,
resilient_parsing=False, allow_extra_args=None,
allow_interspersed_args=None,
ignore_unknown_options=None, help_option_names=None,
token_normalize_func=None, color=None, ignore_default_values=False):
token_normalize_func=None, color=None):
#: the parent context or `None` if none exists.
self.parent = parent
#: the :class:`Command` for this context.
Expand Down Expand Up @@ -317,12 +317,6 @@ def __init__(self, command, parent=None, info_name=None, obj=None,
#: will be ignored. Useful for completion.
self.resilient_parsing = resilient_parsing

#: Indicates that default values should be ignored.
#: Useful for completion.

#: .. versionadded:: 7.0
self.ignore_default_values = ignore_default_values

# If there is no envvar prefix yet, but the parent has one and
# the command on this level has a name, we can expand the envvar
# prefix automatically.
Expand Down
36 changes: 36 additions & 0 deletions tests/test_bashcomplete.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,39 @@ def esub():
assert choices_without_help(cli, ['sub'], 'c') == ['csub']
assert choices_without_help(cli, ['sub', 'csub'], '') == ['dsub', 'esub']
assert choices_without_help(cli, ['sub', 'csub', 'dsub'], '') == ['esub']


def test_hidden():
@click.group()
@click.option('--name', hidden=True)
@click.option('--choices', type=click.Choice([1, 2]), hidden=True)
def cli(name):
pass

@cli.group(hidden=True)
def hgroup():
pass

@hgroup.group()
def hgroupsub():
pass

@cli.command()
def asub():
pass

@cli.command(hidden=True)
@click.option('--hname')
def hsub():
pass

assert choices_without_help(cli, [], '--n') == []
assert choices_without_help(cli, [], '--c') == []
# If the user exactly types out the hidden param, complete its options.
assert choices_without_help(cli, ['--choices'], '') == [1, 2]
assert choices_without_help(cli, [], '') == ['asub']
assert choices_without_help(cli, [], '') == ['asub']
assert choices_without_help(cli, [], 'h') == []
# If the user exactly types out the hidden command, complete its subcommands.
assert choices_without_help(cli, ['hgroup'], '') == ['hgroupsub']
assert choices_without_help(cli, ['hsub'], '--h') == ['--hname']

0 comments on commit 1b0f5a7

Please sign in to comment.