rlmgrep 0.1.12__tar.gz → 0.1.14__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/PKG-INFO +3 -3
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/README.md +2 -2
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/pyproject.toml +1 -1
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep/__init__.py +1 -1
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep/cli.py +30 -8
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep/ingest.py +28 -16
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep.egg-info/PKG-INFO +3 -3
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep/__main__.py +0 -0
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep/config.py +0 -0
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep/file_map.py +0 -0
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep/interpreter.py +0 -0
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep/render.py +0 -0
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep/rlm.py +0 -0
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep.egg-info/SOURCES.txt +0 -0
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep.egg-info/dependency_links.txt +0 -0
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep.egg-info/entry_points.txt +0 -0
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep.egg-info/requires.txt +0 -0
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/rlmgrep.egg-info/top_level.txt +0 -0
- {rlmgrep-0.1.12 → rlmgrep-0.1.14}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rlmgrep
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.14
|
|
4
4
|
Summary: Grep-shaped CLI search powered by DSPy RLM
|
|
5
5
|
Author: rlmgrep
|
|
6
6
|
License: MIT
|
|
@@ -13,7 +13,7 @@ Requires-Dist: pypdf>=4.0.0
|
|
|
13
13
|
|
|
14
14
|
# rlmgrep
|
|
15
15
|
|
|
16
|
-
Grep-shaped search powered by DSPy RLM. It accepts a natural-language query, scans the files you point at, and prints matching lines in a grep-like format.
|
|
16
|
+
Grep-shaped search powered by DSPy RLM. It accepts a natural-language query, scans the files you point at, and prints matching lines in a grep-like format. Use `--answer` to get a narrative response grounded in the selected files/directories.
|
|
17
17
|
|
|
18
18
|
## Quickstart
|
|
19
19
|
|
|
@@ -128,7 +128,7 @@ rg -l "token" . | rlmgrep --files-from-stdin --answer "What does this token cont
|
|
|
128
128
|
## Input selection
|
|
129
129
|
|
|
130
130
|
- Directories are searched recursively by default. Use `--no-recursive` to stop recursion.
|
|
131
|
-
- Hidden files and `.gitignore`
|
|
131
|
+
- Hidden files and ignore files (`.gitignore`, `.ignore`, `.rgignore`) are respected by default. Use `--hidden` or `--no-ignore` to include them.
|
|
132
132
|
- `--type` uses built-in type mappings (e.g., `py`, `js`, `md`); unknown values are treated as file extensions.
|
|
133
133
|
- `-g/--glob` matches path globs against normalized paths (forward slashes).
|
|
134
134
|
- Paths are printed relative to the current working directory when possible.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# rlmgrep
|
|
2
2
|
|
|
3
|
-
Grep-shaped search powered by DSPy RLM. It accepts a natural-language query, scans the files you point at, and prints matching lines in a grep-like format.
|
|
3
|
+
Grep-shaped search powered by DSPy RLM. It accepts a natural-language query, scans the files you point at, and prints matching lines in a grep-like format. Use `--answer` to get a narrative response grounded in the selected files/directories.
|
|
4
4
|
|
|
5
5
|
## Quickstart
|
|
6
6
|
|
|
@@ -115,7 +115,7 @@ rg -l "token" . | rlmgrep --files-from-stdin --answer "What does this token cont
|
|
|
115
115
|
## Input selection
|
|
116
116
|
|
|
117
117
|
- Directories are searched recursively by default. Use `--no-recursive` to stop recursion.
|
|
118
|
-
- Hidden files and `.gitignore`
|
|
118
|
+
- Hidden files and ignore files (`.gitignore`, `.ignore`, `.rgignore`) are respected by default. Use `--hidden` or `--no-ignore` to include them.
|
|
119
119
|
- `--type` uses built-in type mappings (e.g., `py`, `js`, `md`); unknown values are treated as file extensions.
|
|
120
120
|
- `-g/--glob` matches path globs against normalized paths (forward slashes).
|
|
121
121
|
- Paths are printed relative to the current working directory when possible.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__all__ = ["__version__"]
|
|
2
|
-
__version__ = "0.1.
|
|
2
|
+
__version__ = "0.1.14"
|
|
@@ -11,7 +11,7 @@ from .config import ensure_default_config, load_config
|
|
|
11
11
|
from .file_map import build_file_map
|
|
12
12
|
from .ingest import (
|
|
13
13
|
FileRecord,
|
|
14
|
-
|
|
14
|
+
build_ignore_spec,
|
|
15
15
|
collect_candidates,
|
|
16
16
|
load_files,
|
|
17
17
|
resolve_type_exts,
|
|
@@ -88,7 +88,12 @@ def _parse_args(argv: list[str]) -> argparse.Namespace:
|
|
|
88
88
|
parser.add_argument("-m", dest="max_count", type=int, default=None, help="Max matching lines per file")
|
|
89
89
|
parser.add_argument("-a", "--text", dest="binary_as_text", action="store_true", help="Search binary files as text")
|
|
90
90
|
parser.add_argument("--hidden", action="store_true", help="Include hidden files and directories")
|
|
91
|
-
parser.add_argument(
|
|
91
|
+
parser.add_argument(
|
|
92
|
+
"--no-ignore",
|
|
93
|
+
dest="no_ignore",
|
|
94
|
+
action="store_true",
|
|
95
|
+
help="Do not respect ignore files (.gitignore/.ignore/.rgignore)",
|
|
96
|
+
)
|
|
92
97
|
parser.add_argument("--answer", action="store_true", help="Print a narrative answer before grep output")
|
|
93
98
|
parser.add_argument("-y", "--yes", action="store_true", help="Skip file count confirmation")
|
|
94
99
|
parser.add_argument(
|
|
@@ -147,11 +152,24 @@ def _pick(cli_value, config: dict, key: str, default=None):
|
|
|
147
152
|
return default
|
|
148
153
|
|
|
149
154
|
|
|
150
|
-
def _find_git_root(start: Path) -> Path | None:
|
|
155
|
+
def _find_git_root(start: Path) -> tuple[Path | None, Path | None]:
|
|
151
156
|
for p in [start, *start.parents]:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
157
|
+
git_path = p / ".git"
|
|
158
|
+
if git_path.is_dir():
|
|
159
|
+
return p, git_path
|
|
160
|
+
if git_path.is_file():
|
|
161
|
+
try:
|
|
162
|
+
raw = git_path.read_text(encoding="utf-8", errors="ignore").strip()
|
|
163
|
+
except Exception:
|
|
164
|
+
raw = ""
|
|
165
|
+
if raw.startswith("gitdir:"):
|
|
166
|
+
git_dir = raw.split(":", 1)[1].strip()
|
|
167
|
+
git_dir_path = Path(git_dir)
|
|
168
|
+
if not git_dir_path.is_absolute():
|
|
169
|
+
git_dir_path = (p / git_dir_path).resolve()
|
|
170
|
+
return p, git_dir_path
|
|
171
|
+
return p, None
|
|
172
|
+
return None, None
|
|
155
173
|
|
|
156
174
|
|
|
157
175
|
def _env_value(name: str) -> str | None:
|
|
@@ -442,8 +460,12 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
442
460
|
ignore_spec = None
|
|
443
461
|
ignore_root = None
|
|
444
462
|
if not args.no_ignore:
|
|
445
|
-
|
|
446
|
-
|
|
463
|
+
git_root, git_dir = _find_git_root(cwd)
|
|
464
|
+
ignore_root = git_root or cwd
|
|
465
|
+
extra_ignores: list[Path] = []
|
|
466
|
+
if git_dir is not None:
|
|
467
|
+
extra_ignores.append(git_dir / "info" / "exclude")
|
|
468
|
+
ignore_spec = build_ignore_spec(ignore_root, extra_paths=extra_ignores)
|
|
447
469
|
|
|
448
470
|
candidates = collect_candidates(
|
|
449
471
|
input_paths,
|
|
@@ -6,10 +6,7 @@ import os
|
|
|
6
6
|
from pathlib import Path, PurePosixPath
|
|
7
7
|
from typing import Any, Callable, Iterable
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
import pathspec
|
|
11
|
-
except Exception: # pragma: no cover - optional at import time
|
|
12
|
-
pathspec = None
|
|
9
|
+
import pathspec
|
|
13
10
|
|
|
14
11
|
from pypdf import PdfReader
|
|
15
12
|
|
|
@@ -167,18 +164,28 @@ def collect_files(paths: Iterable[str], recursive: bool = True) -> list[Path]:
|
|
|
167
164
|
return files
|
|
168
165
|
|
|
169
166
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
167
|
+
IGNORE_FILENAMES = {".gitignore", ".ignore", ".rgignore"}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def build_ignore_spec(
|
|
171
|
+
root: Path, extra_paths: Iterable[Path] | None = None
|
|
172
|
+
) -> "pathspec.PathSpec | None":
|
|
173
173
|
root = root.resolve()
|
|
174
|
-
|
|
174
|
+
ignore_paths: list[Path] = []
|
|
175
|
+
extra_paths = list(extra_paths or [])
|
|
176
|
+
|
|
175
177
|
for dirpath, dirnames, filenames in os.walk(root):
|
|
176
178
|
if ".git" in dirnames:
|
|
177
179
|
dirnames.remove(".git")
|
|
178
|
-
|
|
179
|
-
|
|
180
|
+
for name in filenames:
|
|
181
|
+
if name in IGNORE_FILENAMES:
|
|
182
|
+
ignore_paths.append(Path(dirpath) / name)
|
|
180
183
|
|
|
181
|
-
|
|
184
|
+
for extra in extra_paths:
|
|
185
|
+
if extra.exists():
|
|
186
|
+
ignore_paths.append(extra)
|
|
187
|
+
|
|
188
|
+
if not ignore_paths:
|
|
182
189
|
return None
|
|
183
190
|
|
|
184
191
|
def _sort_key(p: Path) -> tuple[int, str]:
|
|
@@ -189,10 +196,10 @@ def build_gitignore_spec(root: Path) -> "pathspec.PathSpec | None":
|
|
|
189
196
|
except ValueError:
|
|
190
197
|
return 0, p.as_posix()
|
|
191
198
|
|
|
192
|
-
|
|
199
|
+
ignore_paths.sort(key=_sort_key)
|
|
193
200
|
|
|
194
201
|
patterns: list[str] = []
|
|
195
|
-
for gi in
|
|
202
|
+
for gi in ignore_paths:
|
|
196
203
|
try:
|
|
197
204
|
rel_dir = gi.parent.relative_to(root).as_posix()
|
|
198
205
|
except ValueError:
|
|
@@ -205,13 +212,18 @@ def build_gitignore_spec(root: Path) -> "pathspec.PathSpec | None":
|
|
|
205
212
|
line = raw.rstrip("\n")
|
|
206
213
|
if not line:
|
|
207
214
|
continue
|
|
215
|
+
escaped = False
|
|
208
216
|
if line.startswith("\\#") or line.startswith("\\!"):
|
|
209
217
|
line = line[1:]
|
|
210
|
-
|
|
218
|
+
escaped = True
|
|
219
|
+
if not escaped and line.startswith("#"):
|
|
211
220
|
continue
|
|
212
|
-
negated =
|
|
213
|
-
if
|
|
221
|
+
negated = False
|
|
222
|
+
if not escaped and line.startswith("!"):
|
|
223
|
+
negated = True
|
|
214
224
|
line = line[1:]
|
|
225
|
+
if not line:
|
|
226
|
+
continue
|
|
215
227
|
if line.startswith("/"):
|
|
216
228
|
line = line[1:]
|
|
217
229
|
if rel_dir:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rlmgrep
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.14
|
|
4
4
|
Summary: Grep-shaped CLI search powered by DSPy RLM
|
|
5
5
|
Author: rlmgrep
|
|
6
6
|
License: MIT
|
|
@@ -13,7 +13,7 @@ Requires-Dist: pypdf>=4.0.0
|
|
|
13
13
|
|
|
14
14
|
# rlmgrep
|
|
15
15
|
|
|
16
|
-
Grep-shaped search powered by DSPy RLM. It accepts a natural-language query, scans the files you point at, and prints matching lines in a grep-like format.
|
|
16
|
+
Grep-shaped search powered by DSPy RLM. It accepts a natural-language query, scans the files you point at, and prints matching lines in a grep-like format. Use `--answer` to get a narrative response grounded in the selected files/directories.
|
|
17
17
|
|
|
18
18
|
## Quickstart
|
|
19
19
|
|
|
@@ -128,7 +128,7 @@ rg -l "token" . | rlmgrep --files-from-stdin --answer "What does this token cont
|
|
|
128
128
|
## Input selection
|
|
129
129
|
|
|
130
130
|
- Directories are searched recursively by default. Use `--no-recursive` to stop recursion.
|
|
131
|
-
- Hidden files and `.gitignore`
|
|
131
|
+
- Hidden files and ignore files (`.gitignore`, `.ignore`, `.rgignore`) are respected by default. Use `--hidden` or `--no-ignore` to include them.
|
|
132
132
|
- `--type` uses built-in type mappings (e.g., `py`, `js`, `md`); unknown values are treated as file extensions.
|
|
133
133
|
- `-g/--glob` matches path globs against normalized paths (forward slashes).
|
|
134
134
|
- Paths are printed relative to the current working directory when possible.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|