diffctx 1.10.0__tar.gz → 1.10.2__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.
- {diffctx-1.10.0 → diffctx-1.10.2}/PKG-INFO +1 -1
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/Cargo.lock +22 -56
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/Cargo.toml +3 -3
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/git.rs +129 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/main.rs +47 -11
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/memory_pipeline.rs +1 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/parsers/markdown.rs +54 -13
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/pipeline.rs +43 -2
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/postpass.rs +105 -2
- {diffctx-1.10.0 → diffctx-1.10.2}/pyproject.toml +1 -1
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/cli.py +26 -5
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/ignore.py +16 -3
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/main.py +32 -11
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/mcp/__main__.py +8 -1
- diffctx-1.10.2/src/diffctx/version.py +1 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/writer.py +39 -25
- diffctx-1.10.0/src/diffctx/version.py +0 -1
- {diffctx-1.10.0 → diffctx-1.10.2}/CHANGELOG.md +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/LICENSE +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/README.md +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/analytics.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/candidate_files.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/analytics.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/bm25.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/budget.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/category_weights.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/edge_weights.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/env_overrides.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/extensions.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/filtering.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/fragmentation.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/git.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/graph_filtering.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/importance.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/limits.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/mod.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/mode.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/needs.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/parsers.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/render.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/scoring.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/selection.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/tokenization.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/config/weights.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/core.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/discovery.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/base.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/config_edges/build_system.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/config_edges/cicd.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/config_edges/docker.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/config_edges/generic.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/config_edges/helm.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/config_edges/kubernetes.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/config_edges/mod.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/document/mod.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/history/cochange.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/history/mod.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/mod.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/ansible.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/bazel.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/c_family.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/cargo_edges.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/clojure.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/css.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/dart.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/dbt.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/dotnet.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/elixir.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/erlang.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/go.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/graphql.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/haskell.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/javascript.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/julia.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/jvm.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/latex.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/lua.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/mod.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/nim.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/nix.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/ocaml.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/openapi.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/perl.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/php.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/prisma.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/protobuf.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/python.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/r_lang.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/ruby.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/rust_lang.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/shell.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/sql.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/swift.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/tags.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/terraform.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/semantic/zig.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/similarity/lexical.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/similarity/mod.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/structural/containment.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/structural/mod.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/structural/sibling.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/edges/structural/testing.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/filtering.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/fragmentation.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/graph.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/graph_export.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/interval.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/languages.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/lib.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/mode.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/parsers/config_parser.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/parsers/generic.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/parsers/mod.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/parsers/tree_sitter_strategy.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/ppr.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/project_graph.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/pybridge.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/render.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/scoring.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/select.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/signatures.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/stopwords.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/test_harness.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/tokenizer.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/types.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/utility/boltzmann.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/utility/importance.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/utility/mod.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/utility/needs.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/src/utility/scoring.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/tests/common/mod.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/tests/fixtures/garbage/garbage_api.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/tests/fixtures/garbage/garbage_constants.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/tests/fixtures/garbage/garbage_handlers.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/tests/fixtures/garbage/garbage_models.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/tests/fixtures/garbage/garbage_module.js +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/tests/fixtures/garbage/garbage_services.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/tests/fixtures/garbage/garbage_types.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/tests/fixtures/garbage/garbage_unrelated.yaml +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/tests/fixtures/garbage/garbage_utils.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/tests/fixtures/garbage/garbage_validators.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/diffctx/tests/yaml_cases.rs +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/rust-toolchain.toml +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/__init__.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/__main__.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/clipboard.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/diffctx/__init__.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/diffctx/graph_analytics.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/diffctx/graph_export.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/diffctx/pipeline.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/diffctx/project_graph.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/logger.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/mcp/README.md +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/mcp/__init__.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/mcp/formatting.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/mcp/security.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/mcp/server.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/py.typed +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/tokens.py +0 -0
- {diffctx-1.10.0 → diffctx-1.10.2}/src/diffctx/tree.py +0 -0
|
@@ -355,12 +355,6 @@ version = "0.5.0"
|
|
|
355
355
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
356
356
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
357
357
|
|
|
358
|
-
[[package]]
|
|
359
|
-
name = "hermit-abi"
|
|
360
|
-
version = "0.5.2"
|
|
361
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
362
|
-
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
|
363
|
-
|
|
364
358
|
[[package]]
|
|
365
359
|
name = "id-arena"
|
|
366
360
|
version = "2.3.0"
|
|
@@ -411,23 +405,23 @@ checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f"
|
|
|
411
405
|
|
|
412
406
|
[[package]]
|
|
413
407
|
name = "libmimalloc-sys"
|
|
414
|
-
version = "0.1.
|
|
408
|
+
version = "0.1.49"
|
|
415
409
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
416
|
-
checksum = "
|
|
410
|
+
checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9"
|
|
417
411
|
dependencies = [
|
|
418
412
|
"cc",
|
|
419
413
|
]
|
|
420
414
|
|
|
421
415
|
[[package]]
|
|
422
416
|
name = "libtest-mimic"
|
|
423
|
-
version = "0.
|
|
417
|
+
version = "0.8.2"
|
|
424
418
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
425
|
-
checksum = "
|
|
419
|
+
checksum = "14e6ba06f0ade6e504aff834d7c34298e5155c6baca353cc6a4aaff2f9fd7f33"
|
|
426
420
|
dependencies = [
|
|
421
|
+
"anstream",
|
|
422
|
+
"anstyle",
|
|
427
423
|
"clap",
|
|
428
424
|
"escape8259",
|
|
429
|
-
"termcolor",
|
|
430
|
-
"threadpool",
|
|
431
425
|
]
|
|
432
426
|
|
|
433
427
|
[[package]]
|
|
@@ -459,9 +453,9 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
|
|
459
453
|
|
|
460
454
|
[[package]]
|
|
461
455
|
name = "mimalloc"
|
|
462
|
-
version = "0.1.
|
|
456
|
+
version = "0.1.52"
|
|
463
457
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
464
|
-
checksum = "
|
|
458
|
+
checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862"
|
|
465
459
|
dependencies = [
|
|
466
460
|
"libmimalloc-sys",
|
|
467
461
|
]
|
|
@@ -475,16 +469,6 @@ dependencies = [
|
|
|
475
469
|
"windows-sys",
|
|
476
470
|
]
|
|
477
471
|
|
|
478
|
-
[[package]]
|
|
479
|
-
name = "num_cpus"
|
|
480
|
-
version = "1.17.0"
|
|
481
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
482
|
-
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
|
|
483
|
-
dependencies = [
|
|
484
|
-
"hermit-abi",
|
|
485
|
-
"libc",
|
|
486
|
-
]
|
|
487
|
-
|
|
488
472
|
[[package]]
|
|
489
473
|
name = "once_cell"
|
|
490
474
|
version = "1.21.4"
|
|
@@ -622,9 +606,9 @@ dependencies = [
|
|
|
622
606
|
|
|
623
607
|
[[package]]
|
|
624
608
|
name = "regex"
|
|
625
|
-
version = "1.12.
|
|
609
|
+
version = "1.12.4"
|
|
626
610
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
627
|
-
checksum = "
|
|
611
|
+
checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
|
|
628
612
|
dependencies = [
|
|
629
613
|
"aho-corasick",
|
|
630
614
|
"memchr",
|
|
@@ -645,9 +629,9 @@ dependencies = [
|
|
|
645
629
|
|
|
646
630
|
[[package]]
|
|
647
631
|
name = "regex-syntax"
|
|
648
|
-
version = "0.8.
|
|
632
|
+
version = "0.8.11"
|
|
649
633
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
650
|
-
checksum = "
|
|
634
|
+
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
|
651
635
|
|
|
652
636
|
[[package]]
|
|
653
637
|
name = "rustc-hash"
|
|
@@ -721,9 +705,9 @@ dependencies = [
|
|
|
721
705
|
|
|
722
706
|
[[package]]
|
|
723
707
|
name = "serde_json"
|
|
724
|
-
version = "1.0.
|
|
708
|
+
version = "1.0.150"
|
|
725
709
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
726
|
-
checksum = "
|
|
710
|
+
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
|
727
711
|
dependencies = [
|
|
728
712
|
"indexmap",
|
|
729
713
|
"itoa",
|
|
@@ -772,9 +756,9 @@ dependencies = [
|
|
|
772
756
|
|
|
773
757
|
[[package]]
|
|
774
758
|
name = "smallvec"
|
|
775
|
-
version = "1.15.
|
|
759
|
+
version = "1.15.2"
|
|
776
760
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
777
|
-
checksum = "
|
|
761
|
+
checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
|
|
778
762
|
|
|
779
763
|
[[package]]
|
|
780
764
|
name = "streaming-iterator"
|
|
@@ -818,15 +802,6 @@ dependencies = [
|
|
|
818
802
|
"windows-sys",
|
|
819
803
|
]
|
|
820
804
|
|
|
821
|
-
[[package]]
|
|
822
|
-
name = "termcolor"
|
|
823
|
-
version = "1.4.1"
|
|
824
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
825
|
-
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
|
826
|
-
dependencies = [
|
|
827
|
-
"winapi-util",
|
|
828
|
-
]
|
|
829
|
-
|
|
830
805
|
[[package]]
|
|
831
806
|
name = "thiserror"
|
|
832
807
|
version = "2.0.18"
|
|
@@ -856,15 +831,6 @@ dependencies = [
|
|
|
856
831
|
"cfg-if",
|
|
857
832
|
]
|
|
858
833
|
|
|
859
|
-
[[package]]
|
|
860
|
-
name = "threadpool"
|
|
861
|
-
version = "1.8.1"
|
|
862
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
863
|
-
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
|
|
864
|
-
dependencies = [
|
|
865
|
-
"num_cpus",
|
|
866
|
-
]
|
|
867
|
-
|
|
868
834
|
[[package]]
|
|
869
835
|
name = "tiktoken-rs"
|
|
870
836
|
version = "0.12.0"
|
|
@@ -1058,9 +1024,9 @@ dependencies = [
|
|
|
1058
1024
|
|
|
1059
1025
|
[[package]]
|
|
1060
1026
|
name = "tree-sitter-go"
|
|
1061
|
-
version = "0.
|
|
1027
|
+
version = "0.25.0"
|
|
1062
1028
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1063
|
-
checksum = "
|
|
1029
|
+
checksum = "c8560a4d2f835cc0d4d2c2e03cbd0dde2f6114b43bc491164238d333e28b16ea"
|
|
1064
1030
|
dependencies = [
|
|
1065
1031
|
"cc",
|
|
1066
1032
|
"tree-sitter-language",
|
|
@@ -1244,9 +1210,9 @@ dependencies = [
|
|
|
1244
1210
|
|
|
1245
1211
|
[[package]]
|
|
1246
1212
|
name = "tree-sitter-r"
|
|
1247
|
-
version = "1.
|
|
1213
|
+
version = "1.3.0"
|
|
1248
1214
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1249
|
-
checksum = "
|
|
1215
|
+
checksum = "ffc9954ec870dcad6cffdd302b405306c68cf031ed79a78cd9746f6740d9fe20"
|
|
1250
1216
|
dependencies = [
|
|
1251
1217
|
"cc",
|
|
1252
1218
|
"tree-sitter-language",
|
|
@@ -1264,9 +1230,9 @@ dependencies = [
|
|
|
1264
1230
|
|
|
1265
1231
|
[[package]]
|
|
1266
1232
|
name = "tree-sitter-rust"
|
|
1267
|
-
version = "0.
|
|
1233
|
+
version = "0.24.2"
|
|
1268
1234
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1269
|
-
checksum = "
|
|
1235
|
+
checksum = "439e577dbe07423ec2582ac62c7531120dbfccfa6e5f92406f93dd271a120e45"
|
|
1270
1236
|
dependencies = [
|
|
1271
1237
|
"cc",
|
|
1272
1238
|
"tree-sitter-language",
|
|
@@ -70,8 +70,8 @@ tree-sitter = "0.25"
|
|
|
70
70
|
tree-sitter-python = { version = "0.23", optional = true }
|
|
71
71
|
tree-sitter-javascript = { version = "0.23", optional = true }
|
|
72
72
|
tree-sitter-typescript = { version = "0.23", optional = true }
|
|
73
|
-
tree-sitter-go = { version = "0.
|
|
74
|
-
tree-sitter-rust = { version = "0.
|
|
73
|
+
tree-sitter-go = { version = "0.25", optional = true }
|
|
74
|
+
tree-sitter-rust = { version = "0.24", optional = true }
|
|
75
75
|
tree-sitter-java = { version = "0.23", optional = true }
|
|
76
76
|
tree-sitter-c = { version = "0.24", optional = true }
|
|
77
77
|
tree-sitter-cpp = { version = "0.23", optional = true }
|
|
@@ -126,7 +126,7 @@ pyo3 = { version = "0.29", features = ["extension-module", "abi3-py310"], option
|
|
|
126
126
|
[dev-dependencies]
|
|
127
127
|
tempfile = "3"
|
|
128
128
|
serde_yaml = "0.9"
|
|
129
|
-
libtest-mimic = "0.
|
|
129
|
+
libtest-mimic = "0.8"
|
|
130
130
|
|
|
131
131
|
[[test]]
|
|
132
132
|
name = "yaml_cases"
|
|
@@ -500,6 +500,135 @@ pub fn get_untracked_files(repo_root: &Path) -> Result<Vec<PathBuf>> {
|
|
|
500
500
|
.collect())
|
|
501
501
|
}
|
|
502
502
|
|
|
503
|
+
/// Rewrites one `.diffctx/ignore` pattern line to be anchored to the
|
|
504
|
+
/// directory that contains the `.diffctx/` folder (`rel`, repo-root-relative,
|
|
505
|
+
/// "" for the repo root itself). Mirrors `_process_ignore_line` in the
|
|
506
|
+
/// Python tree-mode ignore resolver (`src/diffctx/ignore.py`) so a pattern
|
|
507
|
+
/// declared in `sub/.diffctx/ignore` only ever matches within `sub/`.
|
|
508
|
+
fn anchor_diffctx_ignore_line(line: &str, rel: &str) -> String {
|
|
509
|
+
let (neg, pat) = match line.strip_prefix('!') {
|
|
510
|
+
Some(rest) => (true, rest),
|
|
511
|
+
None => (false, line),
|
|
512
|
+
};
|
|
513
|
+
let pat_no_trailing_slash = pat.trim_end_matches('/');
|
|
514
|
+
let full = if pat_no_trailing_slash.starts_with('/') || pat_no_trailing_slash.contains('/') {
|
|
515
|
+
let anchored = pat.trim_start_matches('/');
|
|
516
|
+
if rel.is_empty() {
|
|
517
|
+
format!("/{anchored}")
|
|
518
|
+
} else {
|
|
519
|
+
format!("/{rel}/{anchored}")
|
|
520
|
+
}
|
|
521
|
+
} else if rel.is_empty() {
|
|
522
|
+
pat.to_string()
|
|
523
|
+
} else {
|
|
524
|
+
format!("{rel}/**/{pat}")
|
|
525
|
+
};
|
|
526
|
+
if neg { format!("!{full}") } else { full }
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/// Finds every `.diffctx/ignore` file tracked or present in `repo_root`
|
|
530
|
+
/// (any depth) and returns its patterns rewritten to be repo-root-relative,
|
|
531
|
+
/// ready to feed into a combined gitignore-syntax exclude file.
|
|
532
|
+
fn collect_diffctx_ignore_patterns(repo_root: &Path) -> Vec<String> {
|
|
533
|
+
let Ok(files) = run_git_z(
|
|
534
|
+
repo_root,
|
|
535
|
+
&[
|
|
536
|
+
"ls-files",
|
|
537
|
+
"-z",
|
|
538
|
+
"--cached",
|
|
539
|
+
"--others",
|
|
540
|
+
"--exclude-standard",
|
|
541
|
+
"--",
|
|
542
|
+
":(glob)**/.diffctx/ignore",
|
|
543
|
+
],
|
|
544
|
+
) else {
|
|
545
|
+
return Vec::new();
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
let mut patterns = Vec::new();
|
|
549
|
+
for raw in &files {
|
|
550
|
+
let rel_path = unquote_c_style(raw);
|
|
551
|
+
if !rel_path.ends_with(".diffctx/ignore") {
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
let rel_dir = rel_path
|
|
555
|
+
.strip_suffix(".diffctx/ignore")
|
|
556
|
+
.unwrap_or("")
|
|
557
|
+
.trim_end_matches('/');
|
|
558
|
+
let Ok(content) = std::fs::read_to_string(repo_root.join(&rel_path)) else {
|
|
559
|
+
continue;
|
|
560
|
+
};
|
|
561
|
+
for line in content.lines() {
|
|
562
|
+
let line = line.trim_end();
|
|
563
|
+
if line.is_empty() || line.starts_with('#') {
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
566
|
+
patterns.push(anchor_diffctx_ignore_line(line, rel_dir));
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
patterns
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/// Returns the subset of `rel_paths` (repo-root-relative) excluded by either
|
|
573
|
+
/// `.gitignore` (via git's own engine, so nesting/negation/`**` are handled
|
|
574
|
+
/// correctly) or `.diffctx/ignore` (patterns anchored per-directory and fed
|
|
575
|
+
/// to git as a temporary `core.excludesFile`, so the same engine evaluates
|
|
576
|
+
/// both mechanisms uniformly). Best-effort: any failure returns an empty set
|
|
577
|
+
/// rather than blocking the diff pipeline on an ignore-resolution problem.
|
|
578
|
+
pub fn find_ignored_paths(repo_root: &Path, rel_paths: &[String]) -> FxHashSet<String> {
|
|
579
|
+
if rel_paths.is_empty() {
|
|
580
|
+
return FxHashSet::default();
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
let diffctx_patterns = collect_diffctx_ignore_patterns(repo_root);
|
|
584
|
+
let temp_excludes = if diffctx_patterns.is_empty() {
|
|
585
|
+
None
|
|
586
|
+
} else {
|
|
587
|
+
let path = std::env::temp_dir().join(format!("diffctx-ignore-{}.tmp", std::process::id()));
|
|
588
|
+
match std::fs::write(&path, diffctx_patterns.join("\n")) {
|
|
589
|
+
Ok(()) => Some(path),
|
|
590
|
+
Err(_) => None,
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
let mut args: Vec<String> = vec!["check-ignore".into(), "--no-index".into()];
|
|
595
|
+
if let Some(ref path) = temp_excludes {
|
|
596
|
+
args.insert(0, format!("core.excludesFile={}", path.display()));
|
|
597
|
+
args.insert(0, "-c".into());
|
|
598
|
+
}
|
|
599
|
+
args.push("--".into());
|
|
600
|
+
args.extend(rel_paths.iter().cloned());
|
|
601
|
+
let arg_refs: Vec<&str> = args.iter().map(String::as_str).collect();
|
|
602
|
+
|
|
603
|
+
let result = (|| -> Result<FxHashSet<String>> {
|
|
604
|
+
let mut cmd = Command::new("git");
|
|
605
|
+
cmd.arg("-C")
|
|
606
|
+
.arg(repo_root)
|
|
607
|
+
.args(&arg_refs)
|
|
608
|
+
.stdout(Stdio::piped())
|
|
609
|
+
.stderr(Stdio::piped());
|
|
610
|
+
let child = cmd.spawn()?;
|
|
611
|
+
let output = wait_with_timeout(child, Duration::from_secs(git_timeout()), &arg_refs)?;
|
|
612
|
+
// Exit code 1 from `check-ignore` means "none of the given paths are
|
|
613
|
+
// ignored" — not a failure. Any other non-zero code is a real error.
|
|
614
|
+
if !output.status.success() && output.status.code() != Some(1) {
|
|
615
|
+
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
616
|
+
return Err(GitError::CommandFailed(format!(
|
|
617
|
+
"git check-ignore failed: {}",
|
|
618
|
+
stderr.trim()
|
|
619
|
+
)));
|
|
620
|
+
}
|
|
621
|
+
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
622
|
+
Ok(stdout.lines().map(unquote_c_style).collect())
|
|
623
|
+
})();
|
|
624
|
+
|
|
625
|
+
if let Some(path) = temp_excludes {
|
|
626
|
+
let _ = std::fs::remove_file(path);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
result.unwrap_or_default()
|
|
630
|
+
}
|
|
631
|
+
|
|
503
632
|
pub struct CatFileBatch {
|
|
504
633
|
repo_root: PathBuf,
|
|
505
634
|
child: Option<Child>,
|
|
@@ -3,6 +3,9 @@ use mimalloc::MiMalloc;
|
|
|
3
3
|
static GLOBAL: MiMalloc = MiMalloc;
|
|
4
4
|
|
|
5
5
|
use std::path::PathBuf;
|
|
6
|
+
use std::sync::mpsc;
|
|
7
|
+
use std::thread;
|
|
8
|
+
use std::time::Duration;
|
|
6
9
|
|
|
7
10
|
use anyhow::Result;
|
|
8
11
|
use clap::Parser;
|
|
@@ -60,17 +63,50 @@ fn main() -> Result<()> {
|
|
|
60
63
|
eprintln!("error: {e}");
|
|
61
64
|
std::process::exit(2);
|
|
62
65
|
});
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
|
|
67
|
+
// The per-phase git timeout does not bound in-process phases (parse, graph
|
|
68
|
+
// build, scoring), so a pathological repo can hang far past `--timeout`
|
|
69
|
+
// until OOM/SIGKILL (#70). Run the pipeline on a worker thread and enforce
|
|
70
|
+
// `--timeout` as a true total wall-clock ceiling: on expiry, fail fast with
|
|
71
|
+
// the actionable-error contract instead of hanging unbounded.
|
|
72
|
+
let timeout = cli.timeout;
|
|
73
|
+
let path = cli.path.clone();
|
|
74
|
+
let diff_ref = cli.diff_ref.clone();
|
|
75
|
+
let budget = cli.budget;
|
|
76
|
+
let alpha = cli.alpha;
|
|
77
|
+
let tau = cli.tau;
|
|
78
|
+
let no_content = cli.no_content;
|
|
79
|
+
let full = cli.full;
|
|
80
|
+
let (tx, rx) = mpsc::channel();
|
|
81
|
+
thread::spawn(move || {
|
|
82
|
+
let result = build_diff_context(
|
|
83
|
+
&path,
|
|
84
|
+
diff_ref.as_deref(),
|
|
85
|
+
Some(budget),
|
|
86
|
+
alpha,
|
|
87
|
+
tau,
|
|
88
|
+
no_content,
|
|
89
|
+
full,
|
|
90
|
+
scoring_mode,
|
|
91
|
+
timeout,
|
|
92
|
+
);
|
|
93
|
+
let _ = tx.send(result);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
let output = match rx.recv_timeout(Duration::from_secs(timeout)) {
|
|
97
|
+
Ok(result) => result?,
|
|
98
|
+
Err(mpsc::RecvTimeoutError::Timeout) => {
|
|
99
|
+
eprintln!(
|
|
100
|
+
"diffctx: pipeline exceeded {timeout}s wall-clock deadline; aborting before \
|
|
101
|
+
OOM/SIGKILL. Narrow the review with an explicit '--diff <from>..<to>' range or \
|
|
102
|
+
run on a smaller subtree, or raise '--timeout'."
|
|
103
|
+
);
|
|
104
|
+
std::process::exit(124);
|
|
105
|
+
}
|
|
106
|
+
Err(mpsc::RecvTimeoutError::Disconnected) => {
|
|
107
|
+
anyhow::bail!("diffctx: pipeline worker terminated unexpectedly");
|
|
108
|
+
}
|
|
109
|
+
};
|
|
74
110
|
|
|
75
111
|
match cli.format.as_str() {
|
|
76
112
|
"json" => {
|
|
@@ -54,8 +54,8 @@ impl FragmentationStrategy for MarkdownStrategy {
|
|
|
54
54
|
let total_lines = lines.len() as u32;
|
|
55
55
|
let mut fragments: Vec<Fragment> = Vec::new();
|
|
56
56
|
|
|
57
|
-
for (idx, &(start_line,
|
|
58
|
-
let end_line = find_section_end(&headings, idx,
|
|
57
|
+
for (idx, &(start_line, _level, _)) in headings.iter().enumerate() {
|
|
58
|
+
let end_line = find_section_end(&headings, idx, total_lines);
|
|
59
59
|
if end_line < start_line {
|
|
60
60
|
continue;
|
|
61
61
|
}
|
|
@@ -90,16 +90,57 @@ impl FragmentationStrategy for MarkdownStrategy {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
93
|
+
/// A heading's own fragment ends at the very next heading, regardless of
|
|
94
|
+
/// level — not at the next heading of the *same or higher* level. The old
|
|
95
|
+
/// same-or-higher rule made a heading's span include every nested
|
|
96
|
+
/// subsection beneath it, so a lone top-level `#` heading (the common case:
|
|
97
|
+
/// one H1 title, many `##`/`###` children) spanned the entire rest of the
|
|
98
|
+
/// document. A one-line change in the H1's own preamble then flagged that
|
|
99
|
+
/// all-encompassing fragment as `role: "changed"`, dumping the whole file
|
|
100
|
+
/// instead of just the touched paragraph (#91).
|
|
101
|
+
fn find_section_end(headings: &[(u32, u32, String)], idx: usize, total_lines: u32) -> u32 {
|
|
102
|
+
match headings.get(idx + 1) {
|
|
103
|
+
Some(&(next_line, _, _)) => next_line - 1,
|
|
104
|
+
None => total_lines,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#[cfg(test)]
|
|
109
|
+
mod tests {
|
|
110
|
+
use super::*;
|
|
111
|
+
|
|
112
|
+
/// Regression for #91: a lone H1 title followed only by `##` children
|
|
113
|
+
/// must not produce a single fragment spanning the whole document — the
|
|
114
|
+
/// H1's own fragment is just its direct preamble, up to the first child.
|
|
115
|
+
#[test]
|
|
116
|
+
fn h1_fragment_stops_at_first_child_heading_not_eof() {
|
|
117
|
+
let content =
|
|
118
|
+
"# Title\n\nPreamble line.\n\n## Section One\nBody one.\n\n## Section Two\nBody two.\n";
|
|
119
|
+
let fragments = MarkdownStrategy.fragment(Arc::from("doc.md"), content);
|
|
120
|
+
|
|
121
|
+
let title = fragments
|
|
122
|
+
.iter()
|
|
123
|
+
.find(|f| f.content.starts_with("# Title"))
|
|
124
|
+
.expect("Title fragment present");
|
|
125
|
+
assert_eq!(title.id.start_line, 1);
|
|
126
|
+
assert_eq!(
|
|
127
|
+
title.id.end_line, 4,
|
|
128
|
+
"H1 fragment should stop before '## Section One', not run to EOF"
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
#[test]
|
|
133
|
+
fn sibling_headings_still_each_get_their_own_fragment() {
|
|
134
|
+
let content =
|
|
135
|
+
"## Section One\nBody one.\n\n## Section Two\nBody two.\n### Nested\nNested body.\n";
|
|
136
|
+
let fragments = MarkdownStrategy.fragment(Arc::from("doc.md"), content);
|
|
137
|
+
assert_eq!(fragments.len(), 3);
|
|
138
|
+
|
|
139
|
+
let nested = fragments
|
|
140
|
+
.iter()
|
|
141
|
+
.find(|f| f.content.starts_with("### Nested"))
|
|
142
|
+
.expect("Nested fragment present");
|
|
143
|
+
assert_eq!(nested.id.start_line, 6);
|
|
144
|
+
assert_eq!(nested.id.end_line, 8);
|
|
103
145
|
}
|
|
104
|
-
total_lines
|
|
105
146
|
}
|
|
@@ -131,6 +131,13 @@ pub fn compute_scored_state(
|
|
|
131
131
|
return Ok(empty_scored_state(root_dir));
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
let ignored_rel_paths = resolve_ignored_paths(&root_dir, &hunks);
|
|
135
|
+
hunks.retain(|h| !is_ignored_path(&root_dir, Path::new(&*h.path), &ignored_rel_paths));
|
|
136
|
+
|
|
137
|
+
if hunks.is_empty() {
|
|
138
|
+
return Ok(empty_scored_state(root_dir));
|
|
139
|
+
}
|
|
140
|
+
|
|
134
141
|
let diff_text = git::get_diff_text(&root_dir, diff_range)?;
|
|
135
142
|
|
|
136
143
|
let mut changed_files = git::get_changed_files(&root_dir, diff_range)?;
|
|
@@ -152,7 +159,9 @@ pub fn compute_scored_state(
|
|
|
152
159
|
.into_iter()
|
|
153
160
|
.filter(|f| {
|
|
154
161
|
let resolved = f.canonicalize().unwrap_or_else(|_| f.clone());
|
|
155
|
-
!excluded.contains(&resolved)
|
|
162
|
+
!excluded.contains(&resolved)
|
|
163
|
+
&& !is_secret_path(f)
|
|
164
|
+
&& !is_ignored_path(&root_dir, f, &ignored_rel_paths)
|
|
156
165
|
})
|
|
157
166
|
.collect();
|
|
158
167
|
|
|
@@ -412,6 +421,7 @@ pub fn select_with_params(
|
|
|
412
421
|
&state.root_dir,
|
|
413
422
|
&state.preferred_revs,
|
|
414
423
|
batch_reader.as_mut(),
|
|
424
|
+
&state.core_ids,
|
|
415
425
|
);
|
|
416
426
|
if let Some(mut r) = batch_reader {
|
|
417
427
|
r.close();
|
|
@@ -493,6 +503,31 @@ fn is_secret_path(path: &Path) -> bool {
|
|
|
493
503
|
)
|
|
494
504
|
}
|
|
495
505
|
|
|
506
|
+
fn rel_path_string(root_dir: &Path, path: &Path) -> Option<String> {
|
|
507
|
+
path.strip_prefix(root_dir)
|
|
508
|
+
.ok()
|
|
509
|
+
.map(|p| p.to_string_lossy().replace('\\', "/"))
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/// Resolves `.gitignore` / `.diffctx/ignore` exclusions (#85) for every path
|
|
513
|
+
/// touched by `hunks`, in one batched git call. diff mode previously only
|
|
514
|
+
/// ever excluded a hardcoded set of secret-like filenames (`is_secret_path`)
|
|
515
|
+
/// — a file a user explicitly excluded via `.diffctx/ignore` still had its
|
|
516
|
+
/// changed content surfaced in full.
|
|
517
|
+
fn resolve_ignored_paths(root_dir: &Path, hunks: &[crate::types::DiffHunk]) -> FxHashSet<String> {
|
|
518
|
+
let rel_paths: Vec<String> = hunks
|
|
519
|
+
.iter()
|
|
520
|
+
.filter_map(|h| rel_path_string(root_dir, Path::new(&*h.path)))
|
|
521
|
+
.collect();
|
|
522
|
+
git::find_ignored_paths(root_dir, &rel_paths)
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
fn is_ignored_path(root_dir: &Path, path: &Path, ignored_rel_paths: &FxHashSet<String>) -> bool {
|
|
526
|
+
rel_path_string(root_dir, path)
|
|
527
|
+
.map(|rel| ignored_rel_paths.contains(&rel))
|
|
528
|
+
.unwrap_or(false)
|
|
529
|
+
}
|
|
530
|
+
|
|
496
531
|
fn build_diff_context_full(
|
|
497
532
|
root_dir: &Path,
|
|
498
533
|
diff_range: Option<&str>,
|
|
@@ -512,8 +547,14 @@ fn build_diff_context_full(
|
|
|
512
547
|
if hunks.is_empty() {
|
|
513
548
|
return Ok(empty_output(&root_dir));
|
|
514
549
|
}
|
|
550
|
+
let ignored_rel_paths = resolve_ignored_paths(&root_dir, &hunks);
|
|
551
|
+
hunks.retain(|h| !is_ignored_path(&root_dir, Path::new(&*h.path), &ignored_rel_paths));
|
|
552
|
+
if hunks.is_empty() {
|
|
553
|
+
return Ok(empty_output(&root_dir));
|
|
554
|
+
}
|
|
515
555
|
let mut changed_files = git::get_changed_files(&root_dir, diff_range)?;
|
|
516
|
-
changed_files
|
|
556
|
+
changed_files
|
|
557
|
+
.retain(|f| !is_secret_path(f) && !is_ignored_path(&root_dir, f, &ignored_rel_paths));
|
|
517
558
|
if changed_files.is_empty() {
|
|
518
559
|
return Ok(empty_output(&root_dir));
|
|
519
560
|
}
|