Repository: xonsh/xonsh

Issue:
Tab completion fails with IndexError on Windows
I have a directory:

```
$ ls
.  ..  __pycache__  bot.py  db.py  sleepy-bot.conf  sleepy.db
```

If I type `py[TAB]` I get the expected selection of possible completions beginning with 'py'. If, instead, I type `python [TAB]`, I get an Exception:

```
$ python Exception in thread Thread-81:
Traceback (most recent call last):
  File "C:\Python35-32\lib\threading.py", line 914, in _bootstrap_inner
    self.run()
  File "C:\Python35-32\lib\threading.py", line 862, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Python35-32\lib\site-packages\prompt_toolkit\interface.py", line 835, in run
    completions = list(buffer.completer.get_completions(document, complete_event))
  File "C:\Python35-32\lib\site-packages\xonsh\ptk\completer.py", line 49, in get_completions
    self.ctx)
  File "C:\Python35-32\lib\site-packages\xonsh\__amalgam__.py", line 124, in complete
    out = func(prefix, line, begidx, endidx, ctx)
  File "C:\Python35-32\lib\site-packages\xonsh\completers\__amalgam__.py", line 1442, in complete_from_bash
    command = xp.bash_command()
  File "C:\Python35-32\lib\site-packages\xonsh\__amalgam__.py", line 1664, in bash_command
    bc = windows_bash_command()
  File "C:\Python35-32\lib\site-packages\xonsh\__amalgam__.py", line 1629, in windows_bash_command
    bash_works = 'pc-linux-gnu' not in out.splitlines()[0]
IndexError: list index out of range
```

I get the same result with e.g. `python b[TAB]`.

My xonfig:

```
+------------------+---------------------+
| xonsh            | 0.5.7               |
| Git SHA          | f35ac0f             |
| Commit Date      | Mar 1 02:53:16 2017 |
| Python           | 3.5.2               |
| PLY              | 3.9                 |
| have readline    | False               |
| prompt toolkit   | 1.0.3               |
| shell type       | prompt_toolkit      |
| pygments         | 2.1.3               |
| on posix         | False               |
| on linux         | False               |
| on darwin        | False               |
| on windows       | True                |
| on cygwin        | False               |
| is superuser     | False               |
| default encoding | utf-8               |
| xonsh encoding   | utf-8               |
| encoding errors  | surrogateescape     |
+------------------+---------------------+
```


Discussion:
Hi @sopoforic -- thanks for reporting! 
So it looks like a problem with detecting whichever version of bash you have installed is causing this error. The `py<tab>` completions work since that's hitting our python-based completer. The failure is coming when we fall back to the bash completion since we don't find anything python-based to complete.

Is there any output from 

```console
which bash
```

or

```console
bash --version
```

when you run those commands within xonsh?

And is this Windows 10? And do you have the Windows Subsystem for Linux?

Thanks!
Windows 10, yes. I have the Windows Subsystem for Linux installed, though I don't use it.

`which bash` gives:

```
$ which bash
xonsh: For full traceback set: $XONSH_SHOW_TRACEBACK = True
KeyError: 'PATH'
```

`bash --version` returns with no output.
Ahh, ok. So there's no `bash` on path and we used to catch that exception. Maybe @melund can help out with this?
Wait... what? This is weird. It's entering the `if bash_on_path` in https://github.com/xonsh/xonsh/blob/master/xonsh/completers/bash_completion.py#L34 but it shouldn't...

@sopoforic can I ask you to try the following in a Python session and tell me what the output is?

```python
import shutil
shutil.which('bash')
```

Thanks!
```
>>> import shutil
>>> shutil.which('bash')
'C:\\Program Files\\OpenSSH\\bin\\bash.EXE'
```
@sopoforic 

The problem with `which` 
```
which bash
xonsh: For full traceback set: $XONSH_SHOW_TRACEBACK = True
KeyError: 'PATH'
```
is a regression in 0.5.7. I it fixed on master and 0.5.8. I don't know if that is what triggers the first bug. What is the output of `C:\\Program Files\\OpenSSH\\bin\\bash.EXE --version`? 

Btw. I can recommend the having bash from "git for windows" installed. It will give you git completions tab completions in xonsh. 



Resolving patch:
diff --git a/xonsh/completers/bash_completion.py b/xonsh/completers/bash_completion.py
--- a/xonsh/completers/bash_completion.py
+++ b/xonsh/completers/bash_completion.py
@@ -9,11 +9,13 @@
 import shutil
 import pathlib
 import platform
+import functools
 import subprocess
 
 __version__ = '0.1.0'
 
 
+@functools.lru_cache(1)
 def _git_for_windows_path():
     """Returns the path to git for windows, if available and None otherwise."""
     import winreg
@@ -26,25 +28,32 @@ def _git_for_windows_path():
     return gfwp
 
 
+@functools.lru_cache(1)
 def _windows_bash_command(env=None):
     """Determines the command for Bash on windows."""
     wbc = 'bash'
     path = None if env is None else env.get('PATH', None)
     bash_on_path = shutil.which('bash', path=path)
     if bash_on_path:
-        # Check if Bash is from the "Windows Subsystem for Linux" (WSL)
-        # which can't be used by xonsh foreign-shell/completer
-        out = subprocess.check_output([bash_on_path, '--version'],
-                                      stderr=subprocess.PIPE,
-                                      universal_newlines=True)
-        if 'pc-linux-gnu' in out.splitlines()[0]:
+        try:
+            out = subprocess.check_output([bash_on_path, '--version'],
+                                          stderr=subprocess.PIPE,
+                                          universal_newlines=True)
+        except subprocess.CalledProcessError:
+            bash_works = False
+        else:
+            # Check if Bash is from the "Windows Subsystem for Linux" (WSL)
+            # which can't be used by xonsh foreign-shell/completer
+            bash_works = out and 'pc-linux-gnu' not in out.splitlines()[0]
+
+        if bash_works:
+            wbc = bash_on_path
+        else:
             gfwp = _git_for_windows_path()
             if gfwp:
                 bashcmd = os.path.join(gfwp, 'bin\\bash.exe')
                 if os.path.isfile(bashcmd):
                     wbc = bashcmd
-        else:
-            wbc = bash_on_path
     return wbc
 
 
@@ -304,8 +313,10 @@ def bash_completions(prefix, line, begidx, endidx, env=None, paths=None,
         out = subprocess.check_output(
             [command, '-c', script], universal_newlines=True,
             stderr=subprocess.PIPE, env=env)
+        if not out:
+            raise ValueError
     except (subprocess.CalledProcessError, FileNotFoundError,
-            UnicodeDecodeError):
+            UnicodeDecodeError, ValueError):
         return set(), 0
 
     out = out.splitlines()
diff --git a/xonsh/platform.py b/xonsh/platform.py
--- a/xonsh/platform.py
+++ b/xonsh/platform.py
@@ -343,7 +343,7 @@ def windows_bash_command():
         else:
             # Check if Bash is from the "Windows Subsystem for Linux" (WSL)
             # which can't be used by xonsh foreign-shell/completer
-            bash_works = 'pc-linux-gnu' not in out.splitlines()[0]
+            bash_works = out and 'pc-linux-gnu' not in out.splitlines()[0]
 
         if bash_works:
             wbc = bash_on_path


Test patch: