Repository: pallets/click

Issue:
Bash completion for MultiCommands returns subcommands twice until it stops.
Python 2.7.10
broken in click >= 6
ok in click (5.1)

```
manage hello hello world world
```



Discussion:
+1 
Still a problem in click v6.2

Bash completion isn't working properly beyond the first click command level.

I've noticed this problem as well.  Some `git bisect` experiments indicate that the problem was introduced in commit 0a2919f34fcbc635d8530b4c5b60bf119b2bcedb on Nov 24th.

Still observing this issue with click v 6.3 and the current development branch  57c6f09. (Using python 2.7 on OS X in ZSH using bashcomplete (bashcompinit).

instead of getting tab completion providing:

```
cmd sub_cmd1 cmd_1_options ...
```

Autocomplete endlessly completes at the sub command level and never moves into the sub_command itself for auto completion:

```
cmd sub_cmd1 sub_cmd1 sub_cmd1 ....
```

Downgrading to click v 5.1 fixes the issue.

```
pip uninstall click
pip install -Iv click==5.1
```


Resolving patch:
diff --git a/click/_bashcomplete.py b/click/_bashcomplete.py
--- a/click/_bashcomplete.py
+++ b/click/_bashcomplete.py
@@ -30,27 +30,19 @@ def get_completion_script(prog_name, complete_var):
 
 def resolve_ctx(cli, prog_name, args):
     ctx = cli.make_context(prog_name, args, resilient_parsing=True)
-    while ctx.args and isinstance(ctx.command, MultiCommand):
-        cmd = ctx.command.get_command(ctx, ctx.args[0])
+    while ctx.args + ctx.protected_args and isinstance(ctx.command, MultiCommand):
+        a = ctx.args + ctx.protected_args
+        cmd = ctx.command.get_command(ctx, a[0])
         if cmd is None:
             return None
-        ctx = cmd.make_context(ctx.args[0], ctx.args[1:], parent=ctx,
-                               resilient_parsing=True)
+        ctx = cmd.make_context(a[0], a[1:], parent=ctx, resilient_parsing=True)
     return ctx
 
 
-def do_complete(cli, prog_name):
-    cwords = split_arg_string(os.environ['COMP_WORDS'])
-    cword = int(os.environ['COMP_CWORD'])
-    args = cwords[1:cword]
-    try:
-        incomplete = cwords[cword]
-    except IndexError:
-        incomplete = ''
-
+def get_choices(cli, prog_name, args, incomplete):
     ctx = resolve_ctx(cli, prog_name, args)
     if ctx is None:
-        return True
+        return
 
     choices = []
     if incomplete and not incomplete[:1].isalnum():
@@ -64,7 +56,20 @@ def do_complete(cli, prog_name):
 
     for item in choices:
         if item.startswith(incomplete):
-            echo(item)
+            yield item
+
+
+def do_complete(cli, prog_name):
+    cwords = split_arg_string(os.environ['COMP_WORDS'])
+    cword = int(os.environ['COMP_CWORD'])
+    args = cwords[1:cword]
+    try:
+        incomplete = cwords[cword]
+    except IndexError:
+        incomplete = ''
+
+    for item in get_choices(cli, prog_name, args, incomplete):
+        echo(item)
 
     return True
 


Test patch:
diff --git a/tests/test_bashcomplete.py b/tests/test_bashcomplete.py
new file mode 100644
--- /dev/null
+++ b/tests/test_bashcomplete.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+
+import click
+from click._bashcomplete import get_choices
+
+def test_basic():
+    @click.group()
+    @click.option('--global-opt')
+    def cli(global_opt):
+        pass
+
+    @cli.command()
+    @click.option('--local-opt')
+    def sub(local_opt):
+        pass
+
+    assert list(get_choices(cli, 'lol', [], '')) == ['sub']
+    assert list(get_choices(cli, 'lol', [], '-')) == ['--global-opt']
+    assert list(get_choices(cli, 'lol', ['sub'], '')) == []
+    assert list(get_choices(cli, 'lol', ['sub'], '-')) == ['--local-opt']