Summary
grep silently returns zero matches when the workspace lives under a directory whose name is in _IGNORE_DIRS (build, dist, target, venv, node_modules, AppData, Library, and the rest). Only the ripgrep engine is affected. The pure-Python fallback is fine.
This is separate from #17. That issue is about how ripgrep's output is parsed; this one is about which files ripgrep is asked to search in the first place. I checked #123's diff and re-ran with its exact flags, and it does not change this behaviour.
Cause
grep hands ripgrep an absolute path and excludes directories with a glob per name:
for ignored in sorted(_IGNORE_DIRS):
cmd += ["--glob", f"!**/{ignored}/**"]
cmd.append(str(base))
!**/build/** is matched against the entire absolute path, not against the part below the workspace root. So a workspace at C:\Dev\build\myproject matches its own exclusion, every file is filtered out, and rg exits 1 with no output and no error.
_py_grep filters directory names during the walk below base, so it only ever excludes descendants. The two engines disagree, which is the thing the comment above the exclusions says should not happen:
Do not rely solely on a workspace's .gitignore: the Python fallback always omits these generated/dependency directories too.
Reproduction
Measured on Windows 11, Python 3.11.9, ripgrep 15.1.0. Identical file contents in both workspaces:
from coworker.tools.search import search_tools
for p in (r"C:\Dev\build\myproject", r"C:\Dev\normal\myproject"):
out = search_tools(p)[0](pattern="hello")
print(p, out["engine"], out["count"])
| workspace |
engine |
matches |
C:\Dev\build\myproject |
ripgrep |
0 |
C:\Dev\normal\myproject |
ripgrep |
1 |
The only difference between the two is the name of a parent directory.
Since the cause is a glob matched against an absolute path, this is not specific to Windows. A workspace at ~/build/myproject, ~/Library/notes or anything under a dist or venv parent should behave the same way on Linux and macOS. I have only measured the Windows case, so treat the POSIX half as reasoning rather than evidence.
Why CI does not catch it
tests/test_code_tools.py::test_grep_finds_matches_and_respects_glob uses pytest's tmp_path. On Linux that resolves under /tmp, which contains no ignored name, so the test passes. On Windows tmp_path lands under %TEMP%, which sits under AppData, so the same test fails today.
One consequence worth flagging: because the cause is the search path and not the parsing, that test will still fail on Windows after #123 merges.
Suggested fix
Run ripgrep with cwd=base and pass "." as the target. ripgrep then emits workspace-relative paths, the exclusion globs match relative to the workspace, and a node_modules directory inside the workspace is still excluded correctly. _rel would resolve against base instead of the process working directory.
I have that working locally and verified it against both cases above. Happy to open a PR if you want it, and happy to leave it alone if you would rather fold it into #123.
Summary
grepsilently returns zero matches when the workspace lives under a directory whose name is in_IGNORE_DIRS(build,dist,target,venv,node_modules,AppData,Library, and the rest). Only the ripgrep engine is affected. The pure-Python fallback is fine.This is separate from #17. That issue is about how ripgrep's output is parsed; this one is about which files ripgrep is asked to search in the first place. I checked #123's diff and re-ran with its exact flags, and it does not change this behaviour.
Cause
grephands ripgrep an absolute path and excludes directories with a glob per name:!**/build/**is matched against the entire absolute path, not against the part below the workspace root. So a workspace atC:\Dev\build\myprojectmatches its own exclusion, every file is filtered out, and rg exits 1 with no output and no error._py_grepfilters directory names during the walk belowbase, so it only ever excludes descendants. The two engines disagree, which is the thing the comment above the exclusions says should not happen:Reproduction
Measured on Windows 11, Python 3.11.9, ripgrep 15.1.0. Identical file contents in both workspaces:
C:\Dev\build\myprojectC:\Dev\normal\myprojectThe only difference between the two is the name of a parent directory.
Since the cause is a glob matched against an absolute path, this is not specific to Windows. A workspace at
~/build/myproject,~/Library/notesor anything under adistorvenvparent should behave the same way on Linux and macOS. I have only measured the Windows case, so treat the POSIX half as reasoning rather than evidence.Why CI does not catch it
tests/test_code_tools.py::test_grep_finds_matches_and_respects_globuses pytest'stmp_path. On Linux that resolves under/tmp, which contains no ignored name, so the test passes. On Windowstmp_pathlands under%TEMP%, which sits underAppData, so the same test fails today.One consequence worth flagging: because the cause is the search path and not the parsing, that test will still fail on Windows after #123 merges.
Suggested fix
Run ripgrep with
cwd=baseand pass"."as the target. ripgrep then emits workspace-relative paths, the exclusion globs match relative to the workspace, and anode_modulesdirectory inside the workspace is still excluded correctly._relwould resolve againstbaseinstead of the process working directory.I have that working locally and verified it against both cases above. Happy to open a PR if you want it, and happy to leave it alone if you would rather fold it into #123.