Repository: xonsh/xonsh

Issue:
"command not found" in bash_completion step
I recently installed [taskwarrior](taskwarrior.org), and now xonsh produces the following errors on startup:

```
/usr/local/etc/bash_completion.d/task.sh: line 75: task: command not found
/usr/local/etc/bash_completion.d/task.sh: line 75: task: command not found
~ $
```

However `task` is found normally from within the shell.

My path is set on the first line of my `~/.xonshrc`. So my guess is, there is some bash_completion stage in xonsh startup that is running before my PATH gets updated, and failing to find an executable in `/usr/local/bin`. Just as an experiment, I echoed my $PATH line into a new file called `/etc/xonshrc` but the same error message is displayed.



Discussion:
Hi @subsetpark, did you add this file to your `$BASH_COMPLETIONS`?  Just a guess...

@scopatz - yes, it's there. It's the default:

```
['/usr/local/etc/bash_completion',
 '/opt/local/etc/profile.d/bash_completion.sh']
```

And so the script in `bash_completion.d` is being caught and attempting to execute.

Well, $PATH is and the xonshrc file is executed before the completer is even instantiated: https://github.com/scopatz/xonsh/blob/master/xonsh/base_shell.py#L108

So this is some other issue, probably related to the fact that the environment isn't being passed in to the completion functions: https://github.com/scopatz/xonsh/blob/master/xonsh/completer.py#L466 and https://github.com/scopatz/xonsh/blob/master/xonsh/completer.py#L487

That should be a relatively quick fix.

Note that ideally this stuff would be refactored to use the `foreign_shell` interface.


Resolving patch:
diff --git a/xonsh/completer.py b/xonsh/completer.py
--- a/xonsh/completer.py
+++ b/xonsh/completer.py
@@ -428,19 +428,13 @@ def bash_complete(self, prefix, line, begidx, endidx):
             prefix = shlex.quote(prefix)
 
         script = BASH_COMPLETE_SCRIPT.format(filename=fnme,
-                                             line=' '.join(shlex.quote(p) for p in splt),
-                                             comp_line=shlex.quote(line),
-                                             n=n,
-                                             func=func,
-                                             cmd=cmd,
-                                             end=endidx + 1,
-                                             prefix=prefix,
-                                             prev=shlex.quote(prev))
+                    line=' '.join(shlex.quote(p) for p in splt),
+                    comp_line=shlex.quote(line), n=n, func=func, cmd=cmd,
+                    end=endidx + 1, prefix=prefix, prev=shlex.quote(prev))
         try:
-            out = subprocess.check_output(['bash'],
-                                          input=script,
-                                          universal_newlines=True,
-                                          stderr=subprocess.PIPE)
+            out = subprocess.check_output(['bash'], input=script,
+                    universal_newlines=True, stderr=subprocess.PIPE,
+                    env=builtins.__xonsh_env__.detype())
         except subprocess.CalledProcessError:
             out = ''
 
@@ -464,7 +458,7 @@ def _load_bash_complete_funcs(self):
             return
         inp.append('complete -p\n')
         out = subprocess.check_output(['bash'], input='\n'.join(inp),
-                                      universal_newlines=True)
+                env=builtins.__xonsh_env__.detype(), universal_newlines=True)
         for line in out.splitlines():
             head, cmd = line.rsplit(' ', 1)
             if len(cmd) == 0 or cmd == 'cd':
@@ -485,7 +479,7 @@ def _load_bash_complete_files(self):
             inp.append('declare -F ' + ' '.join([f for f in bash_funcs]))
             inp.append('shopt -u extdebug\n')
         out = subprocess.check_output(['bash'], input='\n'.join(inp),
-                                      universal_newlines=True)
+                env=builtins.__xonsh_env__.detype(), universal_newlines=True)
         func_files = {}
         for line in out.splitlines():
             parts = line.split()
@@ -594,11 +588,10 @@ def option_complete(self, prefix, cmd):
         if cmd not in self._options.keys():
             try:
                 manpage = subprocess.Popen(["man", cmd],
-                                           stdout=subprocess.PIPE,
-                                           stderr=subprocess.DEVNULL)
+                            stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
                 # This is a trick to get rid of reverse line feeds
                 text = subprocess.check_output(["col", "-b"],
-                                               stdin=manpage.stdout)
+                        stdin=manpage.stdout)
                 text = text.decode('utf-8')
                 scraped_text = ' '.join(SCRAPE_RE.findall(text))
                 matches = INNER_OPTIONS_RE.findall(scraped_text)


Test patch: