Repository: xonsh/xonsh

Issue:
Pip completer sneaks into cd when directory name contains 'pip'
## Expected Behavior
When triggering autocompletion in a `cd` command to enter a subdirectory of a directory containing 'pip', it should complete the subdirectory name. 

## Current Behavior
Instead, I get suggestions for `pip` subcommands like freeze, config, download, etc.

## Steps to Reproduce
Starting from a clean directory and an empty .xonshrc:
```
mkdir bagpipes
mkdir bagpipes/subdir
cd bagpipes/su[press tab here]
```
When tab is pressed in the above command, xonsh will not complete 'su' to 'subdir', but instead suggest pip subdommands.

## Workaround
Transposing the completers for `cd` and `pip` in the completer list fixes this specific issue, but it would not fix the similar issue of trying to complete another bash command, such as `ls bagpipes/su[press tab here]`. I haven't tried but assume that placing the pip completer after the bash completer would fix that too, although the proper fix seems to be making the pip completer not trigger when it shouldn't.

(For newbies like myself, you can transpose the completers by:

 ```
pip_completer = __xonsh__.completers['pip']
completer remove pip
completer add pip pip_completer ">cd"


Discussion:

Patch:
diff --git a/news/fix_pip_completer.rst b/news/fix_pip_completer.rst
new file mode 100644
index 00000000..a290c4be
--- /dev/null
+++ b/news/fix_pip_completer.rst
@@ -0,0 +1,24 @@
+**Added:**
+
+* <news item>
+
+**Changed:**
+
+* <news item>
+
+**Deprecated:**
+
+* <news item>
+
+**Removed:**
+
+* <news item>
+
+**Fixed:**
+
+* ``pip`` completer no longer fires when ``pip`` happens to appear within a word
+  like ``bagpipes``
+
+**Security:**
+
+* <news item>
diff --git a/xonsh/completers/pip.py b/xonsh/completers/pip.py
index b80acb97..179689ee 100644
--- a/xonsh/completers/pip.py
+++ b/xonsh/completers/pip.py
@@ -9,12 +9,12 @@ import xonsh.lazyasd as xl
 
 @xl.lazyobject
 def PIP_RE():
-    return re.compile(r"pip(?:\d|\.)*")
+    return re.compile(r"\bx?pip(?:\d|\.)*")
 
 
 @xl.lazyobject
 def PIP_LIST_RE():
-    return re.compile(r"pip(?:\d|\.)* (?:uninstall|show)")
+    return re.compile(r"\bx?pip(?:\d|\.)* (?:uninstall|show)")
 
 
 @xl.lazyobject


Test patch:
diff --git a/tests/completers/test_pip_completer.py b/tests/completers/test_pip_completer.py
new file mode 100644
index 00000000..506464ab
--- /dev/null
+++ b/tests/completers/test_pip_completer.py
@@ -0,0 +1,39 @@
+import pytest
+from xonsh.completers.pip import PIP_RE, PIP_LIST_RE
+
+
+@pytest.mark.parametrize(
+    "line", ["pip", "xpip search", "$(pip", "![pip", "$[pip", "!(xpip"]
+)
+def test_pip_re(line):
+    assert PIP_RE.search(line)
+
+
+@pytest.mark.parametrize(
+    "line",
+    [
+        "pip show",
+        "xpip uninstall",
+        "$(pip show",
+        "![pip uninstall",
+        "$[pip show",
+        "!(xpip uninstall",
+    ],
+)
+def test_pip_list_re(line):
+    assert PIP_LIST_RE.search(line)
+
+
+@pytest.mark.parametrize(
+    "line",
+    [
+        "bagpipes show",
+        "toxbagpip uninstall",
+        "$(tompippery show",
+        "![thewholepipandpaboodle uninstall",
+        "$[littlebopip show",
+        "!(boxpip uninstall",
+    ],
+)
+def test_pip_list_re(line):
+    assert PIP_RE.search(line) is None