rgapi 0.1.1__tar.gz → 0.1.4__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.
- rgapi-0.1.4/.github/workflows/ci.yml +83 -0
- {rgapi-0.1.1 → rgapi-0.1.4}/.gitignore +1 -0
- {rgapi-0.1.1 → rgapi-0.1.4}/Cargo.lock +15 -57
- {rgapi-0.1.1 → rgapi-0.1.4}/Cargo.toml +7 -7
- {rgapi-0.1.1 → rgapi-0.1.4}/DEV.md +12 -6
- {rgapi-0.1.1 → rgapi-0.1.4}/PKG-INFO +7 -4
- {rgapi-0.1.1 → rgapi-0.1.4}/README.md +2 -3
- {rgapi-0.1.1 → rgapi-0.1.4}/pyproject.toml +7 -1
- rgapi-0.1.4/python/rgapi/__init__.py +211 -0
- {rgapi-0.1.1 → rgapi-0.1.4}/src/python.rs +3 -3
- {rgapi-0.1.1 → rgapi-0.1.4}/tests/test_rgapi.py +15 -0
- rgapi-0.1.1/.github/workflows/ci.yml +0 -62
- rgapi-0.1.1/python/rgapi/__init__.py +0 -208
- rgapi-0.1.1/tools/build.sh +0 -5
- rgapi-0.1.1/tools/bump.sh +0 -6
- rgapi-0.1.1/tools/bump2.sh +0 -6
- rgapi-0.1.1/tools/release.sh +0 -6
- rgapi-0.1.1/tools/test.sh +0 -4
- {rgapi-0.1.1 → rgapi-0.1.4}/src/lib.rs +0 -0
- {rgapi-0.1.1 → rgapi-0.1.4}/src/search.rs +0 -0
- {rgapi-0.1.1 → rgapi-0.1.4}/src/walk.rs +0 -0
- {rgapi-0.1.1 → rgapi-0.1.4}/tools/bench.py +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
tags: ['v*']
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v6
|
|
14
|
+
- run: cargo test
|
|
15
|
+
|
|
16
|
+
linux:
|
|
17
|
+
needs: test
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v6
|
|
21
|
+
- uses: PyO3/maturin-action@v1
|
|
22
|
+
with:
|
|
23
|
+
args: --release --out dist -i python3.10 -i python3.11 -i python3.12 -i python3.13
|
|
24
|
+
manylinux: auto
|
|
25
|
+
before-script-linux: |
|
|
26
|
+
python3.13 -m pip install 'fastship>=0.0.13'
|
|
27
|
+
python3.13 -m fastship.rs_prep --release
|
|
28
|
+
- uses: actions/upload-artifact@v4
|
|
29
|
+
with:
|
|
30
|
+
name: wheels-linux
|
|
31
|
+
path: dist
|
|
32
|
+
|
|
33
|
+
macos:
|
|
34
|
+
needs: test
|
|
35
|
+
runs-on: macos-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v6
|
|
38
|
+
- uses: actions/setup-python@v6
|
|
39
|
+
with:
|
|
40
|
+
python-version: '3.13'
|
|
41
|
+
- run: python -m pip install 'fastship>=0.0.13'
|
|
42
|
+
- run: python -m fastship.rs_prep --release
|
|
43
|
+
- uses: PyO3/maturin-action@v1
|
|
44
|
+
with:
|
|
45
|
+
args: --release --out dist -i python3.10 -i python3.11 -i python3.12 -i python3.13
|
|
46
|
+
- uses: actions/upload-artifact@v4
|
|
47
|
+
with:
|
|
48
|
+
name: wheels-macos
|
|
49
|
+
path: dist
|
|
50
|
+
|
|
51
|
+
sdist:
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v6
|
|
55
|
+
- uses: PyO3/maturin-action@v1
|
|
56
|
+
with:
|
|
57
|
+
command: sdist
|
|
58
|
+
args: -o dist
|
|
59
|
+
- uses: actions/upload-artifact@v4
|
|
60
|
+
with:
|
|
61
|
+
name: wheels-sdist
|
|
62
|
+
path: dist
|
|
63
|
+
|
|
64
|
+
publish:
|
|
65
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
66
|
+
needs: [linux, macos, sdist]
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
permissions:
|
|
69
|
+
id-token: write
|
|
70
|
+
contents: write
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@v6
|
|
73
|
+
- uses: actions/download-artifact@v4
|
|
74
|
+
with:
|
|
75
|
+
path: dist
|
|
76
|
+
merge-multiple: true
|
|
77
|
+
- uses: softprops/action-gh-release@v2
|
|
78
|
+
with:
|
|
79
|
+
files: dist/*
|
|
80
|
+
generate_release_notes: true
|
|
81
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
82
|
+
with:
|
|
83
|
+
packages-dir: dist/
|
|
@@ -11,12 +11,6 @@ dependencies = [
|
|
|
11
11
|
"memchr",
|
|
12
12
|
]
|
|
13
13
|
|
|
14
|
-
[[package]]
|
|
15
|
-
name = "autocfg"
|
|
16
|
-
version = "1.5.1"
|
|
17
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
18
|
-
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
|
19
|
-
|
|
20
14
|
[[package]]
|
|
21
15
|
name = "bstr"
|
|
22
16
|
version = "1.12.1"
|
|
@@ -149,15 +143,6 @@ dependencies = [
|
|
|
149
143
|
"winapi-util",
|
|
150
144
|
]
|
|
151
145
|
|
|
152
|
-
[[package]]
|
|
153
|
-
name = "indoc"
|
|
154
|
-
version = "2.0.7"
|
|
155
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
156
|
-
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
|
|
157
|
-
dependencies = [
|
|
158
|
-
"rustversion",
|
|
159
|
-
]
|
|
160
|
-
|
|
161
146
|
[[package]]
|
|
162
147
|
name = "libc"
|
|
163
148
|
version = "0.2.186"
|
|
@@ -166,9 +151,9 @@ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
|
|
166
151
|
|
|
167
152
|
[[package]]
|
|
168
153
|
name = "log"
|
|
169
|
-
version = "0.4.
|
|
154
|
+
version = "0.4.33"
|
|
170
155
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
171
|
-
checksum = "
|
|
156
|
+
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
|
172
157
|
|
|
173
158
|
[[package]]
|
|
174
159
|
name = "memchr"
|
|
@@ -185,15 +170,6 @@ dependencies = [
|
|
|
185
170
|
"libc",
|
|
186
171
|
]
|
|
187
172
|
|
|
188
|
-
[[package]]
|
|
189
|
-
name = "memoffset"
|
|
190
|
-
version = "0.9.1"
|
|
191
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
192
|
-
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
|
193
|
-
dependencies = [
|
|
194
|
-
"autocfg",
|
|
195
|
-
]
|
|
196
|
-
|
|
197
173
|
[[package]]
|
|
198
174
|
name = "once_cell"
|
|
199
175
|
version = "1.21.4"
|
|
@@ -217,37 +193,32 @@ dependencies = [
|
|
|
217
193
|
|
|
218
194
|
[[package]]
|
|
219
195
|
name = "pyo3"
|
|
220
|
-
version = "0.
|
|
196
|
+
version = "0.29.0"
|
|
221
197
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
222
|
-
checksum = "
|
|
198
|
+
checksum = "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c"
|
|
223
199
|
dependencies = [
|
|
224
|
-
"cfg-if",
|
|
225
|
-
"indoc",
|
|
226
200
|
"libc",
|
|
227
|
-
"memoffset",
|
|
228
201
|
"once_cell",
|
|
229
202
|
"portable-atomic",
|
|
230
203
|
"pyo3-build-config",
|
|
231
204
|
"pyo3-ffi",
|
|
232
205
|
"pyo3-macros",
|
|
233
|
-
"unindent",
|
|
234
206
|
]
|
|
235
207
|
|
|
236
208
|
[[package]]
|
|
237
209
|
name = "pyo3-build-config"
|
|
238
|
-
version = "0.
|
|
210
|
+
version = "0.29.0"
|
|
239
211
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
240
|
-
checksum = "
|
|
212
|
+
checksum = "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078"
|
|
241
213
|
dependencies = [
|
|
242
|
-
"once_cell",
|
|
243
214
|
"target-lexicon",
|
|
244
215
|
]
|
|
245
216
|
|
|
246
217
|
[[package]]
|
|
247
218
|
name = "pyo3-ffi"
|
|
248
|
-
version = "0.
|
|
219
|
+
version = "0.29.0"
|
|
249
220
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
250
|
-
checksum = "
|
|
221
|
+
checksum = "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b"
|
|
251
222
|
dependencies = [
|
|
252
223
|
"libc",
|
|
253
224
|
"pyo3-build-config",
|
|
@@ -255,9 +226,9 @@ dependencies = [
|
|
|
255
226
|
|
|
256
227
|
[[package]]
|
|
257
228
|
name = "pyo3-macros"
|
|
258
|
-
version = "0.
|
|
229
|
+
version = "0.29.0"
|
|
259
230
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
260
|
-
checksum = "
|
|
231
|
+
checksum = "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771"
|
|
261
232
|
dependencies = [
|
|
262
233
|
"proc-macro2",
|
|
263
234
|
"pyo3-macros-backend",
|
|
@@ -267,13 +238,12 @@ dependencies = [
|
|
|
267
238
|
|
|
268
239
|
[[package]]
|
|
269
240
|
name = "pyo3-macros-backend"
|
|
270
|
-
version = "0.
|
|
241
|
+
version = "0.29.0"
|
|
271
242
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
272
|
-
checksum = "
|
|
243
|
+
checksum = "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362"
|
|
273
244
|
dependencies = [
|
|
274
245
|
"heck",
|
|
275
246
|
"proc-macro2",
|
|
276
|
-
"pyo3-build-config",
|
|
277
247
|
"quote",
|
|
278
248
|
"syn",
|
|
279
249
|
]
|
|
@@ -306,7 +276,7 @@ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
|
|
306
276
|
|
|
307
277
|
[[package]]
|
|
308
278
|
name = "rgapi"
|
|
309
|
-
version = "0.1.
|
|
279
|
+
version = "0.1.4"
|
|
310
280
|
dependencies = [
|
|
311
281
|
"globset",
|
|
312
282
|
"grep-matcher",
|
|
@@ -316,12 +286,6 @@ dependencies = [
|
|
|
316
286
|
"pyo3",
|
|
317
287
|
]
|
|
318
288
|
|
|
319
|
-
[[package]]
|
|
320
|
-
name = "rustversion"
|
|
321
|
-
version = "1.0.22"
|
|
322
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
323
|
-
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
|
324
|
-
|
|
325
289
|
[[package]]
|
|
326
290
|
name = "same-file"
|
|
327
291
|
version = "1.0.6"
|
|
@@ -373,9 +337,9 @@ dependencies = [
|
|
|
373
337
|
|
|
374
338
|
[[package]]
|
|
375
339
|
name = "target-lexicon"
|
|
376
|
-
version = "0.
|
|
340
|
+
version = "0.13.5"
|
|
377
341
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
378
|
-
checksum = "
|
|
342
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
379
343
|
|
|
380
344
|
[[package]]
|
|
381
345
|
name = "unicode-ident"
|
|
@@ -383,12 +347,6 @@ version = "1.0.24"
|
|
|
383
347
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
384
348
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
385
349
|
|
|
386
|
-
[[package]]
|
|
387
|
-
name = "unindent"
|
|
388
|
-
version = "0.2.4"
|
|
389
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
390
|
-
checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
|
|
391
|
-
|
|
392
350
|
[[package]]
|
|
393
351
|
name = "walkdir"
|
|
394
352
|
version = "2.5.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "rgapi"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.4"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
license = "MIT OR Apache-2.0"
|
|
6
6
|
description = "Python API for ripgrep-style file walking and searching"
|
|
@@ -14,12 +14,12 @@ name = "rgapi"
|
|
|
14
14
|
crate-type = ["cdylib", "rlib"]
|
|
15
15
|
|
|
16
16
|
[dependencies]
|
|
17
|
-
globset = "0.4.18"
|
|
18
|
-
grep-matcher = "0.1.8"
|
|
19
|
-
grep-regex = "0.1.14"
|
|
20
|
-
grep-searcher = "0.1.16"
|
|
21
|
-
ignore = "0.4.26"
|
|
22
|
-
pyo3 = { version = "0.
|
|
17
|
+
globset = ">=0.4.18"
|
|
18
|
+
grep-matcher = ">=0.1.8"
|
|
19
|
+
grep-regex = ">=0.1.14"
|
|
20
|
+
grep-searcher = ">=0.1.16"
|
|
21
|
+
ignore = ">=0.4.26"
|
|
22
|
+
pyo3 = { version = ">=0.28", optional = true }
|
|
23
23
|
|
|
24
24
|
[features]
|
|
25
25
|
extension-module = ["pyo3", "pyo3/extension-module"]
|
|
@@ -17,17 +17,23 @@ The public Python API lives in `python/rgapi/__init__.py`. The extension module
|
|
|
17
17
|
## Commands
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
|
|
21
|
-
cargo check
|
|
22
|
-
maturin develop
|
|
23
|
-
pytest -q
|
|
20
|
+
ship-rs-test
|
|
24
21
|
```
|
|
25
22
|
|
|
26
|
-
Run `cargo
|
|
23
|
+
Run `cargo fmt --check` and `cargo check` for Rust-only edits. Run `chkstyle` after Python edits once tests pass.
|
|
27
24
|
|
|
28
25
|
## Release
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+
The canonical version lives in `Cargo.toml`. `pyproject.toml` gets the Python package version from Cargo via `dynamic = ["version"]`.
|
|
28
|
+
|
|
29
|
+
Release flow is: release first, then bump.
|
|
30
|
+
|
|
31
|
+
1. Run `ship-rs-test`.
|
|
32
|
+
2. Confirm the release version in `Cargo.toml` (`[package].version`).
|
|
33
|
+
3. Run `ship-rs-release`.
|
|
34
|
+
4. After pushing the release tag, run `ship-rs-bump`, commit the `Cargo.toml` version bump, and push to `main` without a tag.
|
|
35
|
+
|
|
36
|
+
The GitHub workflow builds wheels for Python 3.10-3.13 on Linux and macOS and publishes artifacts to GitHub Releases and PyPI when a `v*` tag is pushed.
|
|
31
37
|
|
|
32
38
|
## Design notes
|
|
33
39
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rgapi
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
|
+
Requires-Dist: fastship>=0.0.12 ; extra == 'dev'
|
|
7
|
+
Requires-Dist: maturin>=1.0,<2.0 ; extra == 'dev'
|
|
8
|
+
Requires-Dist: pytest ; extra == 'dev'
|
|
9
|
+
Provides-Extra: dev
|
|
6
10
|
Summary: Python API for ripgrep-style file walking and searching
|
|
7
11
|
Home-Page: https://github.com/AnswerDotAI/rgapi
|
|
8
12
|
Author-email: Jeremy Howard <j@fast.ai>
|
|
@@ -54,6 +58,7 @@ pip install rgapi
|
|
|
54
58
|
## Semantics
|
|
55
59
|
|
|
56
60
|
`fd` and `walk` return slash-separated paths relative to `root`. They use the `ignore` crate, so `.gitignore` and the usual ripgrep filters apply by default. Hidden files are skipped unless `hidden=True`. Pass `ignore=False` to disable ignore filtering. Symlinks are not followed unless `follow_links=True`; `same_file_system=True` avoids crossing filesystem boundaries. Traversal is parallel, and result order is not guaranteed; use `sorted(...)` if order matters.
|
|
61
|
+
`root` arguments accept `str` or `pathlib.Path` and expand `~`; `search_path` also accepts path-like file paths. Display labels such as `display_path` are stringified without expansion.
|
|
57
62
|
|
|
58
63
|
`fd` adds fd-like filtering on top of `walk`: `pattern` is a substring match on the relative path, and `include`/`exclude` use glob syntax. `glob=` is accepted as an alias for `include=`. A basename glob such as `*.py` also matches recursively, so it finds `src/app.py`. Use `ext="py"` or `ext=["py", "rs"]` for extension filters, `min_depth=`/`max_depth=` to bound recursion, and `max_filesize=` to skip files above a byte limit.
|
|
59
64
|
|
|
@@ -73,12 +78,10 @@ matches list of (start, end) byte offsets for match rows
|
|
|
73
78
|
|
|
74
79
|
`SearchLine` has a structured `repr`, an rg-style `str`, and `SearchLine.asdict()` returns row fields as a plain Python dict. `rg(..., paths=True)` returns unique matched paths, and `rg(..., count=True)` returns the total number of match spans. `paths` and `count` cannot both be set.
|
|
75
80
|
|
|
76
|
-
`before_context`, `after_context`, and `context`
|
|
81
|
+
`before_context`, `after_context`, and `context` are like `rg -B`, `rg -A`, and `rg -C`. Files containing NUL bytes or invalid UTF-8 are skipped.
|
|
77
82
|
|
|
78
83
|
Search is case-sensitive by default, matching `rg`. Use `smart_case=True` for `rg --smart-case` behavior, or `case_sensitive=False` to force case-insensitive matching.
|
|
79
84
|
|
|
80
|
-
`rg` and `rg_iter` check Python signals while waiting for search results, so notebook interrupts and `KeyboardInterrupt` cancel traversal cooperatively. Cancellation is prompt between files and while results are streaming; a single huge file that produces no callbacks may continue until that file scan returns.
|
|
81
|
-
|
|
82
85
|
## Benchmarks
|
|
83
86
|
|
|
84
87
|
`tools/bench.py` compares the `rg` CLI with in-process `rgapi`. Run it against a release build. One run on this machine, using best time from seven repeats:
|
|
@@ -39,6 +39,7 @@ pip install rgapi
|
|
|
39
39
|
## Semantics
|
|
40
40
|
|
|
41
41
|
`fd` and `walk` return slash-separated paths relative to `root`. They use the `ignore` crate, so `.gitignore` and the usual ripgrep filters apply by default. Hidden files are skipped unless `hidden=True`. Pass `ignore=False` to disable ignore filtering. Symlinks are not followed unless `follow_links=True`; `same_file_system=True` avoids crossing filesystem boundaries. Traversal is parallel, and result order is not guaranteed; use `sorted(...)` if order matters.
|
|
42
|
+
`root` arguments accept `str` or `pathlib.Path` and expand `~`; `search_path` also accepts path-like file paths. Display labels such as `display_path` are stringified without expansion.
|
|
42
43
|
|
|
43
44
|
`fd` adds fd-like filtering on top of `walk`: `pattern` is a substring match on the relative path, and `include`/`exclude` use glob syntax. `glob=` is accepted as an alias for `include=`. A basename glob such as `*.py` also matches recursively, so it finds `src/app.py`. Use `ext="py"` or `ext=["py", "rs"]` for extension filters, `min_depth=`/`max_depth=` to bound recursion, and `max_filesize=` to skip files above a byte limit.
|
|
44
45
|
|
|
@@ -58,12 +59,10 @@ matches list of (start, end) byte offsets for match rows
|
|
|
58
59
|
|
|
59
60
|
`SearchLine` has a structured `repr`, an rg-style `str`, and `SearchLine.asdict()` returns row fields as a plain Python dict. `rg(..., paths=True)` returns unique matched paths, and `rg(..., count=True)` returns the total number of match spans. `paths` and `count` cannot both be set.
|
|
60
61
|
|
|
61
|
-
`before_context`, `after_context`, and `context`
|
|
62
|
+
`before_context`, `after_context`, and `context` are like `rg -B`, `rg -A`, and `rg -C`. Files containing NUL bytes or invalid UTF-8 are skipped.
|
|
62
63
|
|
|
63
64
|
Search is case-sensitive by default, matching `rg`. Use `smart_case=True` for `rg --smart-case` behavior, or `case_sensitive=False` to force case-insensitive matching.
|
|
64
65
|
|
|
65
|
-
`rg` and `rg_iter` check Python signals while waiting for search results, so notebook interrupts and `KeyboardInterrupt` cancel traversal cooperatively. Cancellation is prompt between files and while results are streaming; a single huge file that produces no callbacks may continue until that file scan returns.
|
|
66
|
-
|
|
67
66
|
## Benchmarks
|
|
68
67
|
|
|
69
68
|
`tools/bench.py` compares the `rg` CLI with in-process `rgapi`. Run it against a release build. One run on this machine, using best time from seven repeats:
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rgapi"
|
|
7
|
-
|
|
7
|
+
dynamic = ["version"]
|
|
8
8
|
description = "Python API for ripgrep-style file walking and searching"
|
|
9
9
|
license = {text = "MIT OR Apache-2.0"}
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -15,6 +15,9 @@ classifiers = [
|
|
|
15
15
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
16
16
|
]
|
|
17
17
|
|
|
18
|
+
[project.optional-dependencies]
|
|
19
|
+
dev = ["fastship>=0.0.12", "maturin>=1.0,<2.0", "pytest"]
|
|
20
|
+
|
|
18
21
|
[project.urls]
|
|
19
22
|
Homepage = "https://github.com/AnswerDotAI/rgapi"
|
|
20
23
|
Repository = "https://github.com/AnswerDotAI/rgapi"
|
|
@@ -24,3 +27,6 @@ Issues = "https://github.com/AnswerDotAI/rgapi/issues"
|
|
|
24
27
|
features = ["extension-module"]
|
|
25
28
|
python-source = "python"
|
|
26
29
|
module-name = "rgapi._core"
|
|
30
|
+
|
|
31
|
+
[tool.fastship]
|
|
32
|
+
branch = "main"
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
from os import fspath
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from . import _core
|
|
5
|
+
|
|
6
|
+
Regex = _core.Regex
|
|
7
|
+
SearchLine = _core.SearchLine
|
|
8
|
+
RgIter = _core.RgIter
|
|
9
|
+
def compile(
|
|
10
|
+
pattern:str, # Regex pattern to compile
|
|
11
|
+
case_sensitive:bool|None=None, # True/False forces case; None allows `smart_case`
|
|
12
|
+
smart_case:bool=False # Match `rg --smart-case` behavior
|
|
13
|
+
) -> Regex:
|
|
14
|
+
"Compile a regex matcher for `search_text`, `search_path`, and direct matching."
|
|
15
|
+
return _core.compile(pattern, case_sensitive=case_sensitive, smart_case=smart_case)
|
|
16
|
+
|
|
17
|
+
class SearchResults(list):
|
|
18
|
+
"List of `SearchLine` rows with rg-style text display."
|
|
19
|
+
def __str__(self): return "\n".join(map(str, self))
|
|
20
|
+
def _repr_pretty_(self, p, cycle): p.text("..." if cycle else str(self))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _listify(value):
|
|
24
|
+
if value is None: return []
|
|
25
|
+
if isinstance(value, str): return [value]
|
|
26
|
+
return list(value)
|
|
27
|
+
def _fs_path(path): return str(Path(path).expanduser())
|
|
28
|
+
def _display_path(path): return None if path is None else fspath(path)
|
|
29
|
+
def _filters(glob=None, include=None, exclude=None, ext=None):
|
|
30
|
+
includes = _listify(include) + _listify(glob)
|
|
31
|
+
for suffix in _listify(ext):
|
|
32
|
+
suffix = str(suffix)
|
|
33
|
+
if suffix.startswith("."): suffix = suffix[1:]
|
|
34
|
+
includes.append(f"*.{suffix}")
|
|
35
|
+
return includes, _listify(exclude)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _context(context, before_context, after_context):
|
|
39
|
+
if context: return context, context
|
|
40
|
+
return before_context, after_context
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def walk(
|
|
44
|
+
root:str|Path=".", # Directory to walk (expands `~`)
|
|
45
|
+
hidden:bool=False, # Include hidden files and directories
|
|
46
|
+
ignore:bool=True, # Respect `.gitignore` and other ignore files
|
|
47
|
+
max_depth:int|None=None, # Maximum directory depth to descend
|
|
48
|
+
min_depth:int|None=None, # Minimum depth for returned paths
|
|
49
|
+
max_filesize:int|None=None, # Skip files larger than this many bytes
|
|
50
|
+
follow_links:bool=False, # Follow symbolic links while walking
|
|
51
|
+
same_file_system:bool=False, # Do not cross filesystem boundaries
|
|
52
|
+
path_re:str|None=None, # Regex that returned relative paths must match
|
|
53
|
+
skip_path_re:str|None=None, # Regex for relative paths to skip
|
|
54
|
+
skip_dir=None, # Directory glob or globs to prune
|
|
55
|
+
skip_dir_re:str|None=None, # Directory regex used to prune traversal
|
|
56
|
+
files:bool=True, # Include files in results
|
|
57
|
+
dirs:bool=False # Include directories in results
|
|
58
|
+
) -> list[str]:
|
|
59
|
+
"Walk a directory and return relative file and/or directory paths."
|
|
60
|
+
return _core.walk(_fs_path(root), hidden, ignore, max_depth, min_depth, max_filesize, follow_links,
|
|
61
|
+
same_file_system, path_re, skip_path_re, _listify(skip_dir), skip_dir_re, files, dirs)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def fd(
|
|
65
|
+
root:str|Path=".", # Directory to walk (expands `~`)
|
|
66
|
+
pattern:str|None=None, # Substring that relative paths must contain
|
|
67
|
+
glob=None, # Include glob or globs; alias for `include`
|
|
68
|
+
include=None, # Include glob or globs, e.g. `*.py`
|
|
69
|
+
exclude=None, # Exclude glob or globs, e.g. `test_*.py`
|
|
70
|
+
ext=None, # Extension or extensions to include, without needing `*.`
|
|
71
|
+
hidden:bool=False, # Include hidden files and directories
|
|
72
|
+
ignore:bool=True, # Respect `.gitignore` and other ignore files
|
|
73
|
+
max_depth:int|None=None, # Maximum directory depth to descend
|
|
74
|
+
min_depth:int|None=None, # Minimum depth for returned paths
|
|
75
|
+
max_filesize:int|None=None, # Skip files larger than this many bytes
|
|
76
|
+
follow_links:bool=False, # Follow symbolic links while walking
|
|
77
|
+
same_file_system:bool=False, # Do not cross filesystem boundaries
|
|
78
|
+
path_re:str|None=None, # Regex that returned relative paths must match
|
|
79
|
+
skip_path_re:str|None=None, # Regex for relative paths to skip
|
|
80
|
+
skip_dir=None, # Directory glob or globs to prune
|
|
81
|
+
skip_dir_re:str|None=None, # Directory regex used to prune traversal
|
|
82
|
+
files:bool=True, # Include files in results
|
|
83
|
+
dirs:bool=False # Include directories in results
|
|
84
|
+
) -> list[str]:
|
|
85
|
+
"Find paths with fd-style filters and gitignore support."
|
|
86
|
+
include, exclude = _filters(glob, include, exclude, ext)
|
|
87
|
+
return _core.find(_fs_path(root), pattern, include, exclude, hidden, ignore, max_depth, min_depth, max_filesize,
|
|
88
|
+
follow_links, same_file_system, path_re, skip_path_re, _listify(skip_dir), skip_dir_re, files, dirs)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _rg_args(pattern, root, glob, include, exclude, ext, hidden, ignore, max_depth, min_depth, max_filesize,
|
|
92
|
+
follow_links, same_file_system, path_re, skip_path_re, skip_dir, skip_dir_re, case_sensitive, smart_case,
|
|
93
|
+
before_context, after_context, context):
|
|
94
|
+
include, exclude = _filters(glob, include, exclude, ext)
|
|
95
|
+
before_context, after_context = _context(context, before_context, after_context)
|
|
96
|
+
return (pattern, _fs_path(root), include, exclude, hidden, ignore, max_depth, min_depth, max_filesize, follow_links, same_file_system,
|
|
97
|
+
path_re, skip_path_re, _listify(skip_dir), skip_dir_re, case_sensitive, smart_case, before_context, after_context)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def rg(
|
|
101
|
+
pattern:str, # Regex pattern to search for
|
|
102
|
+
root:str|Path=".", # Directory to search (expands `~`)
|
|
103
|
+
glob=None, # Include glob or globs; alias for `include`
|
|
104
|
+
include=None, # Include glob or globs, e.g. `*.py`
|
|
105
|
+
exclude=None, # Exclude glob or globs, e.g. `test_*.py`
|
|
106
|
+
ext=None, # Extension or extensions to include, without needing `*.`
|
|
107
|
+
hidden:bool=False, # Include hidden files and directories
|
|
108
|
+
ignore:bool=True, # Respect `.gitignore` and other ignore files
|
|
109
|
+
max_depth:int|None=None, # Maximum directory depth to descend
|
|
110
|
+
min_depth:int|None=None, # Minimum depth for returned/searched files
|
|
111
|
+
max_filesize:int|None=None, # Skip files larger than this many bytes
|
|
112
|
+
follow_links:bool=False, # Follow symbolic links while walking
|
|
113
|
+
same_file_system:bool=False, # Do not cross filesystem boundaries
|
|
114
|
+
path_re:str|None=None, # Regex that searched relative paths must match
|
|
115
|
+
skip_path_re:str|None=None, # Regex for relative paths to skip
|
|
116
|
+
skip_dir=None, # Directory glob or globs to prune
|
|
117
|
+
skip_dir_re:str|None=None, # Directory regex used to prune traversal
|
|
118
|
+
case_sensitive:bool|None=None, # True/False forces case; None allows `smart_case`
|
|
119
|
+
smart_case:bool=False, # Match `rg --smart-case` behavior
|
|
120
|
+
before_context:int=0, # Lines of context before each match, like `rg -B`
|
|
121
|
+
after_context:int=0, # Lines of context after each match, like `rg -A`
|
|
122
|
+
context:int=0, # Sets both before and after context, like `rg -C`
|
|
123
|
+
paths:bool=False, # Return unique matched paths instead of rows
|
|
124
|
+
count:bool=False # Return total match span count instead of rows
|
|
125
|
+
):
|
|
126
|
+
"Search files and return `SearchResults`, matched paths, or a count."
|
|
127
|
+
assert not (paths and count), "paths and count are mutually exclusive"
|
|
128
|
+
args = _rg_args(pattern, root, glob, include, exclude, ext, hidden, ignore, max_depth, min_depth, max_filesize,
|
|
129
|
+
follow_links, same_file_system, path_re, skip_path_re, skip_dir, skip_dir_re, case_sensitive, smart_case,
|
|
130
|
+
before_context, after_context, context)
|
|
131
|
+
if paths:
|
|
132
|
+
seen, res = set(), []
|
|
133
|
+
for row in _core.rg_iter(*args):
|
|
134
|
+
if row.kind != "match" or row.path in seen: continue
|
|
135
|
+
seen.add(row.path)
|
|
136
|
+
res.append(row.path)
|
|
137
|
+
return res
|
|
138
|
+
if count: return sum(len(row.matches) for row in _core.rg_iter(*args) if row.kind == "match")
|
|
139
|
+
return SearchResults(_core.rg(*args))
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def rg_iter(
|
|
143
|
+
pattern:str, # Regex pattern to search for
|
|
144
|
+
root:str|Path=".", # Directory to search (expands `~`)
|
|
145
|
+
glob=None, # Include glob or globs; alias for `include`
|
|
146
|
+
include=None, # Include glob or globs, e.g. `*.py`
|
|
147
|
+
exclude=None, # Exclude glob or globs, e.g. `test_*.py`
|
|
148
|
+
ext=None, # Extension or extensions to include, without needing `*.`
|
|
149
|
+
hidden:bool=False, # Include hidden files and directories
|
|
150
|
+
ignore:bool=True, # Respect `.gitignore` and other ignore files
|
|
151
|
+
max_depth:int|None=None, # Maximum directory depth to descend
|
|
152
|
+
min_depth:int|None=None, # Minimum depth for returned/searched files
|
|
153
|
+
max_filesize:int|None=None, # Skip files larger than this many bytes
|
|
154
|
+
follow_links:bool=False, # Follow symbolic links while walking
|
|
155
|
+
same_file_system:bool=False, # Do not cross filesystem boundaries
|
|
156
|
+
path_re:str|None=None, # Regex that searched relative paths must match
|
|
157
|
+
skip_path_re:str|None=None, # Regex for relative paths to skip
|
|
158
|
+
skip_dir=None, # Directory glob or globs to prune
|
|
159
|
+
skip_dir_re:str|None=None, # Directory regex used to prune traversal
|
|
160
|
+
case_sensitive:bool|None=None, # True/False forces case; None allows `smart_case`
|
|
161
|
+
smart_case:bool=False, # Match `rg --smart-case` behavior
|
|
162
|
+
before_context:int=0, # Lines of context before each match, like `rg -B`
|
|
163
|
+
after_context:int=0, # Lines of context after each match, like `rg -A`
|
|
164
|
+
context:int=0 # Sets both before and after context, like `rg -C`
|
|
165
|
+
) -> RgIter:
|
|
166
|
+
"Search files lazily, yielding `SearchLine` rows."
|
|
167
|
+
args = _rg_args(pattern, root, glob, include, exclude, ext, hidden, ignore, max_depth, min_depth, max_filesize,
|
|
168
|
+
follow_links, same_file_system, path_re, skip_path_re, skip_dir, skip_dir_re, case_sensitive, smart_case,
|
|
169
|
+
before_context, after_context, context)
|
|
170
|
+
return _core.rg_iter(*args)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def search_text(
|
|
174
|
+
matcher:Regex, # Compiled `Regex` from `compile()`
|
|
175
|
+
text:str, # Text to search
|
|
176
|
+
path:str|Path="<text>", # Path label stored in results
|
|
177
|
+
before_context:int=0, # Lines of context before each match
|
|
178
|
+
after_context:int=0, # Lines of context after each match
|
|
179
|
+
context:int=0 # Sets both before and after context, like `rg -C`
|
|
180
|
+
) -> SearchResults:
|
|
181
|
+
"Search an in-memory string with a compiled matcher."
|
|
182
|
+
before_context, after_context = _context(context, before_context, after_context)
|
|
183
|
+
return SearchResults(_core.search_text(matcher, text, _display_path(path), before_context, after_context))
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def search_path(
|
|
187
|
+
matcher:Regex, # Compiled `Regex` from `compile()`
|
|
188
|
+
path:str|Path, # File path to search (expands `~`)
|
|
189
|
+
display_path:str|Path|None=None, # Path stored in results; defaults to `path`
|
|
190
|
+
before_context:int=0, # Lines of context before each match
|
|
191
|
+
after_context:int=0, # Lines of context after each match
|
|
192
|
+
context:int=0 # Sets both before and after context, like `rg -C`
|
|
193
|
+
) -> SearchResults:
|
|
194
|
+
"Search one file with a compiled matcher."
|
|
195
|
+
before_context, after_context = _context(context, before_context, after_context)
|
|
196
|
+
return SearchResults(_core.search_path(matcher, _fs_path(path), _display_path(display_path), before_context, after_context))
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
__all__ = [
|
|
200
|
+
"Regex",
|
|
201
|
+
"RgIter",
|
|
202
|
+
"SearchLine",
|
|
203
|
+
"SearchResults",
|
|
204
|
+
"compile",
|
|
205
|
+
"fd",
|
|
206
|
+
"rg",
|
|
207
|
+
"rg_iter",
|
|
208
|
+
"search_path",
|
|
209
|
+
"search_text",
|
|
210
|
+
"walk",
|
|
211
|
+
]
|
|
@@ -13,7 +13,7 @@ use crate::{
|
|
|
13
13
|
search_text as search_text_core, FindOptions, RgIter, RgOptions, SearchLine,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
#[pyclass(name = "SearchLine", eq)]
|
|
16
|
+
#[pyclass(name = "SearchLine", eq, skip_from_py_object)]
|
|
17
17
|
#[derive(Clone, PartialEq)]
|
|
18
18
|
struct SearchLinePy {
|
|
19
19
|
#[pyo3(get)]
|
|
@@ -105,7 +105,7 @@ fn check_signals_or_cancel(py: Python<'_>, iter: &RgIter) -> PyResult<()> {
|
|
|
105
105
|
fn next_rg_line_py(py: Python<'_>, iter: &mut RgIter) -> PyResult<Option<SearchLinePy>> {
|
|
106
106
|
loop {
|
|
107
107
|
check_signals_or_cancel(py, iter)?;
|
|
108
|
-
let res = py.
|
|
108
|
+
let res = py.detach(|| iter.next_timeout(Duration::from_millis(50)));
|
|
109
109
|
check_signals_or_cancel(py, iter)?;
|
|
110
110
|
match res {
|
|
111
111
|
Ok(Ok(line)) => return Ok(Some(SearchLinePy::from(line))),
|
|
@@ -123,7 +123,7 @@ fn collect_rg_py(py: Python<'_>, mut iter: RgIter) -> PyResult<Vec<SearchLinePy>
|
|
|
123
123
|
}
|
|
124
124
|
Ok(res)
|
|
125
125
|
}
|
|
126
|
-
#[pyclass(name = "Regex")]
|
|
126
|
+
#[pyclass(name = "Regex", skip_from_py_object)]
|
|
127
127
|
#[derive(Clone)]
|
|
128
128
|
struct RegexPy {
|
|
129
129
|
#[pyo3(get)]
|
|
@@ -35,6 +35,21 @@ def test_fd_is_relative_and_respects_ignore_hidden_and_globs(tmp_path):
|
|
|
35
35
|
assert set(fd(str(tmp_path), exclude="*.py")) == {"bad.txt", "bin.dat"}
|
|
36
36
|
assert set(walk(str(tmp_path), files=True, dirs=False)) == found
|
|
37
37
|
|
|
38
|
+
def test_pathlike_arguments_and_expanduser(tmp_path, monkeypatch):
|
|
39
|
+
make_tree(tmp_path)
|
|
40
|
+
assert "src/app.py" in fd(tmp_path)
|
|
41
|
+
assert walk(tmp_path, path_re=r"\.py$") == ["src/app.py"]
|
|
42
|
+
assert [r.path for r in rg("TODO", tmp_path, include="*.py")] == ["src/app.py"]
|
|
43
|
+
assert list(rg_iter("TODO", tmp_path, include="*.py")) == rg("TODO", tmp_path, include="*.py")
|
|
44
|
+
matcher = compile("TODO")
|
|
45
|
+
text_label = tmp_path / "memory.txt"
|
|
46
|
+
assert search_text(matcher, "TODO\n", path=text_label)[0].path == str(text_label)
|
|
47
|
+
display = tmp_path / "display.py"
|
|
48
|
+
assert search_path(matcher, tmp_path / "src" / "app.py", display_path=display)[0].path == str(display)
|
|
49
|
+
|
|
50
|
+
monkeypatch.setenv("HOME", str(tmp_path))
|
|
51
|
+
assert fd("~", glob="*.py") == ["src/app.py"]
|
|
52
|
+
|
|
38
53
|
|
|
39
54
|
def test_path_filters_prune_dirs_and_follow_links(tmp_path):
|
|
40
55
|
(tmp_path / "src").mkdir()
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
tags: ['v*']
|
|
7
|
-
pull_request:
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
test:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
steps:
|
|
13
|
-
- uses: actions/checkout@v6
|
|
14
|
-
- run: cargo test
|
|
15
|
-
|
|
16
|
-
build:
|
|
17
|
-
needs: test
|
|
18
|
-
strategy:
|
|
19
|
-
matrix:
|
|
20
|
-
os: [ubuntu-latest, macos-latest]
|
|
21
|
-
python: ['3.10', '3.11', '3.12', '3.13']
|
|
22
|
-
runs-on: ${{ matrix.os }}
|
|
23
|
-
steps:
|
|
24
|
-
- uses: actions/checkout@v6
|
|
25
|
-
- uses: dtolnay/rust-toolchain@stable
|
|
26
|
-
- uses: actions/setup-python@v5
|
|
27
|
-
with:
|
|
28
|
-
python-version: ${{ matrix.python }}
|
|
29
|
-
- run: tools/build.sh release
|
|
30
|
-
- uses: PyO3/maturin-action@v1
|
|
31
|
-
with:
|
|
32
|
-
command: build
|
|
33
|
-
args: --release -o dist
|
|
34
|
-
- uses: actions/upload-artifact@v4
|
|
35
|
-
with:
|
|
36
|
-
name: wheel-${{ matrix.os }}-py${{ matrix.python }}
|
|
37
|
-
path: dist/*.whl
|
|
38
|
-
|
|
39
|
-
publish:
|
|
40
|
-
if: startsWith(github.ref, 'refs/tags/v')
|
|
41
|
-
needs: build
|
|
42
|
-
runs-on: ubuntu-latest
|
|
43
|
-
permissions:
|
|
44
|
-
id-token: write
|
|
45
|
-
contents: write
|
|
46
|
-
steps:
|
|
47
|
-
- uses: actions/checkout@v6
|
|
48
|
-
- uses: PyO3/maturin-action@v1
|
|
49
|
-
with:
|
|
50
|
-
command: sdist
|
|
51
|
-
args: -o dist
|
|
52
|
-
- uses: actions/download-artifact@v4
|
|
53
|
-
with:
|
|
54
|
-
path: dist
|
|
55
|
-
merge-multiple: true
|
|
56
|
-
- uses: softprops/action-gh-release@v2
|
|
57
|
-
with:
|
|
58
|
-
files: dist/*
|
|
59
|
-
generate_release_notes: true
|
|
60
|
-
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
61
|
-
with:
|
|
62
|
-
packages-dir: dist/
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
from . import _core
|
|
2
|
-
|
|
3
|
-
Regex = _core.Regex
|
|
4
|
-
SearchLine = _core.SearchLine
|
|
5
|
-
RgIter = _core.RgIter
|
|
6
|
-
def compile(
|
|
7
|
-
pattern, # Regex pattern to compile
|
|
8
|
-
case_sensitive=None, # True/False forces case; None allows `smart_case`
|
|
9
|
-
smart_case=False # Match `rg --smart-case` behavior
|
|
10
|
-
):
|
|
11
|
-
"Compile a regex matcher for `search_text`, `search_path`, and direct matching."
|
|
12
|
-
return _core.compile(pattern, case_sensitive=case_sensitive, smart_case=smart_case)
|
|
13
|
-
|
|
14
|
-
class SearchResults(list):
|
|
15
|
-
"List of `SearchLine` rows with rg-style text display."
|
|
16
|
-
def __str__(self): return "\n".join(map(str, self))
|
|
17
|
-
def _repr_pretty_(self, p, cycle): p.text("..." if cycle else str(self))
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _listify(value):
|
|
21
|
-
if value is None: return []
|
|
22
|
-
if isinstance(value, str): return [value]
|
|
23
|
-
return list(value)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def _filters(glob=None, include=None, exclude=None, ext=None):
|
|
27
|
-
includes = _listify(include) + _listify(glob)
|
|
28
|
-
for suffix in _listify(ext):
|
|
29
|
-
suffix = str(suffix)
|
|
30
|
-
if suffix.startswith("."): suffix = suffix[1:]
|
|
31
|
-
includes.append(f"*.{suffix}")
|
|
32
|
-
return includes, _listify(exclude)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def _context(context, before_context, after_context):
|
|
36
|
-
if context: return context, context
|
|
37
|
-
return before_context, after_context
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def walk(
|
|
41
|
-
root=".", # Directory to walk
|
|
42
|
-
hidden=False, # Include hidden files and directories
|
|
43
|
-
ignore=True, # Respect `.gitignore` and other ignore files
|
|
44
|
-
max_depth=None, # Maximum directory depth to descend
|
|
45
|
-
min_depth=None, # Minimum depth for returned paths
|
|
46
|
-
max_filesize=None, # Skip files larger than this many bytes
|
|
47
|
-
follow_links=False, # Follow symbolic links while walking
|
|
48
|
-
same_file_system=False, # Do not cross filesystem boundaries
|
|
49
|
-
path_re=None, # Regex that returned relative paths must match
|
|
50
|
-
skip_path_re=None, # Regex for relative paths to skip
|
|
51
|
-
skip_dir=None, # Directory glob or globs to prune
|
|
52
|
-
skip_dir_re=None, # Directory regex used to prune traversal
|
|
53
|
-
files=True, # Include files in results
|
|
54
|
-
dirs=False # Include directories in results
|
|
55
|
-
):
|
|
56
|
-
"Walk a directory and return relative file and/or directory paths."
|
|
57
|
-
return _core.walk(root, hidden, ignore, max_depth, min_depth, max_filesize, follow_links,
|
|
58
|
-
same_file_system, path_re, skip_path_re, _listify(skip_dir), skip_dir_re, files, dirs)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def fd(
|
|
62
|
-
root=".", # Directory to walk
|
|
63
|
-
pattern=None, # Substring that relative paths must contain
|
|
64
|
-
glob=None, # Include glob or globs; alias for `include`
|
|
65
|
-
include=None, # Include glob or globs, e.g. `*.py`
|
|
66
|
-
exclude=None, # Exclude glob or globs, e.g. `test_*.py`
|
|
67
|
-
ext=None, # Extension or extensions to include, without needing `*.`
|
|
68
|
-
hidden=False, # Include hidden files and directories
|
|
69
|
-
ignore=True, # Respect `.gitignore` and other ignore files
|
|
70
|
-
max_depth=None, # Maximum directory depth to descend
|
|
71
|
-
min_depth=None, # Minimum depth for returned paths
|
|
72
|
-
max_filesize=None, # Skip files larger than this many bytes
|
|
73
|
-
follow_links=False, # Follow symbolic links while walking
|
|
74
|
-
same_file_system=False, # Do not cross filesystem boundaries
|
|
75
|
-
path_re=None, # Regex that returned relative paths must match
|
|
76
|
-
skip_path_re=None, # Regex for relative paths to skip
|
|
77
|
-
skip_dir=None, # Directory glob or globs to prune
|
|
78
|
-
skip_dir_re=None, # Directory regex used to prune traversal
|
|
79
|
-
files=True, # Include files in results
|
|
80
|
-
dirs=False # Include directories in results
|
|
81
|
-
):
|
|
82
|
-
"Find paths with fd-style filters and gitignore support."
|
|
83
|
-
include, exclude = _filters(glob, include, exclude, ext)
|
|
84
|
-
return _core.find(root, pattern, include, exclude, hidden, ignore, max_depth, min_depth, max_filesize,
|
|
85
|
-
follow_links, same_file_system, path_re, skip_path_re, _listify(skip_dir), skip_dir_re, files, dirs)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def _rg_args(pattern, root, glob, include, exclude, ext, hidden, ignore, max_depth, min_depth, max_filesize,
|
|
89
|
-
follow_links, same_file_system, path_re, skip_path_re, skip_dir, skip_dir_re, case_sensitive, smart_case,
|
|
90
|
-
before_context, after_context, context):
|
|
91
|
-
include, exclude = _filters(glob, include, exclude, ext)
|
|
92
|
-
before_context, after_context = _context(context, before_context, after_context)
|
|
93
|
-
return (pattern, root, include, exclude, hidden, ignore, max_depth, min_depth, max_filesize, follow_links, same_file_system,
|
|
94
|
-
path_re, skip_path_re, _listify(skip_dir), skip_dir_re, case_sensitive, smart_case, before_context, after_context)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def rg(
|
|
98
|
-
pattern, # Regex pattern to search for
|
|
99
|
-
root=".", # Directory to search
|
|
100
|
-
glob=None, # Include glob or globs; alias for `include`
|
|
101
|
-
include=None, # Include glob or globs, e.g. `*.py`
|
|
102
|
-
exclude=None, # Exclude glob or globs, e.g. `test_*.py`
|
|
103
|
-
ext=None, # Extension or extensions to include, without needing `*.`
|
|
104
|
-
hidden=False, # Include hidden files and directories
|
|
105
|
-
ignore=True, # Respect `.gitignore` and other ignore files
|
|
106
|
-
max_depth=None, # Maximum directory depth to descend
|
|
107
|
-
min_depth=None, # Minimum depth for returned/searched files
|
|
108
|
-
max_filesize=None, # Skip files larger than this many bytes
|
|
109
|
-
follow_links=False, # Follow symbolic links while walking
|
|
110
|
-
same_file_system=False, # Do not cross filesystem boundaries
|
|
111
|
-
path_re=None, # Regex that searched relative paths must match
|
|
112
|
-
skip_path_re=None, # Regex for relative paths to skip
|
|
113
|
-
skip_dir=None, # Directory glob or globs to prune
|
|
114
|
-
skip_dir_re=None, # Directory regex used to prune traversal
|
|
115
|
-
case_sensitive=None, # True/False forces case; None allows `smart_case`
|
|
116
|
-
smart_case=False, # Match `rg --smart-case` behavior
|
|
117
|
-
before_context=0, # Lines of context before each match, like `rg -B`
|
|
118
|
-
after_context=0, # Lines of context after each match, like `rg -A`
|
|
119
|
-
context=0, # Sets both before and after context, like `rg -C`
|
|
120
|
-
paths=False, # Return unique matched paths instead of rows
|
|
121
|
-
count=False # Return total match span count instead of rows
|
|
122
|
-
):
|
|
123
|
-
"Search files and return `SearchResults`, matched paths, or a count."
|
|
124
|
-
assert not (paths and count), "paths and count are mutually exclusive"
|
|
125
|
-
args = _rg_args(pattern, root, glob, include, exclude, ext, hidden, ignore, max_depth, min_depth, max_filesize,
|
|
126
|
-
follow_links, same_file_system, path_re, skip_path_re, skip_dir, skip_dir_re, case_sensitive, smart_case,
|
|
127
|
-
before_context, after_context, context)
|
|
128
|
-
if paths:
|
|
129
|
-
seen, res = set(), []
|
|
130
|
-
for row in _core.rg_iter(*args):
|
|
131
|
-
if row.kind != "match" or row.path in seen: continue
|
|
132
|
-
seen.add(row.path)
|
|
133
|
-
res.append(row.path)
|
|
134
|
-
return res
|
|
135
|
-
if count: return sum(len(row.matches) for row in _core.rg_iter(*args) if row.kind == "match")
|
|
136
|
-
return SearchResults(_core.rg(*args))
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def rg_iter(
|
|
140
|
-
pattern, # Regex pattern to search for
|
|
141
|
-
root=".", # Directory to search
|
|
142
|
-
glob=None, # Include glob or globs; alias for `include`
|
|
143
|
-
include=None, # Include glob or globs, e.g. `*.py`
|
|
144
|
-
exclude=None, # Exclude glob or globs, e.g. `test_*.py`
|
|
145
|
-
ext=None, # Extension or extensions to include, without needing `*.`
|
|
146
|
-
hidden=False, # Include hidden files and directories
|
|
147
|
-
ignore=True, # Respect `.gitignore` and other ignore files
|
|
148
|
-
max_depth=None, # Maximum directory depth to descend
|
|
149
|
-
min_depth=None, # Minimum depth for returned/searched files
|
|
150
|
-
max_filesize=None, # Skip files larger than this many bytes
|
|
151
|
-
follow_links=False, # Follow symbolic links while walking
|
|
152
|
-
same_file_system=False, # Do not cross filesystem boundaries
|
|
153
|
-
path_re=None, # Regex that searched relative paths must match
|
|
154
|
-
skip_path_re=None, # Regex for relative paths to skip
|
|
155
|
-
skip_dir=None, # Directory glob or globs to prune
|
|
156
|
-
skip_dir_re=None, # Directory regex used to prune traversal
|
|
157
|
-
case_sensitive=None, # True/False forces case; None allows `smart_case`
|
|
158
|
-
smart_case=False, # Match `rg --smart-case` behavior
|
|
159
|
-
before_context=0, # Lines of context before each match, like `rg -B`
|
|
160
|
-
after_context=0, # Lines of context after each match, like `rg -A`
|
|
161
|
-
context=0 # Sets both before and after context, like `rg -C`
|
|
162
|
-
):
|
|
163
|
-
"Search files lazily, yielding `SearchLine` rows."
|
|
164
|
-
args = _rg_args(pattern, root, glob, include, exclude, ext, hidden, ignore, max_depth, min_depth, max_filesize,
|
|
165
|
-
follow_links, same_file_system, path_re, skip_path_re, skip_dir, skip_dir_re, case_sensitive, smart_case,
|
|
166
|
-
before_context, after_context, context)
|
|
167
|
-
return _core.rg_iter(*args)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
def search_text(
|
|
171
|
-
matcher, # Compiled `Regex` from `compile()`
|
|
172
|
-
text, # Text to search
|
|
173
|
-
path="<text>", # Path label stored in results
|
|
174
|
-
before_context=0, # Lines of context before each match
|
|
175
|
-
after_context=0, # Lines of context after each match
|
|
176
|
-
context=0 # Sets both before and after context, like `rg -C`
|
|
177
|
-
):
|
|
178
|
-
"Search an in-memory string with a compiled matcher."
|
|
179
|
-
before_context, after_context = _context(context, before_context, after_context)
|
|
180
|
-
return SearchResults(_core.search_text(matcher, text, path, before_context, after_context))
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
def search_path(
|
|
184
|
-
matcher, # Compiled `Regex` from `compile()`
|
|
185
|
-
path, # File path to search
|
|
186
|
-
display_path=None, # Path stored in results; defaults to `path`
|
|
187
|
-
before_context=0, # Lines of context before each match
|
|
188
|
-
after_context=0, # Lines of context after each match
|
|
189
|
-
context=0 # Sets both before and after context, like `rg -C`
|
|
190
|
-
):
|
|
191
|
-
"Search one file with a compiled matcher."
|
|
192
|
-
before_context, after_context = _context(context, before_context, after_context)
|
|
193
|
-
return SearchResults(_core.search_path(matcher, path, display_path, before_context, after_context))
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
__all__ = [
|
|
197
|
-
"Regex",
|
|
198
|
-
"RgIter",
|
|
199
|
-
"SearchLine",
|
|
200
|
-
"SearchResults",
|
|
201
|
-
"compile",
|
|
202
|
-
"fd",
|
|
203
|
-
"rg",
|
|
204
|
-
"rg_iter",
|
|
205
|
-
"search_path",
|
|
206
|
-
"search_text",
|
|
207
|
-
"walk",
|
|
208
|
-
]
|
rgapi-0.1.1/tools/build.sh
DELETED
rgapi-0.1.1/tools/bump.sh
DELETED
rgapi-0.1.1/tools/bump2.sh
DELETED
rgapi-0.1.1/tools/release.sh
DELETED
rgapi-0.1.1/tools/test.sh
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|