Skip to content

Instantly share code, notes, and snippets.

@eddyb
Forked from zroug/cargo-fmt-diff.rs
Last active March 28, 2023 18:12
Show Gist options
  • Save eddyb/23490b0a707d7ea87cba3be3ca93f0d7 to your computer and use it in GitHub Desktop.
Save eddyb/23490b0a707d7ea87cba3be3ca93f0d7 to your computer and use it in GitHub Desktop.
use git2::Delta;
use git2::DiffOptions;
use git2::Repository;
use std::collections::BTreeMap;
use std::env::set_current_dir;
use std::process::Command;
fn main() {
let repo = Repository::open_from_env().unwrap();
set_current_dir(repo.workdir().unwrap()).unwrap();
let head = repo.head().unwrap().peel_to_tree().unwrap();
let mut diff_options = DiffOptions::new();
diff_options.include_untracked(true);
diff_options.recurse_untracked_dirs(true);
diff_options.show_untracked_content(true);
diff_options.context_lines(0);
let diff = repo
.diff_tree_to_workdir(Some(&head), Some(&mut diff_options))
.unwrap();
let mut changed_files = BTreeMap::new();
diff.foreach(
&mut |_, _| true,
Some(&mut |_, _| true),
Some(&mut |delta, hunk| {
if delta.new_file().path().unwrap().extension() != Some("rs".as_ref()) {
return true;
}
match delta.status() {
Delta::Unmodified
| Delta::Deleted
| Delta::Typechange
| Delta::Unreadable
| Delta::Conflicted => true,
Delta::Added
| Delta::Modified
| Delta::Renamed
| Delta::Copied
| Delta::Untracked
| Delta::Ignored => {
changed_files
.entry(delta.new_file().path().unwrap().to_path_buf())
.or_insert(vec![])
.push(hunk.new_start()..=hunk.new_start() + hunk.new_lines() - 1);
true
}
}
}),
None,
)
.unwrap();
// Flatten into a `Vec` so we can use `.chunks(n)`.
let changed_files: Vec<_> = changed_files.into_iter().collect();
for changed_files in changed_files.chunks(100) {
let mut changes_json = String::new();
changes_json.push('[');
for (path, ranges) in changed_files {
let path = format!("{:?}", path.to_str().unwrap());
for range in ranges {
changes_json.push_str(&format!(
"{{\"file\":{},\"range\":[{},{}]}},",
path,
range.start(),
range.end(),
));
}
}
changes_json.pop();
changes_json.push(']');
Command::new("rustfmt")
.args(&[
"--unstable-features",
"--file-lines",
&changes_json,
"--skip-children",
"--edition=2018",
])
.args(changed_files.iter().map(|(path, _)| path))
.status()
.unwrap();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment