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    Started,
 17    Finished,
 18    Skipped,
 19}
 20
 21#[derive(Clone, Debug, PartialEq, Eq)]
 22pub struct PendingOps {
 23    pub repo_path: RepoPath,
 24    pub ops: Vec<PendingOp>,
 25}
 26
 27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 28pub struct PendingOp {
 29    pub id: PendingOpId,
 30    pub git_status: GitStatus,
 31    pub job_status: JobStatus,
 32}
 33
 34#[derive(Clone, Debug)]
 35pub struct PendingOpsSummary {
 36    pub max_id: PendingOpId,
 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                max_id: self.ops.last().map(|op| op.id).unwrap_or_default(),
 52                staged_count: self.staged() as usize,
 53                staging_count: self.staging() as usize,
 54            },
 55        }
 56    }
 57}
 58
 59impl ContextLessSummary for PendingOpsSummary {
 60    fn zero() -> Self {
 61        Self {
 62            max_id: PendingOpId::default(),
 63            staged_count: 0,
 64            staging_count: 0,
 65        }
 66    }
 67
 68    fn add_summary(&mut self, summary: &Self) {
 69        self.max_id = summary.max_id;
 70        self.staged_count += summary.staged_count;
 71        self.staging_count += summary.staging_count;
 72    }
 73}
 74
 75impl KeyedItem for PendingOps {
 76    type Key = PathKey;
 77
 78    fn key(&self) -> Self::Key {
 79        PathKey(self.repo_path.0.clone())
 80    }
 81}
 82
 83impl Add<u16> for PendingOpId {
 84    type Output = PendingOpId;
 85
 86    fn add(self, rhs: u16) -> Self::Output {
 87        Self(self.0 + rhs)
 88    }
 89}
 90
 91impl PendingOps {
 92    pub fn new(path: &RepoPath) -> Self {
 93        Self {
 94            repo_path: path.clone(),
 95            ops: Vec::new(),
 96        }
 97    }
 98
 99    pub fn op_by_id(&self, id: PendingOpId) -> Option<&PendingOp> {
100        self.ops.iter().find(|op| op.id == id)
101    }
102
103    pub fn op_by_id_mut(&mut self, id: PendingOpId) -> Option<&mut PendingOp> {
104        self.ops.iter_mut().find(|op| op.id == id)
105    }
106
107    /// File is staged if the last job is finished and has status Staged.
108    pub fn staged(&self) -> bool {
109        if let Some(last) = self.ops.last() {
110            if last.git_status == GitStatus::Staged && last.finished() {
111                return true;
112            }
113        }
114        false
115    }
116
117    /// File is staged if the last job is not finished and has status Staged.
118    pub fn staging(&self) -> bool {
119        if let Some(last) = self.ops.last() {
120            if last.git_status == GitStatus::Staged && !last.finished() {
121                return true;
122            }
123        }
124        false
125    }
126}
127
128impl PendingOp {
129    pub fn finished(&self) -> bool {
130        self.job_status == JobStatus::Finished
131    }
132
133    pub fn finished_or_skipped(&self) -> bool {
134        self.job_status == JobStatus::Finished || self.job_status == JobStatus::Skipped
135    }
136}