diff --git a/Changelog.rst b/Changelog.rst index df09155..93c0f07 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -12,6 +12,8 @@ Unreleased - Do not offer true/false value completions for boolean flags (``is_flag=True``, including ``--foo/--no-foo`` style options), which previously inserted a value into the positional-argument slot (#116). +- ``show_only_unused`` now also applies to arguments, so an argument that has + already been given is no longer completed again (#125). .. _version-0.3.0: diff --git a/click_repl/_completer.py b/click_repl/_completer.py index 5556607..b7e7743 100644 --- a/click_repl/_completer.py +++ b/click_repl/_completer.py @@ -262,6 +262,29 @@ def _get_completion_for_cmd_args( break elif isinstance(param, click.Argument): + # Show only unused arguments. A variadic argument (nargs=-1) + # always accepts more values, so it is never hidden. + already_present = False + get_source = getattr(autocomplete_ctx, "get_parameter_source", None) + source = None + if get_source is not None: + try: + source = get_source(param.name) + except Exception: + pass + + if source is not None: + already_present = getattr(source, "name", None) == "COMMANDLINE" + else: + already_present = autocomplete_ctx.params.get(param.name) not in ( + None, + (), + [], + ) + + if self.show_only_unused and already_present and param.nargs != -1: + continue + choices.extend( self._get_completion_from_params( autocomplete_ctx, args, param, incomplete diff --git a/tests/test_completion/test_common_tests/test_arg_completion.py b/tests/test_completion/test_common_tests/test_arg_completion.py index ba0742f..83cda50 100644 --- a/tests/test_completion/test_common_tests/test_arg_completion.py +++ b/tests/test_completion/test_common_tests/test_arg_completion.py @@ -32,3 +32,37 @@ def arg_choices(handler): completions = list(c.get_completions(Document("arg-choices "))) assert {x.text for x in completions} == {"foo", "bar"} + + +def test_only_unused_with_arg(): + @root_command.command() + @click.argument("handler", type=click.Choice(("foo", "bar"))) + def unused_arg(handler): + pass + + c.show_only_unused = True + + completions = list(c.get_completions(Document("unused-arg "))) + assert {x.text for x in completions} == {"foo", "bar"} + + completions = list(c.get_completions(Document("unused-arg foo "))) + assert {x.text for x in completions} == set() + + c.show_only_unused = False + + completions = list(c.get_completions(Document("unused-arg foo "))) + assert {x.text for x in completions} == {"foo", "bar"} + + +def test_only_unused_with_variadic_arg(): + @root_command.command() + @click.argument("handlers", type=click.Choice(("foo", "bar")), nargs=-1) + def unused_variadic_arg(handlers): + pass + + c.show_only_unused = True + + completions = list(c.get_completions(Document("unused-variadic-arg foo "))) + assert {x.text for x in completions} == {"foo", "bar"} + + c.show_only_unused = False