Skip to content

Commit

Permalink
Merge pull request #707 from Hou-Xiaoxuan/feat_diff
Browse files Browse the repository at this point in the history
fix(libra): optimize libra diff result
  • Loading branch information
genedna authored Nov 29, 2024
2 parents cbc5562 + 8ba69a5 commit 24db233
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 32 deletions.
1 change: 1 addition & 0 deletions libra/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ futures = { workspace = true }
futures-util = { workspace = true }
gemini = { workspace = true, optional = true }
hex = { workspace = true }
imara-diff = "0.1.7"
indicatif = "0.17.8"
lazy_static = { workspace = true }
lru-mem = "0.3.0"
Expand Down
100 changes: 68 additions & 32 deletions libra/src/command/diff.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::{
collections::HashMap,
collections::{HashMap, HashSet},
fmt,
io::{self, Write},
path::PathBuf,
};

use clap::Parser;
use imara_diff::{intern::InternedInput, Algorithm, UnifiedDiffBuilder};
use mercury::{
hash::SHA1,
internal::{
Expand Down Expand Up @@ -114,6 +115,7 @@ pub async fn execute(args: DiffArgs) {
index.tracked_files()
} else {
// use working directory as new commit
// NOTE: git didn't show diff for untracked files, but we do
util::list_workdir_files().unwrap()
};
get_files_blobs(&files)
Expand Down Expand Up @@ -159,6 +161,16 @@ pub async fn diff(
w: &mut dyn io::Write,
) {
let old_blobs: HashMap<PathBuf, SHA1> = old_blobs.into_iter().collect();
let new_blobs: HashMap<PathBuf, SHA1> = new_blobs.into_iter().collect();
// unison set
let union_files: HashSet<PathBuf> = old_blobs.keys().chain(new_blobs.keys()).cloned().collect();
tracing::debug!(
"old blobs {:?}, new blobs {:?}, union files {:?}",
old_blobs.len(),
new_blobs.len(),
union_files.len()
);

let read_content = |file: &PathBuf, hash: &SHA1| {
// read content from blob or file
match load_object::<Blob>(hash) {
Expand All @@ -173,40 +185,53 @@ pub async fn diff(
}
}
};

// filter files, cross old and new files, and pathspec
for (new_file, new_hash) in new_blobs {
for file in union_files {
// if new_file did't start with any path in filter, skip it
if !filter.is_empty() && !filter.iter().any(|path| new_file.sub_of(path)) {
if !filter.is_empty() && !filter.iter().any(|path| file.sub_of(path)) {
continue;
}
match old_blobs.get(&new_file) {
Some(old_hash) => {
if old_hash == &new_hash {
continue;
}
let old_content = read_content(&new_file, old_hash);
let new_content = read_content(&new_file, &new_hash);
writeln!(
w,
"diff --git a/{} b/{}",
new_file.display(),
new_file.display() // files name is always the same, current did't support rename
)
.unwrap();
writeln!(
w,
"index {}..{}",
&old_hash.to_plain_str()[0..8],
&new_hash.to_plain_str()[0..8]
)
.unwrap();

diff_result(&old_content, &new_content, w);
}
None => {
continue;
}
let new_hash = new_blobs.get(&file);
let old_hash = old_blobs.get(&file);
if new_hash == old_hash {
continue;
}

let old_content = match &old_hash.as_ref() {
Some(hash) => read_content(&file, hash),
None => String::new(),
};
let new_content = match &new_hash.as_ref() {
Some(hash) => read_content(&file, hash),
None => String::new(),
};

writeln!(
w,
"diff --git a/{} b/{}",
file.display(),
file.display() // files name is always the same, current did't support rename
)
.unwrap();

if old_hash.is_none() {
writeln!(w, "new file mode 100644").unwrap();
} else if new_hash.is_none() {
writeln!(w, "deleted file mode 100644").unwrap();
}

let old_index = old_hash.map_or("0000000".to_string(), |h| {
h.to_plain_str()[0..8].to_string()
});
let new_index = new_hash.map_or("0000000".to_string(), |h| {
h.to_plain_str()[0..8].to_string()
});
writeln!(w, "index {}..{}", old_index, new_index).unwrap();

// diff_result(&old_content, &new_content, w);
imara_diff_result(&old_content, &new_content, w);
}
}

Expand Down Expand Up @@ -239,7 +264,8 @@ impl fmt::Display for Line {
}
}

fn diff_result(old: &str, new: &str, w: &mut dyn io::Write) {
#[allow(dead_code)]
fn similar_diff_result(old: &str, new: &str, w: &mut dyn io::Write) {
let diff = similar::TextDiff::from_lines(old, new);
for (idx, group) in diff.grouped_ops(3).iter().enumerate() {
if idx > 0 {
Expand Down Expand Up @@ -269,6 +295,16 @@ fn diff_result(old: &str, new: &str, w: &mut dyn io::Write) {
}
}

fn imara_diff_result(old: &str, new: &str, w: &mut dyn io::Write) {
let input = InternedInput::new(old, new);
let diff = imara_diff::diff(
Algorithm::Histogram,
&input,
UnifiedDiffBuilder::new(&input),
);
write!(w, "{}", diff).unwrap();
}

#[cfg(test)]
mod test {
use super::*;
Expand Down Expand Up @@ -310,11 +346,11 @@ mod test {
}

#[test]
fn test_diff_result() {
fn test_similar_diff_result() {
let old = "Hello World\nThis is the second line.\nThis is the third.";
let new = "Hallo Welt\nThis is the second line.\nThis is life.\nMoar and more";
let mut buf = Vec::new();
diff_result(old, new, &mut buf);
similar_diff_result(old, new, &mut buf);
let result = String::from_utf8(buf).unwrap();
println!("{}", result);
}
Expand Down

1 comment on commit 24db233

@vercel
Copy link

@vercel vercel bot commented on 24db233 Nov 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

mega – ./

mega-git-main-gitmono.vercel.app
mega-gitmono.vercel.app
www.gitmega.dev
gitmega.dev

Please sign in to comment.