pending_op.rs

  1use git::repository::RepoPath;
  2use std::ops::Add;
  3use sum_tree::{ContextLessSummary, Item, KeyedItem};
  4use worktree::{PathKey, PathSummary};
  5
  6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  7pub enum GitStatus {
  8    Staged,
  9    Unstaged,
 10    Reverted,
 11    Unchanged,
 12}
 13
 14#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 15pub enum JobStatus {
 16    Running,
 17    Finished,
 18    Skipped,
 19    Error,
 20}
 21
 22#[derive(Clone, Debug, PartialEq, Eq)]
 23pub struct PendingOps {
 24    pub repo_path: RepoPath,
 25    pub ops: Vec<PendingOp>,
 26}
 27
 28#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 29pub struct PendingOp {
 30    pub id: PendingOpId,
 31    pub git_status: GitStatus,
 32    pub job_status: JobStatus,
 33}
 34
 35#[derive(Clone, Debug)]
 36pub struct PendingOpsSummary {
 37    pub staged_count: usize,
 38    pub staging_count: usize,
 39}
 40
 41#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 42pub struct PendingOpId(pub u16);
 43
 44impl Item for PendingOps {
 45    type Summary = PathSummary<PendingOpsSummary>;
 46
 47    fn summary(&self, _cx: ()) -> Self::Summary {
 48        PathSummary {
 49            max_path: self.repo_path.0.clone(),
 50            item_summary: PendingOpsSummary {
 51                staged_count: self.staged() as usize,
 52                staging_count: self.staging() as usize,
 53            },
 54        }
 55    }
 56}
 57
 58impl ContextLessSummary for PendingOpsSummary {
 59    fn zero() -> Self {
 60        Self {
 61            staged_count: 0,
 62            staging_count: 0,
 63        }
 64    }
 65
 66    fn add_summary(&mut self, summary: &Self) {
 67        self.staged_count += summary.staged_count;
 68        self.staging_count += summary.staging_count;
 69    }
 70}
 71
 72impl KeyedItem for PendingOps {
 73    type Key = PathKey;
 74
 75    fn key(&self) -> Self::Key {
 76        PathKey(self.repo_path.0.clone())
 77    }
 78}
 79
 80impl Add<u16> for PendingOpId {
 81    type Output = PendingOpId;
 82
 83    fn add(self, rhs: u16) -> Self::Output {
 84        Self(self.0 + rhs)
 85    }
 86}
 87
 88impl From<u16> for PendingOpId {
 89    fn from(id: u16) -> Self {
 90        Self(id)
 91    }
 92}
 93
 94impl PendingOps {
 95    pub fn new(path: &RepoPath) -> Self {
 96        Self {
 97            repo_path: path.clone(),
 98            ops: Vec::new(),
 99        }
100    }
101
102    pub fn max_id(&self) -> PendingOpId {
103        self.ops.last().map(|op| op.id).unwrap_or_default()
104    }
105
106    pub fn op_by_id(&self, id: PendingOpId) -> Option<&PendingOp> {
107        self.ops.iter().find(|op| op.id == id)
108    }
109
110    pub fn op_by_id_mut(&mut self, id: PendingOpId) -> Option<&mut PendingOp> {
111        self.ops.iter_mut().find(|op| op.id == id)
112    }
113
114    /// File is staged if the last job is finished and has status Staged.
115    pub fn staged(&self) -> bool {
116        if let Some(last) = self.ops.last() {
117            if last.git_status == GitStatus::Staged && last.job_status == JobStatus::Finished {
118                return true;
119            }
120        }
121        false
122    }
123
124    /// File is staged if the last job is not finished and has status Staged.
125    pub fn staging(&self) -> bool {
126        if let Some(last) = self.ops.last() {
127            if last.git_status == GitStatus::Staged && last.job_status != JobStatus::Finished {
128                return true;
129            }
130        }
131        false
132    }
133}
134
135impl PendingOp {
136    pub fn running(&self) -> bool {
137        self.job_status == JobStatus::Running
138    }
139
140    pub fn finished(&self) -> bool {
141        matches!(self.job_status, JobStatus::Finished | JobStatus::Skipped)
142    }
143
144    pub fn error(&self) -> bool {
145        self.job_status == JobStatus::Error
146    }
147}