Repository: pypa/pip

Issue:
Shell auto completion should also auto complete short options
* Pip version: 9.0.1
* Python version: 2.7.12
* Operating system: Ubuntu 16.04

### Description:

Pip's shell auto completion doesn't auto complete short options. The relevant code is:

https://github.com/pypa/pip/blob/729990c9869148f3f0098a2b2a0c0b92aefb8a69/src/pip/_internal/__init__.py#L130-L131

Which uses: [cpython/Lib/optparse.py:752-756](https://github.com/python/cpython/blob/811b2878dfc68dc3ecd81fb4b370c6e1f9ec69c2/Lib/optparse.py#L752-L756) which returns only the long option, if it's defined.

As a further limitation, which I'm not sure is triggered by Pip's auto completion, is that this will only autocomplete the first long option defined for an option that has multiple long options.

If it's acceptable, we can use the `_short_opts` and `_long_opts` attributes to calculate the completions so that we get all short and long options. What do you think?

### What I've run:

```sh
➜ eval "$(pip completion --zsh)"

➜ pip install -<tab>
# You get:
➜ pip install --
# Since -- is unambiguous when no short options are completed.
```



Discussion:

Resolving patch:
diff --git a/src/pip/_internal/__init__.py b/src/pip/_internal/__init__.py
--- a/src/pip/_internal/__init__.py
+++ b/src/pip/_internal/__init__.py
@@ -105,9 +105,11 @@ def autocomplete():
                 sys.exit(1)
 
         subcommand = commands_dict[subcommand_name]()
-        options += [(opt.get_opt_string(), opt.nargs)
-                    for opt in subcommand.parser.option_list_all
-                    if opt.help != optparse.SUPPRESS_HELP]
+
+        for opt in subcommand.parser.option_list_all:
+            if opt.help != optparse.SUPPRESS_HELP:
+                for opt_str in opt._long_opts + opt._short_opts:
+                    options.append((opt_str, opt.nargs))
 
         # filter out previously specified options from available options
         prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]]
@@ -117,7 +119,7 @@ def autocomplete():
         for option in options:
             opt_label = option[0]
             # append '=' to options which require args
-            if option[1]:
+            if option[1] and option[0][:2] == "--":
                 opt_label += '='
             print(opt_label)
     else:
@@ -127,8 +129,9 @@ def autocomplete():
             opts.append(parser.option_list)
             opts = (o for it in opts for o in it)
 
-            subcommands += [i.get_opt_string() for i in opts
-                            if i.help != optparse.SUPPRESS_HELP]
+            for opt in opts:
+                if opt.help != optparse.SUPPRESS_HELP:
+                    subcommands += opt._long_opts + opt._short_opts
 
         print(' '.join([x for x in subcommands if x.startswith(current)]))
     sys.exit(1)


Test patch:
diff --git a/tests/functional/test_completion.py b/tests/functional/test_completion.py
--- a/tests/functional/test_completion.py
+++ b/tests/functional/test_completion.py
@@ -121,6 +121,29 @@ def test_completion_option_for_command(script):
            "autocomplete function could not complete ``--``"
 
 
+def test_completion_short_option(script):
+    """
+    Test getting completion for short options after ``-`` (eg. pip -)
+    """
+
+    res, env = setup_completion(script, 'pip -', '1')
+
+    assert '-h' in res.stdout.split(),\
+           "autocomplete function could not complete short options after ``-``"
+
+
+def test_completion_short_option_for_command(script):
+    """
+    Test getting completion for short options after ``-`` in command
+    (eg. pip search -)
+    """
+
+    res, env = setup_completion(script, 'pip search -', '2')
+
+    assert '-h' in res.stdout.split(),\
+           "autocomplete function could not complete short options after ``-``"
+
+
 @pytest.mark.parametrize('flag', ['--bash', '--zsh', '--fish'])
 def test_completion_uses_same_executable_name(script, flag):
     expect_stderr = sys.version_info[:2] == (3, 3)