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