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}