|
| 1 | +use std::{ffi::OsStr, path::PathBuf, str::Lines}; |
| 2 | + |
| 3 | +use gix::bstr::BStr; |
| 4 | + |
| 5 | +pub fn blame_file(mut repo: gix::Repository, file: &OsStr, out: impl std::io::Write) -> anyhow::Result<()> { |
| 6 | + repo.object_cache_size_if_unset(repo.compute_object_cache_size_for_tree_diffs(&**repo.index_or_empty()?)); |
| 7 | + |
| 8 | + let suspect = repo.head()?.peel_to_commit_in_place()?; |
| 9 | + let traverse: Vec<_> = gix::traverse::commit::Simple::new(Some(suspect.id), &repo.objects).collect(); |
| 10 | + let mut resource_cache = repo.diff_resource_cache_for_tree_diff()?; |
| 11 | + |
| 12 | + let work_dir: PathBuf = repo.work_dir().expect("TODO").into(); |
| 13 | + let file_path: &BStr = gix::path::os_str_into_bstr(file)?; |
| 14 | + |
| 15 | + let blame_entries = gix::blame::blame_file( |
| 16 | + &repo.objects, |
| 17 | + traverse, |
| 18 | + &mut resource_cache, |
| 19 | + suspect.id, |
| 20 | + work_dir.clone(), |
| 21 | + file_path, |
| 22 | + ) |
| 23 | + .expect("TODO"); |
| 24 | + |
| 25 | + let absolute_path = work_dir.join(file); |
| 26 | + let file_content = std::fs::read_to_string(absolute_path).expect("TODO"); |
| 27 | + let lines = file_content.lines(); |
| 28 | + |
| 29 | + write_blame_entries(out, lines, blame_entries)?; |
| 30 | + |
| 31 | + Ok(()) |
| 32 | +} |
| 33 | + |
| 34 | +fn write_blame_entries( |
| 35 | + mut out: impl std::io::Write, |
| 36 | + mut lines: Lines<'_>, |
| 37 | + blame_entries: Vec<gix::blame::BlameEntry>, |
| 38 | +) -> Result<(), std::io::Error> { |
| 39 | + for blame_entry in blame_entries { |
| 40 | + for line_number in blame_entry.range_in_blamed_file { |
| 41 | + let line = lines.next().unwrap(); |
| 42 | + |
| 43 | + writeln!( |
| 44 | + out, |
| 45 | + "{} {} {}", |
| 46 | + blame_entry.commit_id.to_hex_with_len(8), |
| 47 | + // `line_number` is 0-based, but we want to show 1-based line numbers (as `git` |
| 48 | + // does). |
| 49 | + line_number + 1, |
| 50 | + line |
| 51 | + )?; |
| 52 | + } |
| 53 | + } |
| 54 | + |
| 55 | + Ok(()) |
| 56 | +} |
0 commit comments