use crate::error::Result;
use crate::git;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SyncState {
NoUpstream,
Synced,
HasUnpushedCommits { count: usize },
Behind { count: usize },
Diverged { ahead: usize, behind: usize },
}
impl SyncState {
pub fn detect(branch: &str) -> Result<Self> {
if !git::has_remote_tracking(branch) {
return Ok(SyncState::NoUpstream);
}
let ahead = git::unpushed_commit_count(branch).unwrap_or(0);
let behind = git::behind_upstream_count(branch).unwrap_or(0);
Ok(match (ahead, behind) {
(0, 0) => SyncState::Synced,
(a, 0) if a > 0 => SyncState::HasUnpushedCommits { count: a },
(0, b) if b > 0 => SyncState::Behind { count: b },
(a, b) => SyncState::Diverged {
ahead: a,
behind: b,
},
})
}
pub fn has_unpushed(&self) -> bool {
matches!(
self,
SyncState::HasUnpushedCommits { .. } | SyncState::Diverged { .. }
)
}
pub fn unpushed_count(&self) -> usize {
match self {
SyncState::HasUnpushedCommits { count } => *count,
SyncState::Diverged { ahead, .. } => *ahead,
_ => 0,
}
}
pub fn description(&self) -> String {
match self {
SyncState::NoUpstream => "no upstream".to_string(),
SyncState::Synced => "synced".to_string(),
SyncState::HasUnpushedCommits { count } => format!("{count} unpushed commit(s)"),
SyncState::Behind { count } => format!("{count} commit(s) behind"),
SyncState::Diverged { ahead, behind } => {
format!("{ahead} ahead, {behind} behind")
}
}
}
}