fix(files): use display_path for DFT_OVERRIDE_BINARY matching (closes #967)#979
Open
Booyaka101 wants to merge 1 commit into
Open
fix(files): use display_path for DFT_OVERRIDE_BINARY matching (closes #967)#979Booyaka101 wants to merge 1 commit into
Booyaka101 wants to merge 1 commit into
Conversation
…ilfred#967) `guess_content` was matching `DFT_OVERRIDE_BINARY` glob patterns against `FileArgument`'s `to_string_lossy()`. When difftastic is invoked as `GIT_EXTERNAL_DIFF` (the canonical setup), git passes the *temp file paths* as the lhs/rhs arguments — see `options.rs:918-928`: ```rust [display_path, lhs_tmp_file, _hash, lhs_mode, rhs_tmp_file, _hash, rhs_mode] => { ( display_path.to_string_lossy().to_string(), // logical filename FileArgument::from_path_argument(lhs_tmp_file), // /tmp/abc123 FileArgument::from_path_argument(rhs_tmp_file), // /tmp/def456 ... ) } ``` So `*.toml` was being matched against `/tmp/abc123…`, which obviously fails. The override silently never fired for any user with difft set up through git's external-diff hook — including the deleted-file case in the report, where the rhs is `/dev/null`. Match against `display_path` instead. This is the same string that's already plumbed through to `check_diff_attr`, so all three branches of the existing match expression now agree on what "this file's name" means. While here, also try the basename when an unanchored pattern doesn't match the full path. The `glob` crate treats `*` as not crossing `/`, so before this change `*.toml` wouldn't match `crates/foo/file.toml` even when `display_path` was wired up correctly. The new `matches_override` helper falls back to matching just the filename when the full path doesn't match. Path-shaped patterns containing `/` (e.g. `build/*.lock`) keep their anchored semantics — the basename fallback only fires when the full match has already failed, and we guard against treating a path with no parent as "different from its basename" so the fallback is a no-op for root-level files. This addresses both the reported regression (deleted files via git external-diff) and the secondary "issue with `/` in glob patterns" behaviour the maintainer flagged when reopening the issue. Six unit tests in `files.rs` cover: * root filename matched (`*.toml` vs `rust-toolchain.toml`) * deeper filename matched via basename fallback (the Wilfred#967 case) * path-shaped pattern matched at its anchor (`build/*.lock` vs `build/Cargo.lock`) * path-shaped pattern NOT matched outside its anchor (no false positive for `build/*.lock` vs `crates/build/Cargo.lock`) * unrelated pattern doesn't false-positive on basename (`*.gz` vs `src/main.rs`) * empty `display_path` doesn't crash the helper Two callers in `main.rs` (`diff_file`, `diff_conflicts_file`) updated to pass `display_path` instead of `FileArgument`. The pre-existing `guess_content` test wrapper in `files.rs` is updated to pass `""` (no overrides registered there anyway, so the loop short-circuits). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #967.
guess_contentmatchesDFT_OVERRIDE_BINARYglob patterns against theFileArgumentit receives. When difftastic is invoked asGIT_EXTERNAL_DIFF(the canonical setup, including @osa1'sgit diffrepro in the issue), git passes the temp file paths as the lhs/rhs arguments and only puts the logical filename indisplay_path. Fromsrc/options.rs:918-928:So
*.tomlwas being matched against something like/tmp/abc123and silently never fired for any user with difft set up through git's external-diff hook — including the deleted-file case in the report, where the rhs is/dev/null.Fix
Match against
display_pathinstead of theFileArgument's temp path. Thedisplay_path: &stris already plumbed through both callers (diff_fileanddiff_conflicts_file) and is the same stringcheck_diff_attralready operates on, so all three arms of the existing match expression now agree on what "this file's name" means.While here, also try the basename when an unanchored pattern fails to match the full path. The
globcrate treats*as not crossing/, so before this change*.tomlwouldn't matchcrates/foo/file.tomleven withdisplay_pathwired up correctly. That's the "issue with/in glob patterns" behaviour you flagged when you reopened the issue:Path-shaped patterns containing
/keep their anchored semantics — the basename fallback only fires when the full match has already failed, and we guard against treating a path with no parent as "different from its basename" so the fallback is a no-op for root-level files (avoids redundantly runningpattern.matchestwice).Test plan
Six new unit tests in
files.rs::tests:override_matches_root_filename*.tomlvsrust-toolchain.tomloverride_matches_filename_at_depth*.tomlvscrates/foo/rust-toolchain.tomloverride_matches_path_shaped_patternbuild/*.lockvsbuild/Cargo.lock(anchored hit)override_does_not_match_path_shaped_pattern_outside_anchorbuild/*.lockdoes NOT matchcrates/build/Cargo.lock(no false positive)override_does_not_match_non_matching_extension*.gzvssrc/main.rs(basename fallback doesn't false-positive)override_handles_empty_display_path""I extracted
matches_overrideinto a standalone Cargo workspace and ran the suite there — 6/6 passing. I wasn't able to runcargo testagainst the full difftastic tree on this Windows box because the vendored-parser symlinks need either developer mode or admin to materialise; the helper's logic is fully covered by the standalone run, and the twomain.rscallsite changes are mechanical (both already haddisplay_path: &strin scope).Notes / open questions
FileArgumentparameter onguess_contentremoved — it was only used for the override match; the rest of the function readsbytes. If you'd rather keep the parameter for symmetry with other call shapes I can leave it in as_path: &FileArgument, but dropping it seemed cleaner.#[cfg(test)] fn guess_contentshim infiles.rsnow passes""instead of&FileArgument::Stdin. No registered overrides in those tests so the loop short-circuits identically.**/*.tomlfor "any depth" and treatsrc/fooas anchored only at the root), but they handle the dominant*.<ext>andbare-filenameshapes thatDFT_OVERRIDE_BINARYis documented with. Happy to take it further toward fullglobset/ignore-crate semantics if you'd prefer that direction in a follow-up.Credit to @osa1 for the report and the patient back-and-forth on repro details.