1use serde::{Deserialize, Serialize};
2use std::sync::Arc;
3
4#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
5#[serde(tag = "type")]
6pub enum BranchKind {
7 Local,
8 Remote { remote: String },
9 Unknown,
10}
11
12#[derive(Serialize, Deserialize, Default, Clone, Copy, Debug, PartialEq, Eq)]
13pub struct StatusSummary {
14 pub untracked: usize,
15 pub modified: usize,
16 pub staged: usize,
17 pub conflicted: usize,
18}
19
20#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
21pub struct BranchItem {
22 pub name: String,
23 pub full_ref: String,
24 pub kind: BranchKind,
25 pub current: bool,
26}
27
28#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
31pub struct FileEntry {
32 pub path: String,
33 #[serde(default)]
34 pub old_path: Option<String>,
35 pub status: String,
36 #[serde(default)]
37 pub staged: bool,
38 #[serde(default)]
39 pub resolved_conflict: bool,
40 pub hunks: Vec<String>,
41}
42
43#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
44pub struct ConflictDetails {
45 pub path: String,
46 pub ours: Option<String>,
47 pub theirs: Option<String>,
48 pub base: Option<String>,
49 #[serde(default)]
50 pub binary: bool,
51 #[serde(default)]
52 pub lfs_pointer: bool,
53}
54
55#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
56#[serde(rename_all = "kebab-case")]
57pub enum ConflictSide {
58 Ours,
59 Theirs,
60}
61
62#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
64pub struct StatusPayload {
65 pub files: Vec<FileEntry>,
66 pub ahead: u32,
67 pub behind: u32,
68}
69
70#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
72pub struct CommitItem {
73 pub id: String,
74 pub msg: String,
75 pub meta: String,
76 pub author: String,
77}
78
79#[derive(Serialize, Deserialize, Default, Clone, Copy, Debug, PartialEq, Eq)]
81pub struct FetchOptions {
82 pub prune: bool,
83}
84
85#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
87pub struct StashItem {
88 pub selector: String,
89 pub msg: String,
90 pub meta: String,
91}
92
93#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
95pub struct LogQuery {
96 pub rev: Option<String>,
97 pub path: Option<String>,
98 pub since_utc: Option<String>,
99 pub until_utc: Option<String>,
100 pub author_contains: Option<String>,
101 pub skip: u32,
102 pub limit: u32,
103 pub topo_order: bool,
104 pub include_merges: bool,
105}
106
107impl LogQuery {
108 pub fn head(limit: u32) -> Self {
109 Self {
110 limit,
111 ..Default::default()
112 }
113 }
114}
115
116#[derive(Serialize, Deserialize, Clone, Debug, Default)]
117pub struct Capabilities {
118 pub commits: bool,
119 pub branches: bool,
120 pub tags: bool,
121 pub staging: bool,
122 pub push_pull: bool,
123 pub fast_forward: bool,
124}
125
126#[derive(Serialize, Deserialize, Clone, Debug)]
127#[serde(tag = "type", rename_all = "kebab-case")]
128pub enum VcsEvent {
129 Info {
130 msg: String,
131 },
132 RemoteMessage(String),
133 Progress {
134 phase: String,
135 detail: String,
136 },
137 Auth {
138 method: String,
139 detail: String,
140 },
141 PushStatus {
142 refname: String,
143 status: Option<String>,
144 },
145 Warning(String),
146 Error(String),
147}
148
149pub type OnEvent = Arc<dyn Fn(VcsEvent) + Send + Sync + 'static>;
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn log_query_head_sets_limit_and_defaults_rest() {
157 let query = LogQuery::head(25);
158 assert_eq!(query.limit, 25);
159 assert!(query.rev.is_none());
160 assert!(query.path.is_none());
161 assert_eq!(query.skip, 0);
162 assert!(!query.topo_order);
163 }
164
165 #[test]
166 fn status_summary_default_is_zeroed() {
167 let summary = StatusSummary::default();
168 assert_eq!(summary.untracked, 0);
169 assert_eq!(summary.modified, 0);
170 assert_eq!(summary.staged, 0);
171 assert_eq!(summary.conflicted, 0);
172 }
173}