Repository: xonsh/xonsh

Issue:
Paths relative to `CDPATH` are completed even for commands that aren't `cd`, and are buggy
Steps to reproduce:
1. Navigate to an empty directory
2. Set your `CDPATH` to include your home directory
3. Type `cat `
4. Start typing the name of some directory in your home, then press  tab
5. It will be completed, and a space will be inserted after instead of the usual slash
6. Delete the space, add a slash and start typing the name of a file or a directory in said directory, then press tab again
7. The whole thing will be replaced with the name of the file/subdirectory, once again, with a space after.

This is probably two bugs, but I can't reproduce one without the other.

Xonfig:
```
+------------------+---------------------+
| xonsh            | 0.6.6.dev1          |
| Git SHA          | 4c78866e            |
| Commit Date      | Jun 6 18:21:58 2018 |
| Python           | 3.6.5               |
| PLY              | 3.11                |
| have readline    | True                |
| prompt toolkit   | 1.0.15              |
| shell type       | prompt_toolkit      |
| pygments         | 2.2.0               |
| on posix         | True                |
| on linux         | True                |
| distro           | debian              |
| on darwin        | False               |
| on windows       | False               |
| on cygwin        | False               |
| on msys2         | False               |
| is superuser     | False               |
| default encoding | utf-8               |
| xonsh encoding   | utf-8               |
| encoding errors  | surrogateescape     |
+------------------+---------------------+
```



Discussion:
Hi @dratini0 - thanks for reporting! This is really weird.  I have basically the exact same xonfig as you do and I cannot reproduce this at all.  Cat does not fill in anything when I hit tab.  What does the `xontrib list` command return?
Also, what is in your xonshrc?

Resolving patch:
diff --git a/xonsh/completers/path.py b/xonsh/completers/path.py
--- a/xonsh/completers/path.py
+++ b/xonsh/completers/path.py
@@ -20,6 +20,18 @@ def PATTERN_NEED_QUOTES():
     return re.compile(pattern)
 
 
+def cd_in_command(line):
+    lexer = builtins.__xonsh_execer__.parser.lexer
+    lexer.reset()
+    lexer.input(line)
+    have_cd = False
+    for tok in lexer:
+        if tok.type == 'NAME' and tok.value == 'cd':
+            have_cd = True
+            break
+    return have_cd
+
+
 def _path_from_partial_string(inp, pos=None):
     if pos is None:
         pos = len(inp)
@@ -295,7 +307,7 @@ def complete_path(prefix, line, start, end, ctx, cdpath=True, filtfunc=None):
     if tilde in prefix:
         home = os.path.expanduser(tilde)
         paths = {s.replace(home, tilde) for s in paths}
-    if cdpath:
+    if cdpath and cd_in_command(line):
         _add_cdpaths(paths, prefix)
     paths = set(filter(filtfunc, paths))
     paths, _ = _quote_paths({_normpath(s) for s in paths},


Test patch:
diff --git a/tests/test_path_completers.py b/tests/test_path_completers.py
--- a/tests/test_path_completers.py
+++ b/tests/test_path_completers.py
@@ -1,9 +1,17 @@
+import builtins
+
 import pytest
+from unittest.mock import patch
 
 from xonsh.environ import Env
 import xonsh.completers.path as xcp
 
 
+@pytest.fixture(autouse=True)
+def xonsh_execer_autouse(xonsh_builtins, xonsh_execer):
+    return xonsh_execer
+
+
 def test_pattern_need_quotes():
     # just make sure the regex compiles
     xcp.PATTERN_NEED_QUOTES.match('')
@@ -18,3 +26,16 @@ def test_complete_path(xonsh_builtins):
                                     'CDPATH': set(),
     }
     xcp.complete_path('[1-0.1]', '[1-0.1]', 0, 7, dict())
+
+
+@patch('xonsh.completers.path._add_cdpaths')
+def test_cd_path_no_cd(mock_add_cdpaths, xonsh_builtins):
+    xonsh_builtins.__xonsh_env__ = {'CASE_SENSITIVE_COMPLETIONS': False,
+                                    'GLOB_SORTED': True,
+                                    'SUBSEQUENCE_PATH_COMPLETION': False,
+                                    'FUZZY_PATH_COMPLETION': False,
+                                    'SUGGEST_THRESHOLD': 3,
+                                    'CDPATH': ['/'],
+    }
+    xcp.complete_path('a', 'cat a', 4, 5, dict())
+    mock_add_cdpaths.assert_not_called()