use crate::{file::File, Error, Result};
use bstr::BString;
#[allow(unused)]
use tracing::{debug, error, info, instrument, span, warn};
#[derive(Debug, Clone)]
pub enum Meta {
Added(File),
Deleted(File),
Modified { old: File, new: File },
Renamed { old: File, new: File },
Copied { old: File, new: File },
Ignored(File),
Untracked(File),
Typechange { old: File, new: File },
Unreadable(File),
Conflicted { old: File, new: File },
}
impl Meta {
pub(crate) fn from_git2(from: &git2::DiffDelta) -> Result<Self> {
use git2::Delta;
Ok(match from.status() {
Delta::Added => Self::Added(Self::get_new_file_only(from)?),
Delta::Deleted => Self::Deleted(Self::get_old_file_only(from)?),
Delta::Modified => {
let (old, new) = Self::get_both_files(from)?;
Self::Modified { old, new }
}
Delta::Renamed => {
let (old, new) = Self::get_both_files(from)?;
Self::Renamed { old, new }
}
Delta::Copied => {
let (old, new) = Self::get_both_files(from)?;
Self::Copied { old, new }
}
Delta::Ignored => Self::Ignored(Self::get_new_file_only(from)?),
Delta::Untracked => Self::Untracked(Self::get_new_file_only(from)?),
Delta::Typechange => {
let (old, new) = Self::get_both_files(from)?;
Self::Typechange { old, new }
}
Delta::Unreadable => Self::Unreadable(Self::get_new_file_only(from)?),
Delta::Unmodified => unreachable!("We don't include unmodified files"),
Delta::Conflicted => {
let (old, new) = Self::get_both_files(from)?;
Self::Conflicted { old, new }
}
})
}
fn get_new_file_only(from: &git2::DiffDelta) -> Result<File> {
assert_eq!(from.nfiles(), 1);
let file = from.new_file();
let path = file.path().ok_or_else(|| Error::MissingPath(file.id()))?;
Ok(File::new(path))
}
fn get_old_file_only(from: &git2::DiffDelta) -> Result<File> {
assert_eq!(from.nfiles(), 1);
let file = from.old_file();
let path = file.path().ok_or_else(|| Error::MissingPath(file.id()))?;
Ok(File::new(path))
}
fn get_both_files(from: &git2::DiffDelta) -> Result<(File, File)> {
assert_eq!(from.nfiles(), 2);
let old_path = from
.old_file()
.path()
.ok_or_else(|| Error::MissingPath(from.old_file().id()))?;
let new_path = from
.new_file()
.path()
.ok_or_else(|| Error::MissingPath(from.new_file().id()))?;
Ok((File::new(old_path), File::new(new_path)))
}
}
#[derive(Debug, Clone)]
pub struct Details {
meta: Meta,
lines: Vec<Line>,
}
impl Details {
pub(crate) fn new(meta: Meta, lines: Vec<Line>) -> Self {
Self { meta, lines }
}
}
#[derive(Debug, Clone)]
pub struct Line {
old_lineno: Option<u32>,
new_lineno: Option<u32>,
num_lines: u32,
content_offset: i64,
content: BString,
origin: git2::DiffLineType,
}
impl Line {
pub(crate) fn from_git2(from: &git2::DiffLine) -> Self {
Self {
old_lineno: from.old_lineno(),
new_lineno: from.new_lineno(),
num_lines: from.num_lines(),
content_offset: from.content_offset(),
content: from.content().into(),
origin: from.origin_value(),
}
}
}