use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq)]
pub struct GitStatus {
pub modified: Vec<PathBuf>,
pub added: Vec<PathBuf>,
pub deleted: Vec<PathBuf>,
pub untracked: Vec<PathBuf>,
pub conflicts: Vec<PathBuf>,
pub renamed: Vec<(PathBuf, PathBuf)>,
pub branch: Option<String>,
pub in_merge: bool,
pub in_rebase: bool,
}
impl GitStatus {
pub fn new() -> Self {
Self {
modified: Vec::new(),
added: Vec::new(),
deleted: Vec::new(),
untracked: Vec::new(),
conflicts: Vec::new(),
renamed: Vec::new(),
branch: None,
in_merge: false,
in_rebase: false,
}
}
pub fn is_clean(&self) -> bool {
self.modified.is_empty()
&& self.added.is_empty()
&& self.deleted.is_empty()
&& self.untracked.is_empty()
&& self.conflicts.is_empty()
&& self.renamed.is_empty()
}
pub fn has_staged_changes(&self) -> bool {
!self.added.is_empty() || !self.renamed.is_empty()
}
pub fn has_unstaged_changes(&self) -> bool {
!self.modified.is_empty() || !self.deleted.is_empty()
}
pub fn has_conflicts(&self) -> bool {
!self.conflicts.is_empty()
}
pub fn all_changed_files(&self) -> Vec<PathBuf> {
let mut files = Vec::new();
files.extend(self.modified.clone());
files.extend(self.added.clone());
files.extend(self.deleted.clone());
files.extend(self.renamed.iter().map(|(_, new)| new.clone()));
files.sort();
files.dedup();
files
}
}
impl Default for GitStatus {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct GitDiff {
pub files_changed: Vec<FileDiff>,
pub insertions: usize,
pub deletions: usize,
}
impl GitDiff {
pub fn new() -> Self {
Self {
files_changed: Vec::new(),
insertions: 0,
deletions: 0,
}
}
pub fn files_count(&self) -> usize {
self.files_changed.len()
}
pub fn is_empty(&self) -> bool {
self.files_changed.is_empty()
}
}
impl Default for GitDiff {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct FileDiff {
pub path: PathBuf,
pub insertions: usize,
pub deletions: usize,
pub change_type: FileChangeType,
}
#[derive(Debug, Clone, PartialEq)]
pub enum FileChangeType {
Added,
Modified,
Deleted,
Renamed { from: PathBuf },
Copied { from: PathBuf },
}
#[derive(Debug, Clone, PartialEq)]
pub struct WorktreeInfo {
pub name: String,
pub path: PathBuf,
pub branch: String,
pub commit: CommitId,
pub is_bare: bool,
pub is_detached: bool,
pub is_locked: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CommitId {
hash: String,
}
impl CommitId {
pub fn new(hash: String) -> Self {
Self { hash }
}
pub fn hash(&self) -> &str {
&self.hash
}
pub fn short_hash(&self) -> &str {
if self.hash.len() >= 7 {
&self.hash[..7]
} else {
&self.hash
}
}
pub fn is_valid(&self) -> bool {
!self.hash.is_empty() && self.hash.chars().all(|c| c.is_ascii_hexdigit())
}
}
impl std::fmt::Display for CommitId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.hash)
}
}
impl From<String> for CommitId {
fn from(hash: String) -> Self {
Self::new(hash)
}
}
impl From<&str> for CommitId {
fn from(hash: &str) -> Self {
Self::new(hash.to_string())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct GitRepoState {
pub current_branch: Option<String>,
pub current_commit: CommitId,
pub status: GitStatus,
pub branches: Vec<String>,
pub tags: Vec<String>,
pub remotes: Vec<String>,
}