rgapi 0.2.2__tar.gz → 0.2.3__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.
Files changed (30) hide show
  1. {rgapi-0.2.2 → rgapi-0.2.3}/.github/workflows/ci.yml +1 -1
  2. {rgapi-0.2.2 → rgapi-0.2.3}/Cargo.lock +29 -40
  3. {rgapi-0.2.2 → rgapi-0.2.3}/Cargo.toml +2 -2
  4. {rgapi-0.2.2 → rgapi-0.2.3}/DEV.md +4 -4
  5. {rgapi-0.2.2 → rgapi-0.2.3}/PKG-INFO +15 -16
  6. {rgapi-0.2.2 → rgapi-0.2.3}/README.md +14 -15
  7. {rgapi-0.2.2 → rgapi-0.2.3}/py/Cargo.toml +2 -2
  8. {rgapi-0.2.2 → rgapi-0.2.3}/py/src/lib.rs +56 -217
  9. {rgapi-0.2.2 → rgapi-0.2.3}/python/rgapi/__init__.py +29 -43
  10. rgapi-0.2.3/rustfmt.toml +1 -0
  11. {rgapi-0.2.2 → rgapi-0.2.3}/src/block.rs +11 -30
  12. {rgapi-0.2.2 → rgapi-0.2.3}/src/matcher.rs +42 -10
  13. {rgapi-0.2.2 → rgapi-0.2.3}/src/nb.rs +13 -46
  14. {rgapi-0.2.2 → rgapi-0.2.3}/src/search.rs +23 -92
  15. {rgapi-0.2.2 → rgapi-0.2.3}/src/walk.rs +40 -99
  16. {rgapi-0.2.2 → rgapi-0.2.3}/tests/test_async.py +11 -10
  17. {rgapi-0.2.2 → rgapi-0.2.3}/tests/test_rgapi.py +67 -67
  18. rgapi-0.2.2/rustfmt.toml +0 -4
  19. {rgapi-0.2.2 → rgapi-0.2.3}/.gitignore +0 -0
  20. {rgapi-0.2.2 → rgapi-0.2.3}/LICENSE +0 -0
  21. {rgapi-0.2.2 → rgapi-0.2.3}/_config.yml +0 -0
  22. {rgapi-0.2.2 → rgapi-0.2.3}/_layouts/default.html +0 -0
  23. {rgapi-0.2.2 → rgapi-0.2.3}/py/build.rs +0 -0
  24. {rgapi-0.2.2 → rgapi-0.2.3}/pyproject.toml +0 -0
  25. {rgapi-0.2.2 → rgapi-0.2.3}/python/rgapi/_cli.py +0 -0
  26. {rgapi-0.2.2 → rgapi-0.2.3}/python/rgapi/block.py +0 -0
  27. {rgapi-0.2.2 → rgapi-0.2.3}/python/rgapi/nb.py +0 -0
  28. {rgapi-0.2.2 → rgapi-0.2.3}/python/rgapi/skill.py +0 -0
  29. {rgapi-0.2.2 → rgapi-0.2.3}/src/lib.rs +2 -2
  30. {rgapi-0.2.2 → rgapi-0.2.3}/tools/bench.py +0 -0
@@ -62,7 +62,7 @@ jobs:
62
62
  - uses: dtolnay/rust-toolchain@stable
63
63
  - id: crates-auth
64
64
  uses: rust-lang/crates-io-auth-action@v1
65
- - run: cargo publish -p rgapi
65
+ - run: cargo publish -p rgapi --no-verify
66
66
  env:
67
67
  CARGO_REGISTRY_TOKEN: ${{ steps.crates-auth.outputs.token }}
68
68
  - uses: actions/download-artifact@v8
@@ -50,9 +50,9 @@ checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48"
50
50
 
51
51
  [[package]]
52
52
  name = "crc32fast"
53
- version = "1.5.2"
53
+ version = "1.5.3"
54
54
  source = "registry+https://github.com/rust-lang/crates.io-index"
55
- checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78"
55
+ checksum = "0ba106e844045ddc02c20768ac4b0b7cb45f2cc2ecbd833ac9f5dacb183c2055"
56
56
  dependencies = [
57
57
  "cfg-if",
58
58
  ]
@@ -107,9 +107,9 @@ dependencies = [
107
107
 
108
108
  [[package]]
109
109
  name = "fancy-regex"
110
- version = "0.19.2"
110
+ version = "0.20.0"
111
111
  source = "registry+https://github.com/rust-lang/crates.io-index"
112
- checksum = "d301f5bf187b3c295fce6468d3875037a0bccc5f6b151c63cac2f85babf21912"
112
+ checksum = "20ed7f62ce0ae0da1a8b93c3c7104ab7e0760a74491e097c701fff966e945390"
113
113
  dependencies = [
114
114
  "bit-set",
115
115
  "regex-automata",
@@ -183,9 +183,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
183
183
 
184
184
  [[package]]
185
185
  name = "libc"
186
- version = "0.2.190"
186
+ version = "0.2.191"
187
187
  source = "registry+https://github.com/rust-lang/crates.io-index"
188
- checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
188
+ checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a"
189
189
 
190
190
  [[package]]
191
191
  name = "log"
@@ -201,9 +201,9 @@ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
201
201
 
202
202
  [[package]]
203
203
  name = "memmap2"
204
- version = "0.9.11"
204
+ version = "0.9.12"
205
205
  source = "registry+https://github.com/rust-lang/crates.io-index"
206
- checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0"
206
+ checksum = "6b0ca1155a9ecc25aa12e8313a119f32edf0255fea2f44839c4ac0a12b2ac157"
207
207
  dependencies = [
208
208
  "libc",
209
209
  ]
@@ -237,9 +237,9 @@ dependencies = [
237
237
 
238
238
  [[package]]
239
239
  name = "pyo3"
240
- version = "0.29.3"
240
+ version = "0.30.1"
241
241
  source = "registry+https://github.com/rust-lang/crates.io-index"
242
- checksum = "700d18fa267b73b9b521fd7e13580e2f446916f176cacee1ab63fcc8191f1655"
242
+ checksum = "229ca13b8a15bb0d1487b81ab975bfcd97513416499a8312011b6036e42e0de4"
243
243
  dependencies = [
244
244
  "libc",
245
245
  "once_cell",
@@ -251,18 +251,18 @@ dependencies = [
251
251
 
252
252
  [[package]]
253
253
  name = "pyo3-build-config"
254
- version = "0.29.3"
254
+ version = "0.30.1"
255
255
  source = "registry+https://github.com/rust-lang/crates.io-index"
256
- checksum = "7b3fc0c4d08f6bb10e71fe39dfb9e2f59c6eb6854e22ec8092f50c69a4499adb"
256
+ checksum = "70130e2b6dd1ee589a8788026a429561ca5c40fa7a2fa7914c2282eddae24700"
257
257
  dependencies = [
258
258
  "target-lexicon",
259
259
  ]
260
260
 
261
261
  [[package]]
262
262
  name = "pyo3-ffi"
263
- version = "0.29.3"
263
+ version = "0.30.1"
264
264
  source = "registry+https://github.com/rust-lang/crates.io-index"
265
- checksum = "dfc0b8e19df29aad7086cf977bb0c2a2f143e30567eb113e9cf72b62ca698330"
265
+ checksum = "5e7ff73c555c286d212d4ce7e5fbda845a973c4f61bd5f160f5f2c3c2a04d1c4"
266
266
  dependencies = [
267
267
  "libc",
268
268
  "pyo3-build-config",
@@ -270,26 +270,26 @@ dependencies = [
270
270
 
271
271
  [[package]]
272
272
  name = "pyo3-macros"
273
- version = "0.29.3"
273
+ version = "0.30.1"
274
274
  source = "registry+https://github.com/rust-lang/crates.io-index"
275
- checksum = "6100e8a4b5eba53afaa5ed078364851a0b2499c553a44c31026b929049b49dc6"
275
+ checksum = "c46d2e5862c7bb8207e3b639f713dda3c499933444784154c11d013c5a691b60"
276
276
  dependencies = [
277
277
  "proc-macro2",
278
278
  "pyo3-macros-backend",
279
279
  "quote",
280
- "syn 2.0.119",
280
+ "syn",
281
281
  ]
282
282
 
283
283
  [[package]]
284
284
  name = "pyo3-macros-backend"
285
- version = "0.29.3"
285
+ version = "0.30.1"
286
286
  source = "registry+https://github.com/rust-lang/crates.io-index"
287
- checksum = "6143877a16e82b5a727b7127ff4cd86858a24a28d745d72f43e6f227c7b1bdb3"
287
+ checksum = "38b89f066f2ae72a2aef52d1537ca2fcd104440ebfadee06e97aa90738a25b9b"
288
288
  dependencies = [
289
289
  "heck",
290
290
  "proc-macro2",
291
291
  "quote",
292
- "syn 2.0.119",
292
+ "syn",
293
293
  ]
294
294
 
295
295
  [[package]]
@@ -320,7 +320,7 @@ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
320
320
 
321
321
  [[package]]
322
322
  name = "rgapi"
323
- version = "0.2.2"
323
+ version = "0.2.3"
324
324
  dependencies = [
325
325
  "crc32fast",
326
326
  "fancy-regex",
@@ -335,7 +335,7 @@ dependencies = [
335
335
 
336
336
  [[package]]
337
337
  name = "rgapi-py"
338
- version = "0.2.2"
338
+ version = "0.2.3"
339
339
  dependencies = [
340
340
  "grep-matcher",
341
341
  "pyo3",
@@ -391,14 +391,14 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
391
391
  dependencies = [
392
392
  "proc-macro2",
393
393
  "quote",
394
- "syn 3.0.6",
394
+ "syn",
395
395
  ]
396
396
 
397
397
  [[package]]
398
398
  name = "serde_json"
399
- version = "1.0.151"
399
+ version = "1.0.154"
400
400
  source = "registry+https://github.com/rust-lang/crates.io-index"
401
- checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
401
+ checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6"
402
402
  dependencies = [
403
403
  "itoa",
404
404
  "memchr",
@@ -415,20 +415,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
415
415
 
416
416
  [[package]]
417
417
  name = "syn"
418
- version = "2.0.119"
418
+ version = "3.0.9"
419
419
  source = "registry+https://github.com/rust-lang/crates.io-index"
420
- checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
421
- dependencies = [
422
- "proc-macro2",
423
- "quote",
424
- "unicode-ident",
425
- ]
426
-
427
- [[package]]
428
- name = "syn"
429
- version = "3.0.6"
430
- source = "registry+https://github.com/rust-lang/crates.io-index"
431
- checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
420
+ checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
432
421
  dependencies = [
433
422
  "proc-macro2",
434
423
  "quote",
@@ -443,9 +432,9 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
443
432
 
444
433
  [[package]]
445
434
  name = "unicode-ident"
446
- version = "1.0.26"
435
+ version = "1.0.27"
447
436
  source = "registry+https://github.com/rust-lang/crates.io-index"
448
- checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
437
+ checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
449
438
 
450
439
  [[package]]
451
440
  name = "walkdir"
@@ -2,7 +2,7 @@
2
2
  members = ["py"]
3
3
 
4
4
  [workspace.package]
5
- version = "0.2.2"
5
+ version = "0.2.3"
6
6
  edition = "2024"
7
7
 
8
8
  [workspace.dependencies]
@@ -24,7 +24,7 @@ name = "rgapi"
24
24
 
25
25
  [dependencies]
26
26
  crc32fast = "1"
27
- fancy-regex = "0.19"
27
+ fancy-regex = ">=0.20"
28
28
  globset = ">=0.4.18"
29
29
  grep-matcher.workspace = true
30
30
  grep-searcher = ">=0.1.16"
@@ -23,7 +23,7 @@ cargo develop
23
23
  pytest -q
24
24
  ```
25
25
 
26
- `cargo develop` and bare `cargo test` use the same Cargo profile and share the core and binding libraries. Unit tests also build a separate `cfg(test)` executable. The published `rgapi` crate has no Python dependency; the unpublished `rgapi-py` crate in `py/` builds the extension. Run `cargo fmt` after Rust edits and `chkstyle` before committing Python edits.
26
+ `cargo develop` and bare `cargo test` use the same Cargo profile and share the core and binding libraries. Unit tests also build a separate `cfg(test)` executable. The published `rgapi` crate has no Python dependency; the unpublished `rgapi-py` crate in `py/` builds the extension. Run `cargo fastfmt` after Rust edits and `chkstyle` before committing Python edits.
27
27
 
28
28
  ## Release
29
29
 
@@ -41,7 +41,7 @@ The GitHub workflow builds wheels for Python 3.10-3.13 on Linux and macOS and pu
41
41
 
42
42
  All user-supplied regexes use the shared `RegexMatcher` in `src/matcher.rs`, backed by `fancy-regex`. There is no separate fallback engine or native C dependency. The adapter implements `grep_matcher::Matcher` so `grep-searcher` continues to handle file scanning, line numbers, context, and binary detection. `compile_regex` returns rgapi's own exported `RegexMatcher` type.
43
43
 
44
- The matcher centralizes smart-case analysis and line-ending policy. Line-safe patterns can search a whole buffer; patterns that can consume line endings or inspect neighbouring lines are evaluated on individual lines. Notebook multiline matching instead uses the whole cell. Filename/path regexes match their whole input. Backtracking-limit errors propagate through the existing result channels, including directory-pruning errors; cancellation must not hide a queued error from async consumers.
44
+ The matcher centralizes smart-case analysis and line-ending policy. Line-safe patterns can search a whole buffer; patterns that can consume line endings, inspect neighbouring lines or need the backtracking engine are evaluated on individual lines, so that engine's step budget covers one line, not a whole buffer. Notebook multiline matching instead uses the whole cell. Filename/path regexes match their whole input. Backtracking-limit errors propagate through the existing result channels, including directory-pruning errors; cancellation must not hide a queued error from async consumers.
45
45
 
46
46
  Python discovery and `paths=True` results contain absolute `pathlib.Path` objects. Structured search rows hold base-relative string labels with `/` separators. Traversal uses `ignore::WalkParallel`, so result order is not part of the API contract. Search results are structured rows; collected result lists use rg-style `str()` and notebook display. `SearchLine.lnhash` is computed with the same CRC-32-based line-content hash format as exhash (`lineno|hash|`, low 12 bits of CRC-32 over the line's UTF-8 bytes, encoded as two Base64url characters); `lnhashs=True` only changes row display, not `line_number` or matching behavior. Path regexes filter returned/searched paths; `skip_dir` and `skip_dir_re` prune traversal through `ignore::WalkBuilder::filter_entry`. Depth, size, filesystem, hidden, and ignore options use `ignore::WalkBuilder` settings. The `ignore` walker follows every root it is given. Discovery checks each root with `symlink_metadata`. The worker sends each unfollowed link root as a result before walking the other roots. This also supports dangling roots, which the underlying walker would reject. `ls` sets `walk_root_links`, which gives a root link to a directory to the walker. The walker then reports paths under the link. Other discovery roots use absolute paths without canonicalizing. Content searches retain canonical root resolution. `rg_iter` exposes the same parallel search stream that `rg` collects by default; `paths=True` and `count=True` consume that stream with different reducers. Text search skips binary files and invalid UTF-8 content.
47
47
 
@@ -51,9 +51,9 @@ Streaming engine: `walk.rs` owns the generic machinery. `StreamIter<T>` is the w
51
51
 
52
52
  Async API: `fda`, `fda_iter`, `rga`, `rga_iter`, `nbrga`, and `nbrga_iter` wrap the corresponding private core operations. `rga(summary=True)` uses `_core.block_search_async`; ordinary `rga` uses `_core.rg_async`. Each collected core function takes a Python callback, runs on Rust threads through the generic `stream_async` helper, and delivers with one GIL attach at the end. Iterator forms use `stream_iter_async` and attach once per batch. The Python side settles an `asyncio.Future` or feeds an `asyncio.Queue` via `loop.call_soon_threadsafe`; no Python thread blocks and `asyncio.to_thread` is not involved. `AsyncHandle.cancel()` sets the same atomic flag used by the Rust iterators.
53
53
 
54
- Truncation is recorded on collected results: `max_results` sets `stop_reason="max_results"`, and `timeout_ms` on `rg`/`rga`/`nbrg`/`nbrga`/`fd`/`fda`/`walk`/`ls` sets `stop_reason="timeout"`. `SearchResults`, `BlockResults`, `PathResults`, and `NbResults` share this through `_Results`; `complete` means `stop_reason is None`. In block summary mode, `max_results` counts matching blocks and keeps their block context. `count=True` returns a plain int, so it rejects timeouts and block summary mode.
54
+ Truncation is recorded on collected results: `max_results` sets `stop_reason="max_results"`, and `timeout_ms` on `rg`/`rga`/`nbrg`/`nbrga`/`fd`/`fda`/`ls` sets `stop_reason="timeout"`. `SearchResults`, `BlockResults`, `PathResults`, and `NbResults` share this through `_Results`; `complete` means `stop_reason is None`. In block summary mode, `max_results` counts matching blocks and keeps their block context. `count` returns a plain int, or a dict for `count="file"`, so it rejects timeouts and block summary mode.
55
55
 
56
- Rust discovery returns base-relative `PathBuf` values. Glob filters operate on native paths; only regex matching uses string labels. PyO3 converts discovery roots and results with its filesystem-path support. Python joins each result to the base from `_core.walk_base` without resolving links. `PathResults` stores that display base and completion status, including across slices. Its `__repr__` uses `Path.lstat()` for an `ls -l`-style listing capped at `MAX_REPR` rows. `str()` returns one base-relative name per line. `ls` is `fd` with shell-style defaults (one level, dirs, ignore rules off) and `walk_root_links`, sorted in place.
56
+ Rust discovery returns base-relative `PathBuf` values. Glob filters operate on native paths; only regex matching uses string labels. PyO3 converts discovery roots and results with its filesystem-path support. Python joins each result to the base from `_core.walk_base` without resolving links. `PathResults` stores that display base and completion status, including across slices. Its `__repr__` uses `Path.lstat()` for an `ls -l`-style listing capped at `MAX_REPR` rows. `str()` returns one base-relative name per line. `ls` is `fd` with shell-style defaults (one level, dirs, ignore rules off) and `walk_root_links`, sorted in place. `fd` takes `pattern` first, as `rg` does. `ls` takes `root` first, as the shell's `ls DIR` does.
57
57
 
58
58
  Rust callers can consume a `StreamIter` with `cancel_and_join()` to cancel, drain queued results, and wait for the walk's workers to finish. `Drop` remains nonblocking. Since filesystem calls already in progress must return before joining completes, keep `cancel_and_join()` off async executors.
59
59
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rgapi
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Requires-Dist: fastcore>=2.2.29
@@ -32,7 +32,7 @@ For common file discovery and search:
32
32
  ```python
33
33
  from rgapi import fd, ls, rg, rg_iter
34
34
 
35
- fd(".", ext="py", exclude="test_*.py")
35
+ fd(ext="py", exclude="test_*.py")
36
36
  ls("src")
37
37
  for row in rg_iter("TODO", ".", include="*.py", context=2): print(row.asdict())
38
38
  rg("TODO", ".", ext="py", skip_dir=".venv", paths=True)
@@ -56,16 +56,15 @@ await rga("TODO", ".", ext="py", timeout_ms=200)
56
56
  async for row in rga_iter("TODO", "."): print(row)
57
57
  ```
58
58
 
59
- Use the lower-level functions to compile a regex, search text or a single file, or walk a directory:
59
+ Use the lower-level functions to compile a regex, or to search text or a single file:
60
60
 
61
61
  ```python
62
- from rgapi import compile, search_path, search_text, walk
62
+ from rgapi import compile, search_path, search_text
63
63
 
64
64
  matcher = compile("TODO")
65
65
  matcher.is_match("TODO")
66
66
  matcher.finditer("TODO TODO")
67
67
 
68
- walk(".")
69
68
  search_text(matcher, "alpha\nTODO\nomega\n", path="memory.txt", context=1)
70
69
  search_path(matcher, "src/lib.rs", display_path="src/lib.rs")
71
70
  ```
@@ -78,7 +77,7 @@ pip install rgapi
78
77
 
79
78
  ## File discovery
80
79
 
81
- `fd` and `walk` return absolute `pathlib.Path` objects. Use them directly with `.read_text()`, `.open()`, `.stat()`, or other filesystem operations. Their collected results display names relative to `root`. Pass `root` as a `str` or `Path`, or as a list of them. The sync and async APIs expand `~` and accept `.`, `./`, and paths containing `..`.
80
+ `fd` returns absolute `pathlib.Path` objects. Use them directly with `.read_text()`, `.open()`, `.stat()`, or other filesystem operations. Its collected results display names relative to `root`. Pass `root` as a `str` or `Path`, or as a list of them. The sync and async APIs expand `~` and accept `.`, `./`, and paths containing `..`.
82
81
 
83
82
  A list of roots, such as `rg("TODO", ["src", "tests"])`, works with every walk and search function. The roots are searched as one walk that returns one result list. `timeout_ms` and `max_results` apply to the whole walk. Result paths are relative to the common ancestor of the roots. For example, rows read `src/app.py` and `tests/test_app.py`. `PathResults` displays use the same relative paths. Filters such as `include`, `path_re` and `skip_dir` match these relative paths. A file under more than one root, such as `src/app.py` with roots `[".", "src"]`, appears once.
84
83
 
@@ -88,7 +87,7 @@ Hidden files are skipped unless `hidden=True`. Discovery returns symlinks themse
88
87
 
89
88
  Traversal runs in parallel without guaranteed result order. Use `sorted(...)` when order matters.
90
89
 
91
- `fd` adds filename filters to `walk`. Its `pattern` is a smart-case regex matched against each basename. Lowercase patterns match case-insensitively. A pattern containing uppercase letters is case-sensitive. Use `path_re` to match the slash-separated relative path instead.
90
+ `fd` takes `pattern` first and `root` second, as `rg` does. With no pattern, it returns every file under `root`. `pattern` is a smart-case regex matched against each basename. Lowercase patterns match case-insensitively. A pattern containing uppercase letters is case-sensitive. Use `path_re` to match the slash-separated relative path instead.
92
91
 
93
92
  `include` and `exclude` use case-sensitive glob syntax. `glob=` is an alias for `include=`. Patterns without `/` match names at any depth, so `*.py` matches `src/app.py`. Patterns containing `/` are root-relative. `*` stays within a path component; `**` spans directories: `src/*` matches immediate children, whereas `src/**` also matches deeper descendants. Matching a directory with `exclude` prunes its entire subtree. Includes never prune traversal. Excludes always win, and includes do not override ignore rules.
94
93
 
@@ -96,7 +95,7 @@ Filter extensions with `ext="py"` or `ext=["py", "rs"]`. Extension and glob filt
96
95
 
97
96
  Set `min_depth` and `max_depth` to bound recursion. `max_filesize` skips files above a byte limit.
98
97
 
99
- `ls` follows the shell command's listing conventions. It uses `fd` with `max_depth=1`, includes directories, disables ignore rules, and sorts by name. Set `hidden=True` for `ls -a` behaviour. All `fd` filters remain available.
98
+ `ls` follows the shell command's listing conventions. It takes `root` first, as the shell's `ls DIR` does. It uses `fd` with `max_depth=1`, includes directories, disables ignore rules, and sorts by name. Set `hidden=True` for `ls -a` behaviour. All `fd` filters remain available.
100
99
 
101
100
  `fd_iter` yields absolute `Path` objects as the walk finds them. It accepts every `fd` filter. Stopping iteration ends the walk. It does not accept `timeout_ms`.
102
101
 
@@ -113,10 +112,10 @@ Patterns support backreferences and lookaround everywhere, including filename an
113
112
  ```python
114
113
  rg(r"\b(\w+)\s+\1\b", ".") # repeated words
115
114
  rg(r"(?<=TODO: )\w+", ".") # word following TODO:
116
- fd(".", pattern=r"^(\w+)_\1\.py$") # names such as utils_utils.py
115
+ fd(r"^(\w+)_\1\.py$") # names such as utils_utils.py
117
116
  ```
118
117
 
119
- All regex parameters use `fancy-regex`; no engine-selection flag or C library is required. Ordinary patterns use its non-backtracking engine. Patterns requiring backtracking have a bounded backtracking budget; exceeding it raises `ValueError`, rather than silently skipping a file or path.
118
+ All regex parameters use `fancy-regex`, with no engine-selection flag and no C library. Ordinary patterns, including word boundaries (`\b`, `\B`) outside lookbehinds, use its non-backtracking engine. Patterns requiring backtracking have a step budget that allows lines of millions of characters. A search that exceeds the budget raises `ValueError`. It never silently skips a file or path.
120
119
 
121
120
  Each `SearchLine` has these fields:
122
121
 
@@ -135,7 +134,7 @@ matches list of (start, end) byte offsets for match rows
135
134
 
136
135
  Pass `lnhashs=True` to `rg` or `rg_iter` to display hash addresses instead of line numbers. The `line_number` field remains available.
137
136
 
138
- For other result forms, use `rg(..., paths=True)` to return unique matched paths or `rg(..., count=True)` to count match spans. `paths` and `count` cannot both be set.
137
+ For other result forms, use `rg(..., paths=True)` to return unique matched paths, `rg(..., count=True)` to count match spans, or `rg(..., count="file")` for a dict from each file's label to its count, sorted by label. `paths` and `count` cannot both be set.
139
138
 
140
139
  `^` and `$` match at the start and end of each line. A line ends at `\n` or `\r\n`. `$` also matches before a `\r` that has no `\n` after it. `rg`, `rgstr`, and `compile` reject patterns containing a literal `\n` or `\r`. `nbrg` allows them with `multiline=True`.
141
140
 
@@ -143,10 +142,10 @@ Content searches and compiled content matchers are confined to individual lines:
143
142
 
144
143
  ### Path results
145
144
 
146
- `fd`, `walk`, and `ls` return `PathResults`, a list of absolute `Path` objects. So do `rg` and `nbrg` with `paths=True`, and their async equivalents. Indexing or iterating returns ordinary Paths:
145
+ `fd` and `ls` return `PathResults`, a list of absolute `Path` objects. So do `rg` and `nbrg` with `paths=True`, and their async equivalents. Indexing or iterating returns ordinary Paths:
147
146
 
148
147
  ```python
149
- for path in fd("src", ext="py"):
148
+ for path in fd(root="src", ext="py"):
150
149
  text = path.read_text()
151
150
  size = path.stat().st_size
152
151
  ```
@@ -163,13 +162,13 @@ Rust callers can set `FindOptions::special_files` to also discover FIFOs, socket
163
162
 
164
163
  ### Limits and timeouts
165
164
 
166
- Set `timeout_ms` on `rg`, `fd`, `walk`, or `ls` to stop at a deadline and return the results collected so far. Their async versions accept it too. Results report why the operation stopped:
165
+ Set `timeout_ms` on `rg`, `fd` or `ls` to stop at a deadline and return the results collected so far. Their async versions accept it too. Results report why the operation stopped:
167
166
 
168
167
  - `stop_reason=None` means the result is complete.
169
168
  - `stop_reason="max_results"` means `max_results` truncated the result.
170
169
  - `stop_reason="timeout"` means the deadline was reached.
171
170
 
172
- `complete` is true exactly when `stop_reason` is `None`. `count=True` returns a plain integer without a completion flag. It cannot be combined with `timeout_ms`.
171
+ `complete` is true exactly when `stop_reason` is `None`. A count is a plain integer or dict, with no completion flag. Counting can't be combined with `timeout_ms`.
173
172
 
174
173
  Deadlines stop result collection and request worker cancellation. Workers cannot interrupt a regex evaluation or filesystem call already in progress; a timeout is not a hard per-match execution limit.
175
174
 
@@ -256,7 +255,7 @@ Run `rgapi-nbrg --help` for its discovery, matching, and output options.
256
255
  ```python
257
256
  from rgapi import fda, rga, rga_iter
258
257
 
259
- await fda(".", ext="py")
258
+ await fda(ext="py")
260
259
  res = await rga("TODO", ".", timeout_ms=200)
261
260
  if not res.complete: print(f"partial results: {res.stop_reason}")
262
261
  async for row in rga_iter("TODO", "."): ...
@@ -11,7 +11,7 @@ For common file discovery and search:
11
11
  ```python
12
12
  from rgapi import fd, ls, rg, rg_iter
13
13
 
14
- fd(".", ext="py", exclude="test_*.py")
14
+ fd(ext="py", exclude="test_*.py")
15
15
  ls("src")
16
16
  for row in rg_iter("TODO", ".", include="*.py", context=2): print(row.asdict())
17
17
  rg("TODO", ".", ext="py", skip_dir=".venv", paths=True)
@@ -35,16 +35,15 @@ await rga("TODO", ".", ext="py", timeout_ms=200)
35
35
  async for row in rga_iter("TODO", "."): print(row)
36
36
  ```
37
37
 
38
- Use the lower-level functions to compile a regex, search text or a single file, or walk a directory:
38
+ Use the lower-level functions to compile a regex, or to search text or a single file:
39
39
 
40
40
  ```python
41
- from rgapi import compile, search_path, search_text, walk
41
+ from rgapi import compile, search_path, search_text
42
42
 
43
43
  matcher = compile("TODO")
44
44
  matcher.is_match("TODO")
45
45
  matcher.finditer("TODO TODO")
46
46
 
47
- walk(".")
48
47
  search_text(matcher, "alpha\nTODO\nomega\n", path="memory.txt", context=1)
49
48
  search_path(matcher, "src/lib.rs", display_path="src/lib.rs")
50
49
  ```
@@ -57,7 +56,7 @@ pip install rgapi
57
56
 
58
57
  ## File discovery
59
58
 
60
- `fd` and `walk` return absolute `pathlib.Path` objects. Use them directly with `.read_text()`, `.open()`, `.stat()`, or other filesystem operations. Their collected results display names relative to `root`. Pass `root` as a `str` or `Path`, or as a list of them. The sync and async APIs expand `~` and accept `.`, `./`, and paths containing `..`.
59
+ `fd` returns absolute `pathlib.Path` objects. Use them directly with `.read_text()`, `.open()`, `.stat()`, or other filesystem operations. Its collected results display names relative to `root`. Pass `root` as a `str` or `Path`, or as a list of them. The sync and async APIs expand `~` and accept `.`, `./`, and paths containing `..`.
61
60
 
62
61
  A list of roots, such as `rg("TODO", ["src", "tests"])`, works with every walk and search function. The roots are searched as one walk that returns one result list. `timeout_ms` and `max_results` apply to the whole walk. Result paths are relative to the common ancestor of the roots. For example, rows read `src/app.py` and `tests/test_app.py`. `PathResults` displays use the same relative paths. Filters such as `include`, `path_re` and `skip_dir` match these relative paths. A file under more than one root, such as `src/app.py` with roots `[".", "src"]`, appears once.
63
62
 
@@ -67,7 +66,7 @@ Hidden files are skipped unless `hidden=True`. Discovery returns symlinks themse
67
66
 
68
67
  Traversal runs in parallel without guaranteed result order. Use `sorted(...)` when order matters.
69
68
 
70
- `fd` adds filename filters to `walk`. Its `pattern` is a smart-case regex matched against each basename. Lowercase patterns match case-insensitively. A pattern containing uppercase letters is case-sensitive. Use `path_re` to match the slash-separated relative path instead.
69
+ `fd` takes `pattern` first and `root` second, as `rg` does. With no pattern, it returns every file under `root`. `pattern` is a smart-case regex matched against each basename. Lowercase patterns match case-insensitively. A pattern containing uppercase letters is case-sensitive. Use `path_re` to match the slash-separated relative path instead.
71
70
 
72
71
  `include` and `exclude` use case-sensitive glob syntax. `glob=` is an alias for `include=`. Patterns without `/` match names at any depth, so `*.py` matches `src/app.py`. Patterns containing `/` are root-relative. `*` stays within a path component; `**` spans directories: `src/*` matches immediate children, whereas `src/**` also matches deeper descendants. Matching a directory with `exclude` prunes its entire subtree. Includes never prune traversal. Excludes always win, and includes do not override ignore rules.
73
72
 
@@ -75,7 +74,7 @@ Filter extensions with `ext="py"` or `ext=["py", "rs"]`. Extension and glob filt
75
74
 
76
75
  Set `min_depth` and `max_depth` to bound recursion. `max_filesize` skips files above a byte limit.
77
76
 
78
- `ls` follows the shell command's listing conventions. It uses `fd` with `max_depth=1`, includes directories, disables ignore rules, and sorts by name. Set `hidden=True` for `ls -a` behaviour. All `fd` filters remain available.
77
+ `ls` follows the shell command's listing conventions. It takes `root` first, as the shell's `ls DIR` does. It uses `fd` with `max_depth=1`, includes directories, disables ignore rules, and sorts by name. Set `hidden=True` for `ls -a` behaviour. All `fd` filters remain available.
79
78
 
80
79
  `fd_iter` yields absolute `Path` objects as the walk finds them. It accepts every `fd` filter. Stopping iteration ends the walk. It does not accept `timeout_ms`.
81
80
 
@@ -92,10 +91,10 @@ Patterns support backreferences and lookaround everywhere, including filename an
92
91
  ```python
93
92
  rg(r"\b(\w+)\s+\1\b", ".") # repeated words
94
93
  rg(r"(?<=TODO: )\w+", ".") # word following TODO:
95
- fd(".", pattern=r"^(\w+)_\1\.py$") # names such as utils_utils.py
94
+ fd(r"^(\w+)_\1\.py$") # names such as utils_utils.py
96
95
  ```
97
96
 
98
- All regex parameters use `fancy-regex`; no engine-selection flag or C library is required. Ordinary patterns use its non-backtracking engine. Patterns requiring backtracking have a bounded backtracking budget; exceeding it raises `ValueError`, rather than silently skipping a file or path.
97
+ All regex parameters use `fancy-regex`, with no engine-selection flag and no C library. Ordinary patterns, including word boundaries (`\b`, `\B`) outside lookbehinds, use its non-backtracking engine. Patterns requiring backtracking have a step budget that allows lines of millions of characters. A search that exceeds the budget raises `ValueError`. It never silently skips a file or path.
99
98
 
100
99
  Each `SearchLine` has these fields:
101
100
 
@@ -114,7 +113,7 @@ matches list of (start, end) byte offsets for match rows
114
113
 
115
114
  Pass `lnhashs=True` to `rg` or `rg_iter` to display hash addresses instead of line numbers. The `line_number` field remains available.
116
115
 
117
- For other result forms, use `rg(..., paths=True)` to return unique matched paths or `rg(..., count=True)` to count match spans. `paths` and `count` cannot both be set.
116
+ For other result forms, use `rg(..., paths=True)` to return unique matched paths, `rg(..., count=True)` to count match spans, or `rg(..., count="file")` for a dict from each file's label to its count, sorted by label. `paths` and `count` cannot both be set.
118
117
 
119
118
  `^` and `$` match at the start and end of each line. A line ends at `\n` or `\r\n`. `$` also matches before a `\r` that has no `\n` after it. `rg`, `rgstr`, and `compile` reject patterns containing a literal `\n` or `\r`. `nbrg` allows them with `multiline=True`.
120
119
 
@@ -122,10 +121,10 @@ Content searches and compiled content matchers are confined to individual lines:
122
121
 
123
122
  ### Path results
124
123
 
125
- `fd`, `walk`, and `ls` return `PathResults`, a list of absolute `Path` objects. So do `rg` and `nbrg` with `paths=True`, and their async equivalents. Indexing or iterating returns ordinary Paths:
124
+ `fd` and `ls` return `PathResults`, a list of absolute `Path` objects. So do `rg` and `nbrg` with `paths=True`, and their async equivalents. Indexing or iterating returns ordinary Paths:
126
125
 
127
126
  ```python
128
- for path in fd("src", ext="py"):
127
+ for path in fd(root="src", ext="py"):
129
128
  text = path.read_text()
130
129
  size = path.stat().st_size
131
130
  ```
@@ -142,13 +141,13 @@ Rust callers can set `FindOptions::special_files` to also discover FIFOs, socket
142
141
 
143
142
  ### Limits and timeouts
144
143
 
145
- Set `timeout_ms` on `rg`, `fd`, `walk`, or `ls` to stop at a deadline and return the results collected so far. Their async versions accept it too. Results report why the operation stopped:
144
+ Set `timeout_ms` on `rg`, `fd` or `ls` to stop at a deadline and return the results collected so far. Their async versions accept it too. Results report why the operation stopped:
146
145
 
147
146
  - `stop_reason=None` means the result is complete.
148
147
  - `stop_reason="max_results"` means `max_results` truncated the result.
149
148
  - `stop_reason="timeout"` means the deadline was reached.
150
149
 
151
- `complete` is true exactly when `stop_reason` is `None`. `count=True` returns a plain integer without a completion flag. It cannot be combined with `timeout_ms`.
150
+ `complete` is true exactly when `stop_reason` is `None`. A count is a plain integer or dict, with no completion flag. Counting can't be combined with `timeout_ms`.
152
151
 
153
152
  Deadlines stop result collection and request worker cancellation. Workers cannot interrupt a regex evaluation or filesystem call already in progress; a timeout is not a hard per-match execution limit.
154
153
 
@@ -235,7 +234,7 @@ Run `rgapi-nbrg --help` for its discovery, matching, and output options.
235
234
  ```python
236
235
  from rgapi import fda, rga, rga_iter
237
236
 
238
- await fda(".", ext="py")
237
+ await fda(ext="py")
239
238
  res = await rga("TODO", ".", timeout_ms=200)
240
239
  if not res.complete: print(f"partial results: {res.stop_reason}")
241
240
  async for row in rga_iter("TODO", "."): ...
@@ -11,7 +11,7 @@ test = false
11
11
  [dependencies]
12
12
  rgapi = { path = ".." }
13
13
  grep-matcher.workspace = true
14
- pyo3 = { version = ">=0.29", features = ["extension-module"] }
14
+ pyo3 = { version = ">=0.30", features = ["extension-module"] }
15
15
 
16
16
  [build-dependencies]
17
- pyo3-build-config = "0.29"
17
+ pyo3-build-config = ">=0.29"