diff --git a/Cargo.lock b/Cargo.lock index a0986dcc7..cb815ee3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -448,6 +448,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", +] + [[package]] name = "flate2" version = "1.0.27" @@ -527,33 +539,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31887c304d9a935f3e5494fb5d6a0106c34e965168ec0db9b457424eedd0c741" dependencies = [ "gix-actor", + "gix-attributes", + "gix-command", "gix-commitgraph", "gix-config", "gix-date", "gix-diff", "gix-discover", "gix-features", + "gix-filter", "gix-fs", "gix-glob", "gix-hash", "gix-hashtable", + "gix-ignore", + "gix-index", "gix-lock", "gix-macros", "gix-object", "gix-odb", "gix-pack", "gix-path", + "gix-pathspec", "gix-ref", "gix-refspec", "gix-revision", "gix-revwalk", "gix-sec", + "gix-submodule", "gix-tempfile", "gix-trace", "gix-traverse", "gix-url", "gix-utils", "gix-validate", + "gix-worktree", "once_cell", "parking_lot", "smallvec", @@ -574,6 +594,32 @@ dependencies = [ "winnow 0.5.28", ] +[[package]] +name = "gix-attributes" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "214ee3792e504ee1ce206b36dcafa4f328ca313d1e2ac0b41433d68ef4e14260" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-quote", + "gix-trace", + "kstring", + "smallvec", + "thiserror", + "unicode-bom", +] + +[[package]] +name = "gix-bitmap" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b6cd0f246180034ddafac9b00a112f19178135b21eb031b3f79355891f7325" +dependencies = [ + "thiserror", +] + [[package]] name = "gix-chunk" version = "0.4.7" @@ -583,6 +629,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "gix-command" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce1ffc7db3fb50b7dae6ecd937a3527cb725f444614df2ad8988d81806f13f09" +dependencies = [ + "bstr", + "gix-path", + "gix-trace", + "shell-words", +] + [[package]] name = "gix-commitgraph" version = "0.24.0" @@ -690,6 +748,27 @@ dependencies = [ "walkdir", ] +[[package]] +name = "gix-filter" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9240862840fb740d209422937195e129e4ed3da49af212383260134bea8f6c1a" +dependencies = [ + "bstr", + "encoding_rs", + "gix-attributes", + "gix-command", + "gix-hash", + "gix-object", + "gix-packetline-blocking", + "gix-path", + "gix-quote", + "gix-trace", + "gix-utils", + "smallvec", + "thiserror", +] + [[package]] name = "gix-fs" version = "0.10.0" @@ -733,6 +812,44 @@ dependencies = [ "parking_lot", ] +[[package]] +name = "gix-ignore" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f7069aaca4a05784c4cb44e392f0eaf627c6e57e05d3100c0e2386a37a682f0" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-trace", + "unicode-bom", +] + +[[package]] +name = "gix-index" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7152181ba8f0a3addc5075dd612cea31fc3e252b29c8be8c45f4892bf87426" +dependencies = [ + "bitflags 2.4.2", + "bstr", + "btoi", + "filetime", + "gix-bitmap", + "gix-features", + "gix-fs", + "gix-hash", + "gix-lock", + "gix-object", + "gix-traverse", + "itoa", + "libc", + "memmap2", + "rustix", + "smallvec", + "thiserror", +] + [[package]] name = "gix-lock" version = "13.0.0" @@ -814,6 +931,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "gix-packetline-blocking" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8ef6dd3ea50e26f3bf572e90c034d033c804d340cd1eb386392f184a9ba2f7" +dependencies = [ + "bstr", + "faster-hex", + "gix-trace", + "thiserror", +] + [[package]] name = "gix-path" version = "0.10.4" @@ -827,6 +956,21 @@ dependencies = [ "thiserror", ] +[[package]] +name = "gix-pathspec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cbd49750edb26b0a691e5246fc635fa554d344da825cd20fa9ee0da9c1b761f" +dependencies = [ + "bitflags 2.4.2", + "bstr", + "gix-attributes", + "gix-config-value", + "gix-glob", + "gix-path", + "thiserror", +] + [[package]] name = "gix-quote" version = "0.4.10" @@ -917,6 +1061,21 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "gix-submodule" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73182f6c1f5ed1ed94ba16581ac62593d5e29cd1c028b2af618f836283b8f8d4" +dependencies = [ + "bstr", + "gix-config", + "gix-path", + "gix-pathspec", + "gix-refspec", + "gix-url", + "thiserror", +] + [[package]] name = "gix-tempfile" version = "13.0.0" @@ -986,6 +1145,24 @@ dependencies = [ "thiserror", ] +[[package]] +name = "gix-worktree" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca36bb3dc54038c66507dc75c4d8edbee2d6d5cc45227b4eb508ad13dd60a006" +dependencies = [ + "bstr", + "gix-attributes", + "gix-features", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-ignore", + "gix-index", + "gix-object", + "gix-path", +] + [[package]] name = "globset" version = "0.4.14" @@ -1408,6 +1585,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kstring" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" +dependencies = [ + "static_assertions", +] + [[package]] name = "libc" version = "0.2.152" @@ -1880,6 +2066,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + [[package]] name = "signal-hook" version = "0.3.17" diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml index 051134e4a..6aa50dcf7 100644 --- a/helix-vcs/Cargo.toml +++ b/helix-vcs/Cargo.toml @@ -19,7 +19,7 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p parking_lot = "0.12" arc-swap = { version = "1.6.0" } -gix = { version = "0.58.0", default-features = false , optional = true } +gix = { version = "0.58.0", features = ["attributes"], default-features = false, optional = true } imara-diff = "0.1.5" anyhow = "1" diff --git a/helix-vcs/src/git.rs b/helix-vcs/src/git.rs index e4d45301a..995bade06 100644 --- a/helix-vcs/src/git.rs +++ b/helix-vcs/src/git.rs @@ -1,5 +1,7 @@ use anyhow::{bail, Context, Result}; use arc_swap::ArcSwap; +use gix::filter::plumbing::driver::apply::Delay; +use std::io::Read; use std::path::Path; use std::sync::Arc; @@ -76,29 +78,21 @@ fn get_diff_base(&self, file: &Path) -> Result> { let file_oid = find_file_in_commit(&repo, &head, file)?; let file_object = repo.find_object(file_oid)?; - let mut data = file_object.detach().data; - // convert LF to CRLF if configured to avoid showing every line as changed - if repo - .config_snapshot() - .boolean("core.autocrlf") - .unwrap_or(false) - { - let mut normalized_file = Vec::with_capacity(data.len()); - let mut at_cr = false; - for &byte in &data { - if byte == b'\n' { - // if this is a LF instead of a CRLF (last byte was not a CR) - // insert a new CR to generate a CRLF - if !at_cr { - normalized_file.push(b'\r'); - } - } - at_cr = byte == b'\r'; - normalized_file.push(byte) - } - data = normalized_file + let data = file_object.detach().data; + // Get the actual data that git would make out of the git object. + // This will apply the user's git config or attributes like crlf conversions. + if let Some(work_dir) = repo.work_dir() { + let rela_path = file.strip_prefix(work_dir)?; + let rela_path = gix::path::try_into_bstr(rela_path)?; + let (mut pipeline, _) = repo.filter_pipeline(None)?; + let mut worktree_outcome = + pipeline.convert_to_worktree(&data, rela_path.as_ref(), Delay::Forbid)?; + let mut buf = Vec::with_capacity(data.len()); + worktree_outcome.read_to_end(&mut buf)?; + Ok(buf) + } else { + Ok(data) } - Ok(data) } fn get_current_head_name(&self, file: &Path) -> Result>>> {